diff --git a/stm-firmware/include/reflow-controller/safety/safety-memory.h b/stm-firmware/include/reflow-controller/safety/safety-memory.h index cbfacd5..541baee 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-memory.h +++ b/stm-firmware/include/reflow-controller/safety/safety-memory.h @@ -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__ */ diff --git a/stm-firmware/include/stm-periph/backup-ram.h b/stm-firmware/include/stm-periph/backup-ram.h index 3f4a470..2d33cd6 100644 --- a/stm-firmware/include/stm-periph/backup-ram.h +++ b/stm-firmware/include/stm-periph/backup-ram.h @@ -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); diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index fb05f4c..18e445f 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -30,10 +30,12 @@ #include #include #include +#include #include #include #include #include +#include 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, diff --git a/stm-firmware/safety/safety-memory.c b/stm-firmware/safety/safety-memory.c index 2ec93a5..b376cd0 100644 --- a/stm-firmware/safety/safety-memory.c +++ b/stm-firmware/safety/safety-memory.c @@ -19,4 +19,189 @@ */ #include +#include +#include +#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); diff --git a/stm-firmware/stm-periph/backup-ram.c b/stm-firmware/stm-periph/backup-ram.c index 62ad992..720f004 100644 --- a/stm-firmware/stm-periph/backup-ram.c +++ b/stm-firmware/stm-periph/backup-ram.c @@ -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; +}