Compare commits

...

10 Commits

12 changed files with 294 additions and 87 deletions

View File

@ -11,6 +11,6 @@ mechanisms and the behavior. For a detailed code documentation see the doxygen o
:maxdepth: 2
pt1000-processing
safety
safety/index
code/index

View File

@ -8,6 +8,10 @@ The safety flags are represented in software by the following enums
.. doxygenenum:: safety_flag
The safety flags can be temporarily or permanent. Some temporary flags are reset automatically, once the error condition disappears. Others have to be explicitly cleared.
The safety weights (if a flag stops the PID controller, or triggers the panic mode) are configured by default as described below. However, it will be possible to override these weights by
setting config entries in the safety memory.
.. todo:: Change docu of config entires in memory
----------------------------------------------------------------------------------------------------------------------------------
@ -90,4 +94,21 @@ safety backup memory is cleared
persistent self-clearing Stops PID Panic Mode
========== ============= ============= ===========
yes no yes no
========== ============= ============= ===========
========== ============= ============= ===========
.. _safety_flags_stack:
ERR_FLAG_STACK
---------------------------
``ERR_FLAG_STACK`` ialization of the controller, in case a corrupted safety memory is encountered.
This error is not recoverable and will trigger the panic mode.
.. seealso:: :ref:`safety_stack_checking`
========== ============= ============= ===========
persistent self-clearing Stops PID Panic Mode
========== ============= ============= ===========
yes no yes yes
========== ============= ============= ===========

View File

@ -21,3 +21,4 @@ which are used to retain boot information across resets, for example to communic
flags
backup-ram
error-handling
stack-checking

View File

@ -0,0 +1,39 @@
.. _safety_stack_checking:
Safety Stack Checking
=====================
To ensure correct operation of the controller, the stack is continuously monitored. For this, the :ref:`firmware_safety` checks the stack in each run.
These checks include:
1. Checking of used stack space and limit to end of stack
2. Checking a protection area between heap and stack for memory corruption
Any detected error will set the :ref:`safety_flags_stack` error flag.
Stack Pointer Checking
----------------------
The stack pointer is checked using :c:func:`stack_check_get_free`. The returned value for the remaining stack space is checked against
.. doxygendefine:: SAFETY_MIN_STACK_FREE
.. doxygenfunction:: stack_check_get_free
Stack and Heap Corruption Checking
----------------------------------
A section of memory is located between the stack and the heap. It is defined inside the linker script. It's size is configured by the linker script parameter ``__stack_corruption_area_size``, which is set to ``128`` by default.
This section is filled at the initializazion of the safety controller by a call to
.. doxygenfunction:: stack_check_init_corruption_detect_area
On each run of the safety controller's handling function (:c:func:`safety_controller_handle`) the following function is called:
.. doxygenfunction:: stack_check_corruption_detect_area
This function constantly checks the memory area for write modifications, and therefore detects, if the stack or heap have grown outside their boundaries.

View File

@ -23,6 +23,7 @@
enum safety_flag {
ERR_FLAG_NO_FLAG = 0,
ERR_FLAG_MEAS_ADC_OFF = (1<<0),
ERR_FLAG_MEAS_ADC_OVERFLOW = (1<<1),
ERR_FLAG_MEAS_ADC_WATCHDOG = (1<<2),
@ -39,6 +40,7 @@ enum safety_flag {
ERR_FLAG_DEBUG = (1<<13),
ERR_FLAG_TIMING_MAIN_LOOP = (1<<14),
ERR_FLAG_SAFETY_MEM_CORRUPT = (1<<15),
ERR_FLAG_SAFETY_TAB_CORRUPT = (1<<16),
};
enum timing_monitor {
@ -53,6 +55,11 @@ enum analog_value_monitor {
ERR_AMON_UC_TEMP = (1<<1),
};
#define ERR_FLAG_ENTRY(errflag) {.name=#errflag, .flag = (errflag), .error_state = false, .error_state_inv = true, .key = 0UL, .weight = NULL, .persistency = NULL}
#define TIM_MON_ENTRY(mon, min, max, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min_delta = (min), .max_delta = (max), .last = 0ULL, .enabled= false}
#define ANA_MON_ENTRY(mon, min_value, max_value, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = false}
#define ERR_FLAG_WEIGHT_ENTRY(_flag, _weight) {.flag = (_flag), .flag_ptr = NULL, .weight = (_weight), .start_dummy = 0x11823344, .end_dummy = 0xAABBCCFD}
#define ERR_FLAG_PERSIST_ENTRY(_flag, _persist) {.flag = (_flag), .flag_ptr = NULL, .persistency = (_persist), .start_dummy = 0xFF1100BB, .end_dummy = 0xEBB439A2}
/**
* @brief Magic key used to reset the watchdog using the @ref watchdog_ack function
@ -72,6 +79,9 @@ enum analog_value_monitor {
#define WATCHDOG_PRESCALER 8
/**
* @brief Minimum number of bytes that have to be free on the stack. If this is not the case, an error is detected
*/
#define SAFETY_MIN_STACK_FREE 0x100
#define PID_CONTROLLER_ERR_CAREMASK (ERR_FLAG_STACK | ERR_FLAG_AMON_UC_TEMP | ERR_FLAG_AMON_VREF | \
@ -93,4 +103,40 @@ enum analog_value_monitor {
#define SAFETY_CONTROLLER_ADC_DELAY_MS 120
#define SAFETY_CONFIG_DEFAULT_PERSIST ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OVERFLOW, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_TIMING_MEAS_ADC, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_TIMING_PID, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_AMON_UC_TEMP, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_AMON_VREF, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_STACK, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_SAFETY_ADC, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_SYSTICK, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_WTCHDG_FIRED, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_UNCAL, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_DEBUG, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_SAFETY_MEM_CORRUPT, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, true),
#define SAFETY_CONFIG_DEFAULT_WEIGHTS ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OVERFLOW, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_PID, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_UC_TEMP, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_VREF, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_STACK, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SYSTICK, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_WTCHDG_FIRED, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_UNCAL, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_DEBUG, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_MEM_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
#endif /* __SAFETY_CONFIG_H__ */

View File

@ -55,7 +55,7 @@ struct safety_memory_header {
uint32_t config_overrides_len; /**< @brief Length of override entries in words */
uint32_t err_memory_offset; /**< @brief Offset of the error memory */
uint32_t err_memory_end; /**< @brief End of the error memory. This points to the word after the error memory, containing the CRC of the whole backup RAM. */
uint32_t magic_i; /**< @brief Invers Magic. Set to the bitwise inverse of @ref SAFETY_MEMORY_MAGIC */
uint32_t crc; /**< @brief CRC of the header */
};
struct safety_memory_boot_status {

View File

@ -25,8 +25,16 @@
#define STACK_CHECK_MIN_HEAP_GAP 16UL
/**
* @brief Get usage of the stack
* @return Usage of the stack in bytes
*/
int32_t stack_check_get_usage();
/**
* @brief Get free stack space
* @return free stack space in bytes. If negative, a stack overflow occured
*/
int32_t stack_check_get_free();
static inline int stack_check_collision()
@ -50,8 +58,32 @@ static inline uint32_t read_stack_pointer()
return stack_pointer;
}
/**
* @brief Init the stack corruption detection area.
*
* This function initializes the memory area between heap and stack with random values generated by the
* STM's random number generator. A 32 bit CRC generated by the CRC unit of the STM is appended for verification of the
* area.
*
*
* @return 0 if successful, else an error has occured in generating a random number. This should never happen
* @note This function turns on the CRC unit but does not disable it afterwards. Therefore, the CRC unit does not have
* to be explicitly initialized before calling @ref stack_check_corruption_detect_area.
*/
int stack_check_init_corruption_detect_area(void);
/**
* @brief Check the CRC of the stack corruption detection area
*
* This function checks the stack corruption detection area, which must be initialized by
* @ref stack_check_init_corruption_detect_area beforehand.
*
* The CRC unit must be enabled for this function to work properly.
* After calling @stack_check_init_corruption_detect_area, this is the case.
*
* @return 0 if no error is detected, all other values are an error.
* @note Make sure CRC unit is enabled.
*/
int stack_check_corruption_detect_area(void);
#endif /* __STACK_CHECK_H__ */

View File

@ -26,14 +26,16 @@
void HardFault_Handler(void)
{
/* This is a non recoverable fault. Hang here */
/* This is a non recoverable fault. Stop the oven */
oven_driver_set_power(0);
oven_driver_apply_power_level();
/* Set the error led */
led_set(0, 1);
while (1);
/* Try the real panic mode */
panic_mode();
}
/* Overwrite default handler. Go to panic mode */
@ -44,12 +46,9 @@ void __int_default_handler(void)
void panic_mode(void)
{
/* This variable is static, because I don't want it to be on the stack */
static struct safety_memory_boot_status IN_SECTION(.ccm.bss) boot_status;
/* Panic mode is esentially the same as a hardfault,
* but it can be expected, that more functionality is still usable
*/
oven_driver_set_power(0);
oven_driver_apply_power_level();
@ -59,6 +58,6 @@ void panic_mode(void)
(void)safety_memory_set_boot_status(&boot_status);
}
/* Let the watchdog do the rest */
while (1);
}

View File

@ -39,12 +39,32 @@
#include <reflow-controller/safety/safety-memory.h>
#include <helper-macros/helper-macros.h>
#define check_flag_persistent(flag) ((flag)->persistency && (flag)->persistency->persistency)
#define get_flag_weight(flag) ((flag)->weight ? (flag->weight->weight) : SAFETY_FLAG_CONFIG_WEIGHT_NONE)
struct safety_weight {
uint32_t start_dummy;
enum config_weight weight;
enum safety_flag flag;
volatile struct error_flag *flag_ptr;
uint32_t end_dummy;
};
struct safety_persistency {
uint32_t start_dummy;
bool persistency;
enum safety_flag flag;
volatile struct error_flag *flag_ptr;
uint32_t end_dummy;
};
struct error_flag {
const char *name;
enum safety_flag flag;
bool error_state;
bool error_state_inv;
bool persistent;
volatile struct safety_persistency *persistency;
volatile struct safety_weight *weight;
uint32_t key;
};
@ -70,36 +90,24 @@ struct analog_mon {
uint64_t timestamp;
};
struct safety_weight {
uint32_t start_dummy;
enum config_weight weight;
enum safety_flag flag;
volatile struct error_flag *flag_ptr;
uint32_t end_dummy;
};
#define ERR_FLAG_ENTRY(errflag, persistency) {.name=#errflag, .flag = (errflag), .error_state = false, .error_state_inv = true, .persistent = (persistency), .key = 0UL}
#define TIM_MON_ENTRY(mon, min, max, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min_delta = (min), .max_delta = (max), .last = 0ULL, .enabled= false}
#define ANA_MON_ENTRY(mon, min_value, max_value, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = false}
#define ERR_FLAG_WEIGHT_ENTRY(_flag, _weight) {.flag = (_flag), .flag_ptr = NULL, .weight = (_weight), .start_dummy = 0x11823344, .end_dummy = 0xAABBCCFD}
static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false),
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false),
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, false),
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OVERFLOW, true),
ERR_FLAG_ENTRY(ERR_FLAG_TIMING_MEAS_ADC, false),
ERR_FLAG_ENTRY(ERR_FLAG_TIMING_PID, false),
ERR_FLAG_ENTRY(ERR_FLAG_AMON_UC_TEMP, true),
ERR_FLAG_ENTRY(ERR_FLAG_AMON_VREF, false),
ERR_FLAG_ENTRY(ERR_FLAG_STACK, true),
ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_ADC, true),
ERR_FLAG_ENTRY(ERR_FLAG_SYSTICK, true),
ERR_FLAG_ENTRY(ERR_FLAG_WTCHDG_FIRED, true),
ERR_FLAG_ENTRY(ERR_FLAG_UNCAL, false),
ERR_FLAG_ENTRY(ERR_FLAG_DEBUG, true),
ERR_FLAG_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP, false),
ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_MEM_CORRUPT, true),
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF),
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG),
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE),
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OVERFLOW),
ERR_FLAG_ENTRY(ERR_FLAG_TIMING_MEAS_ADC),
ERR_FLAG_ENTRY(ERR_FLAG_TIMING_PID),
ERR_FLAG_ENTRY(ERR_FLAG_AMON_UC_TEMP),
ERR_FLAG_ENTRY(ERR_FLAG_AMON_VREF),
ERR_FLAG_ENTRY(ERR_FLAG_STACK),
ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_ADC),
ERR_FLAG_ENTRY(ERR_FLAG_SYSTICK),
ERR_FLAG_ENTRY(ERR_FLAG_WTCHDG_FIRED),
ERR_FLAG_ENTRY(ERR_FLAG_UNCAL),
ERR_FLAG_ENTRY(ERR_FLAG_DEBUG),
ERR_FLAG_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP),
ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_MEM_CORRUPT),
ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT),
};
static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = {
@ -116,27 +124,14 @@ static volatile struct analog_mon IN_SECTION(.ccm.data) analog_mons[] = {
ERR_FLAG_AMON_UC_TEMP),
};
static const struct safety_weight default_flag_weights[] = {
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OVERFLOW, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_PID, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_UC_TEMP, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_VREF, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_STACK, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SYSTICK, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_WTCHDG_FIRED, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_UNCAL, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_DEBUG, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_MEM_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
};
static const struct safety_weight default_flag_weights[] = { SAFETY_CONFIG_DEFAULT_WEIGHTS };
static const struct safety_persistency default_flag_persistencies[] = {SAFETY_CONFIG_DEFAULT_PERSIST};
static volatile struct safety_persistency IN_SECTION(.ccm.bss) flag_persistencies[COUNT_OF(default_flag_persistencies)];
static uint32_t IN_SECTION(.ccm.bss) flag_persistencies_crc;
static volatile struct safety_weight IN_SECTION(.ccm.bss) flag_weights[COUNT_OF(default_flag_weights)];
static uint32_t IN_SECTION(.ccm.data) flag_weight_crc;
static uint32_t IN_SECTION(.ccm.bss) flag_weight_crc;
static int flag_weight_table_crc_check(void)
{
@ -150,6 +145,17 @@ static int flag_weight_table_crc_check(void)
return 0;
}
static int flag_persistency_table_crc_check(void)
{
crc_unit_reset();
crc_unit_input_array((uint32_t*)flag_persistencies, wordsize_of(flag_persistencies));
if (crc_unit_get_crc() != flag_persistencies_crc)
return -1;
return 0;
}
static volatile struct error_flag *find_error_flag(enum safety_flag flag)
{
uint32_t i;
@ -172,12 +178,14 @@ static void init_safety_flag_weight_table_from_default(void)
volatile struct safety_weight *current_weight;
/* Copy the table */
memcpy((void *)flag_weights, default_flag_weights, wordsize_of(flag_weights));
memcpy((void *)flag_weights, default_flag_weights, sizeof(flag_weights));
/* Fill in the flag pointers */
for (index = 0; index < COUNT_OF(flag_weights); index++) {
current_weight = &flag_weights[index];
current_weight->flag_ptr = find_error_flag(current_weight->flag);
if (current_weight->flag_ptr)
current_weight->flag_ptr->weight = current_weight;
}
crc_unit_reset();
@ -185,6 +193,27 @@ static void init_safety_flag_weight_table_from_default(void)
flag_weight_crc = crc_unit_get_crc();
}
static void init_safety_flag_persistencies_from_default(void)
{
uint32_t index;
volatile struct safety_persistency *current_persistency;
/* Copy values */
memcpy((void *)flag_persistencies, default_flag_persistencies, sizeof(flag_persistencies));
/* Fill in flag pointers */
for (index = 0; index < COUNT_OF(flag_persistencies); index++) {
current_persistency = &flag_persistencies[index];
current_persistency->flag_ptr = find_error_flag(current_persistency->flag);
if (current_persistency->flag_ptr)
current_persistency->flag_ptr->persistency = current_persistency;
}
crc_unit_reset();
crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies));
flag_persistencies_crc = crc_unit_get_crc();
}
static bool error_flag_get_status(const volatile struct error_flag *flag)
{
if (flag->error_state == flag->error_state_inv) {
@ -259,6 +288,31 @@ static void safety_controller_process_monitor_checks()
safety_controller_process_active_timing_mons();
}
static uint8_t flag_enum_to_flag_no(enum safety_flag flag)
{
uint32_t flag_mask;
uint8_t i;
if (!is_power_of_two(flag))
return 0xFF;
flag_mask = (uint32_t)flag;
for (i = 0; i < 32; i++) {
if ((flag_mask >> i) & 0x1U)
break;
}
return i;
}
static enum safety_flag flag_no_to_flag_enum(uint8_t no)
{
if (no >= COUNT_OF(flags))
return ERR_FLAG_NO_FLAG;
return (1U << no);
}
int safety_controller_report_error(enum safety_flag flag)
{
return safety_controller_report_error_with_key(flag, 0x0UL);
@ -279,14 +333,13 @@ int safety_controller_report_error_with_key(enum safety_flag flag, uint32_t key)
flags[i].error_state_inv = !flags[i].error_state;
flags[i].key = key;
if (flags[i].persistent && !old_state) {
if (check_flag_persistent(&flags[i]) && !old_state) {
err_mem_entry.counter = 1;
err_mem_entry.flag_num = i;
err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag);
err_mem_entry.type = SAFETY_MEMORY_ERR_ENTRY_FLAG;
res = safety_memory_insert_error_entry(&err_mem_entry);
if (res) {
if (res)
ret = -12;
}
} else {
ret = 0;
}
@ -350,6 +403,7 @@ void safety_controller_init()
stack_check_init_corruption_detect_area();
init_safety_flag_weight_table_from_default();
init_safety_flag_persistencies_from_default();
if (found_memory_state == SAFETY_MEMORY_INIT_CORRUPTED)
safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT);
@ -428,13 +482,11 @@ static void safety_controller_handle_safety_adc()
/**
* @brief Check the memory structures.
* @return 0 if okay, != 0 when an error was detected. PANIC mode shall be entered in this case.
*/
static int safety_controller_handle_memory_checks(void)
static void safety_controller_handle_memory_checks(void)
{
static uint64_t ts = 0;
enum safety_memory_state found_state;
int panic_request = 0;
if (systick_ticks_have_passed(ts, 250)) {
ts = systick_get_global_tick();
@ -447,10 +499,18 @@ static int safety_controller_handle_memory_checks(void)
}
}
panic_request = flag_weight_table_crc_check();
}
/* If flag weight table is broken, reinit to default and set flag */
if (flag_weight_table_crc_check()) {
safety_controller_report_error(ERR_FLAG_SAFETY_TAB_CORRUPT);
init_safety_flag_weight_table_from_default();
}
return panic_request;
/* If persistency table is broken, reinit to default and set flag */
if(flag_persistency_table_crc_check()) {
safety_controller_report_error(ERR_FLAG_SAFETY_TAB_CORRUPT);
init_safety_flag_persistencies_from_default();
}
}
}
static void safety_controller_do_systick_checking()
@ -472,21 +532,17 @@ static void safety_controller_do_systick_checking()
int safety_controller_handle()
{
int panic_requested;
int ret = 0;
safety_controller_check_stack();
safety_controller_handle_safety_adc();
panic_requested = safety_controller_handle_memory_checks();
/* Panic here. If our internal structures are broken, we cannot be sure of anything anymore */
if (panic_requested)
panic_mode();
safety_controller_handle_memory_checks();
safety_controller_do_systick_checking();
safety_controller_process_monitor_checks();
/* TODO: Check flags for PID and HALT */
/* TODO: Check flag weights and trigger appropriate safety action */
ret |= watchdog_ack(WATCHDOG_MAGIC_KEY);
@ -553,7 +609,7 @@ int safety_controller_get_flag(enum safety_flag flag, bool *status, bool try_ack
found_flag = find_error_flag(flag);
if (found_flag) {
*status = error_flag_get_status(found_flag);
if (try_ack && !found_flag->persistent) {
if (try_ack && !check_flag_persistent(found_flag)) {
/* Flag is generally non persistent
* If key is set, this function cannot remove the flag
*/
@ -583,7 +639,7 @@ int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key)
found_flag = find_error_flag(flag);
if (found_flag) {
if (!found_flag->persistent && (found_flag->key == key || !key)) {
if (!check_flag_persistent(found_flag) && (found_flag->key == key || !found_flag->key)) {
found_flag->error_state = false;
found_flag->error_state_inv = true;
ret = 0;

View File

@ -76,13 +76,21 @@ static enum safety_memory_state safety_memory_get_header(struct safety_memory_he
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 */
/* Check magic */
if (header->magic != SAFETY_MEMORY_MAGIC) {
/* Magic invalid */
ret = SAFETY_MEMORY_INIT_FRESH;
goto return_val;
}
/* Check the header crc */
crc_unit_reset();
crc_unit_input_array((uint32_t *)header, wordsize_of(struct safety_memory_header));
if (crc_unit_get_crc() != 0UL) {
ret = SAFETY_MEMORY_INIT_CORRUPTED;
goto return_val;
}
res = 0;
if (header->boot_status_offset < wordsize_of(struct safety_memory_header))
res++;
@ -106,8 +114,14 @@ return_val:
return ret;
}
static void safety_memory_write_header(const struct safety_memory_header *header)
static void safety_memory_write_and_patch_header(struct safety_memory_header *header)
{
/* Patch the CRC */
crc_unit_reset();
crc_unit_input_array((uint32_t *)header, wordsize_of(struct safety_memory_header) - 1U);
header->crc = crc_unit_get_crc();
/* Write to memory */
backup_ram_write_data(0UL, (uint32_t *)header, wordsize_of(*header));
}
@ -121,10 +135,9 @@ static void safety_memory_write_new_header(void)
header.err_memory_offset = header.config_overrides_offset + SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT;
header.err_memory_end = header.err_memory_offset;
header.magic = SAFETY_MEMORY_MAGIC;
header.magic_i = ~SAFETY_MEMORY_MAGIC;
backup_ram_wipe();
safety_memory_write_header(&header);
safety_memory_write_and_patch_header(&header);
}
static int safety_memory_check_crc()
@ -399,7 +412,7 @@ int safety_memory_insert_error_entry(struct error_memory_entry *entry)
/* Still fits in memory */
backup_ram_write_data(header.err_memory_end, &input_data, 1UL);
header.err_memory_end++;
safety_memory_write_header(&header);
safety_memory_write_and_patch_header(&header);
safety_memory_gen_crc();
ret = 0;
}
@ -435,7 +448,7 @@ int safety_memory_insert_error_entry(struct error_memory_entry *entry)
if ((addr + 1) < backup_ram_get_size_in_words()) {
backup_ram_write_data(addr, &input_data, 1UL);
header.err_memory_end++;
safety_memory_write_header(&header);
safety_memory_write_and_patch_header(&header);
} else {
ret = -3;
goto return_value;