Issue #18: Write init of safety memory

This commit is contained in:
Mario Hüttel 2020-09-05 15:15:31 +02:00
parent 04008a07c0
commit c9a5a2c2ff
5 changed files with 258 additions and 0 deletions

View File

@ -34,6 +34,8 @@
*/
#define SAFETY_MEMORY_HEADER_ADDRESS 0UL
#define SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT 512
/**
* @brief Safety memory header
*/
@ -52,4 +54,57 @@ struct safety_memory_boot_status {
uint32_t code_updated;
};
enum safety_memory_state {
SAFETY_MEMORY_INIT_FRESH = 0,
SAFETY_MEMORY_INIT_CORRUPTED = 1,
SAFETY_MEMORY_INIT_VALID_MEMORY = 2,
};
enum safety_memory_error_entry_type {
SAFETY_MEMORY_ERR_ENTRY_FLAG = 1,
SAFETY_MEMORY_ERR_ENTRY_NOP = 2,
};
struct error_memory_entry {
enum safety_memory_error_entry_type type;
uint16_t flag_num;
};
enum config_override_entry_type {
SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT = 1,
SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTANCE = 2,
};
struct config_override {
enum config_override_entry_type type;
union {
struct {
uint16_t flag;
uint8_t weight;
} weight_override;
struct {
uint16_t flag;
uint8_t persistance;
} persistance_override;
} entry;
};
int safety_memory_init(enum safety_memory_state *found_state);
int safety_memory_get_boot_status(struct safety_memory_boot_status *status);
int safety_memory_get_error_entry_count(uint32_t *count);
int safety_memory_check(void);
int safety_memory_get_error_entry(uint32_t idx, struct error_memory_entry *entry);
int safety_memory_insert_error_entry(struct error_memory_entry *entry);
int safety_memory_insert_config_override(struct config_override *config_override);
int safety_memory_get_config_override_count(uint32_t *count);
int safety_memory_get_config_override(uint32_t idx, struct config_override *config_override);
#endif /* __SAFETY_MEMORY_H__ */

View File

@ -53,3 +53,5 @@ int backup_ram_get_data(uint32_t addr, uint32_t *data, uint32_t count);
* @return 0 if successful
*/
int backup_ram_write_data(uint32_t addr, const uint32_t *data, uint32_t count);
uint32_t backup_ram_get_size_in_words(void);

View File

@ -30,10 +30,12 @@
#include <reflow-controller/stack-check.h>
#include <helper-macros/helper-macros.h>
#include <reflow-controller/systick.h>
#include <reflow-controller/safety/fault.h>
#include <stm32/stm32f4xx.h>
#include <cmsis/core_cm4.h>
#include <stddef.h>
#include <string.h>
#include <reflow-controller/safety/safety-memory.h>
struct error_flag {
const char *name;
@ -248,6 +250,15 @@ void safety_controller_report_analog_value(enum analog_value_monitor monitor, fl
void safety_controller_init()
{
enum safety_memory_state found_memory_state;
/* Init the safety memory */
if (safety_memory_init(&found_memory_state)) {
/* Trigger panic mode! */
panic_mode();
}
if (found_memory_state == SAFETY_MEMORY_INIT_CORRUPTED)
safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT);
/* Init default flag states */
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_UNSTABLE,

View File

@ -19,4 +19,189 @@
*/
#include <reflow-controller/safety/safety-memory.h>
#include <stm-periph/crc-unit.h>
#include <stm-periph/backup-ram.h>
#define wordsize_of(x) ((sizeof(x) / 4U) / ((sizeof(x) % 4U) ? 0U : 1U))
static enum safety_memory_state safety_memory_get_header(struct safety_memory_header *header)
{
int res;
enum safety_memory_state ret;
if (!header)
return SAFETY_MEMORY_INIT_CORRUPTED;
res = backup_ram_get_data(0UL, (uint32_t *)header, wordsize_of(struct safety_memory_header));
if (res)
return SAFETY_MEMORY_INIT_CORRUPTED;
/* Check magics */
if (header->magic != SAFETY_MEMORY_MAGIC || header->magic_i != (uint32_t)(~SAFETY_MEMORY_MAGIC)) {
/* Magics invalid */
ret = SAFETY_MEMORY_INIT_FRESH;
goto return_val;
}
res = 0;
if (header->boot_status_offset < wordsize_of(struct safety_memory_header))
res++;
if (header->config_overrides_offset < header->boot_status_offset + wordsize_of(struct safety_memory_boot_status))
res++;
if (header->config_overrides_len > SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT)
res++;
if (header->err_memory_offset < header->config_overrides_offset + header->config_overrides_len)
res++;
if (header->err_memory_end >= backup_ram_get_size_in_words() || header->err_memory_end < header->err_memory_offset)
res++;
if (res) {
/* Error detected: Write new header */
ret = SAFETY_MEMORY_INIT_CORRUPTED;
} else {
ret = SAFETY_MEMORY_INIT_VALID_MEMORY;
}
return_val:
return ret;
}
static void safety_memory_write_new_header(void)
{
struct safety_memory_header header;
header.boot_status_offset = sizeof(struct safety_memory_header);
header.config_overrides_offset = header.boot_status_offset + sizeof(struct safety_memory_boot_status)/4;
header.err_memory_offset = header.config_overrides_offset + SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT;
header.err_memory_end = header.err_memory_offset;
backup_ram_wipe();
backup_ram_write_data(0UL, (uint32_t *)&header, wordsize_of(header));
}
static int safety_memory_check_crc()
{
struct safety_memory_header header;
enum safety_memory_state state = safety_memory_get_header(&header);
uint32_t crc_offset;
uint32_t data;
uint32_t addr;
int res;
if (state != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -1;
crc_offset = header.err_memory_end;
crc_unit_reset();
for (addr = 0; addr < crc_offset; addr++) {
res = backup_ram_get_data(addr, &data, 1UL);
if (res)
return -2000;
crc_unit_input(data);
}
res = backup_ram_get_data(crc_offset, &data, 1UL);
if (res)
return -2001;
if (crc_unit_get_crc() != data)
return -3000;
else
return 0;
}
static int safety_memory_gen_crc()
{
struct safety_memory_header header;
uint32_t word_addr;
uint32_t data;
int res;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -1;
crc_unit_reset();
for (word_addr = 0; word_addr < header.err_memory_end; word_addr++) {
res = backup_ram_get_data(word_addr, &data, 1);
if (res)
return -2;
crc_unit_input(data);
}
/* Write CRC */
data = crc_unit_get_crc();
res = backup_ram_write_data(header.err_memory_end, &data, 1UL);
if (res)
return -3;
return 0;
}
int safety_memory_init(enum safety_memory_state *found_state)
{
struct safety_memory_header header;
int res;
int ret = -1;
if (!found_state)
return -1001;
crc_unit_init();
backup_ram_init(true);
*found_state = safety_memory_get_header(&header);
switch (*found_state) {
case SAFETY_MEMORY_INIT_VALID_MEMORY:
/* Valid memory detected. Check CRC */
res = safety_memory_check_crc();
if (res)
*found_state = SAFETY_MEMORY_INIT_CORRUPTED;
break;
case SAFETY_MEMORY_INIT_FRESH:
safety_memory_write_new_header();
break;
case SAFETY_MEMORY_INIT_CORRUPTED:
default:
*found_state = SAFETY_MEMORY_INIT_CORRUPTED;
safety_memory_write_new_header();
break;
}
/* Check if memory header was written newly */
if (*found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) {
/* If yes, generate new CRC checksum */
res = safety_memory_gen_crc();
if (res)
ret = -100;
else
ret = 0;
}
return ret;
}
int safety_memory_get_boot_status(struct safety_memory_boot_status *status);
int safety_memory_get_error_entry_count(uint32_t *count);
int safety_memory_check(void)
{
int res;
res = safety_memory_check_crc();
return -!!res;
}
int safety_memory_get_error_entry(uint32_t idx, struct error_memory_entry *entry);
int safety_memory_insert_error_entry(struct error_memory_entry *entry);
int safety_memory_insert_config_override(struct config_override *config_override);
int safety_memory_get_config_override_count(uint32_t *count);
int safety_memory_get_config_override(uint32_t idx, struct config_override *config_override);

View File

@ -102,3 +102,8 @@ int backup_ram_write_data(uint32_t addr, const uint32_t *data, uint32_t count)
return 0;
}
uint32_t backup_ram_get_size_in_words(void)
{
return (uint32_t)BACKUP_RAM_SIZE_WORDS;
}