Edit doxygen headers and improve flag weight handling in safety controller

This commit is contained in:
Mario Hüttel 2021-01-25 20:59:48 +01:00
parent 870c228e37
commit 55f35a5009
4 changed files with 215 additions and 72 deletions

View File

@ -32,6 +32,8 @@
* *
* The enum type is binary or'able to allow combining * The enum type is binary or'able to allow combining
* multiple safety flags. * multiple safety flags.
*
* @note For a more detailed explaination of the flags, check out the Sphinx documentation.
*/ */
enum safety_flag { enum safety_flag {
ERR_FLAG_NO_FLAG = 0, ERR_FLAG_NO_FLAG = 0,
@ -80,11 +82,11 @@ enum analog_value_monitor {
ERR_AMON_SUPPLY_VOLT = (1<<2), ERR_AMON_SUPPLY_VOLT = (1<<2),
}; };
#define ERR_FLAG_ENTRY(errflag) {.name=#errflag, .flag = (errflag), .error_state = false, .error_state_inv = true, .key = 0UL, .weight = NULL, .persistency = NULL} #define ERR_FLAG_ENTRY(errflag) {.name=#errflag, .flag = (errflag), .error_state = false, .error_state_inv = true, .key = 0UL, .weight = NULL, .persistence = 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 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 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_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} #define ERR_FLAG_PERSIST_ENTRY(_flag, _persist) {.flag = (_flag), .flag_ptr = NULL, .persistence = (_persist), .start_dummy = 0xFF1100BB, .end_dummy = 0xEBB439A2}
/** /**
* @brief Magic key used to reset the watchdog using the @ref watchdog_ack function * @brief Magic key used to reset the watchdog using the @ref watchdog_ack function

View File

@ -120,7 +120,7 @@ struct error_memory_entry {
*/ */
enum config_override_entry_type { enum config_override_entry_type {
SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT = 1, SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT = 1,
SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTANCE = 2, SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE = 2,
}; };
/** /**

View File

@ -42,57 +42,111 @@
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.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) * @brief Macro that checks if a given @ref error_flag is persistent
*/
#define check_flag_persistent(flag) ((flag)->persistence && (flag)->persistence->persistence)
/**
* @brief Macro that retrieves the flag weight of a given @ref error_flag
*
* If no flag weight table is present, the flag is evaluated as SAFETY_FLAG_CONFIG_WEIGHT_PANIC
*/
#define get_flag_weight(flag) ((flag)->weight ? ((flag)->weight->weight) : SAFETY_FLAG_CONFIG_WEIGHT_PANIC)
/**
* @brief Safety controller internal structure implementing a safety flag weight.
*/
struct safety_weight { struct safety_weight {
uint32_t start_dummy; /** @brief Dummy value. This seeds the CRC */
enum config_weight weight; uint32_t start_dummy;
enum safety_flag flag;
volatile struct error_flag *flag_ptr; /** @brief The safety flag's weight */
uint32_t end_dummy; enum config_weight weight;
/** @brief The enum value of the flag this weight corresponds to */
enum safety_flag flag;
/** @brief the flag, this weight corresponds to */
volatile struct error_flag *flag_ptr;
/** @brief Dummy value. This seeds the CRC */
uint32_t end_dummy;
}; };
struct safety_persistency { /**
uint32_t start_dummy; * @brief Safety controller internal struct implementing a flag persistence entry
bool persistency; */
enum safety_flag flag; struct safety_persistence {
volatile struct error_flag *flag_ptr; /** @brief Dummy value. This seeds the CRC */
uint32_t end_dummy; uint32_t start_dummy;
/** @brief Corresponding flag is persistent and cannot be cleared */
bool persistence;
/** @brief Corresponding safety flag's enum value */
enum safety_flag flag;
/** @brief Corresponding safety error flag */
volatile struct error_flag *flag_ptr;
/** @brief Dummy value. This seeds the CRC */
uint32_t end_dummy;
}; };
/**
* @brief Safety controller internal struct implementing an error flag
*/
struct error_flag { struct error_flag {
const char *name; /** @brief Name of the error flag */
enum safety_flag flag; const char *name;
bool error_state;
bool error_state_inv; /** @brief Enum value of this safety flag */
volatile struct safety_persistency *persistency; enum safety_flag flag;
volatile struct safety_weight *weight;
uint32_t key; /** @brief The flag's state. True is errorneous. */
bool error_state;
/** @brief Not the flag's state. This always has to be inverted to @ref error_flag::error_state */
bool error_state_inv;
/** @brief Persistence entry of this flag */
volatile struct safety_persistence *persistence;
/** @brief Weight entry of this flag */
volatile struct safety_weight *weight;
/** @brief Key needed to remove this safety flag. If key == 0, no key is set and
* the flag can be cleared by all code
*/
uint32_t key;
}; };
struct timing_mon { struct timing_mon {
const char *name; const char *name;
enum timing_monitor monitor; enum timing_monitor monitor;
enum safety_flag associated_flag; enum safety_flag associated_flag;
uint64_t min_delta; uint64_t min_delta;
uint64_t max_delta; uint64_t max_delta;
uint64_t last; uint64_t last;
uint64_t calculated_delta; uint64_t calculated_delta;
bool enabled; bool enabled;
}; };
struct analog_mon { struct analog_mon {
const char *name; const char *name;
enum analog_value_monitor monitor; enum analog_value_monitor monitor;
enum safety_flag associated_flag; enum safety_flag associated_flag;
float min; float min;
float max; float max;
float value; float value;
bool valid; bool valid;
uint64_t timestamp; uint64_t timestamp;
}; };
/**
* @brief All safety error flags.
*/
static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = { static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF), ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF),
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG), ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG),
@ -114,6 +168,9 @@ static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT), ERR_FLAG_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT),
}; };
/**
* @brief All timing monitors
*/
static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = { static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = {
TIM_MON_ENTRY(ERR_TIMING_PID, 2, 5000, ERR_FLAG_TIMING_PID), TIM_MON_ENTRY(ERR_TIMING_PID, 2, 5000, ERR_FLAG_TIMING_PID),
TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC), TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC),
@ -121,6 +178,9 @@ static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = {
TIM_MON_ENTRY(ERR_TIMING_MAIN_LOOP, 0, 1000, ERR_FLAG_TIMING_MAIN_LOOP), TIM_MON_ENTRY(ERR_TIMING_MAIN_LOOP, 0, 1000, ERR_FLAG_TIMING_MAIN_LOOP),
}; };
/**
* @brief All analog value monitors
*/
static volatile struct analog_mon IN_SECTION(.ccm.data) analog_mons[] = { static volatile struct analog_mon IN_SECTION(.ccm.data) analog_mons[] = {
ANA_MON_ENTRY(ERR_AMON_VREF, SAFETY_ADC_VREF_MVOLT - SAFETY_ADC_VREF_TOL_MVOLT, ANA_MON_ENTRY(ERR_AMON_VREF, SAFETY_ADC_VREF_MVOLT - SAFETY_ADC_VREF_TOL_MVOLT,
SAFETY_ADC_VREF_MVOLT + SAFETY_ADC_VREF_TOL_MVOLT, ERR_FLAG_AMON_VREF), SAFETY_ADC_VREF_MVOLT + SAFETY_ADC_VREF_TOL_MVOLT, ERR_FLAG_AMON_VREF),
@ -131,16 +191,58 @@ static volatile struct analog_mon IN_SECTION(.ccm.data) analog_mons[] = {
ERR_FLAG_AMON_SUPPLY_VOLT), ERR_FLAG_AMON_SUPPLY_VOLT),
}; };
/**
* @brief The default flag weights, that are loaded on boot.
*/
static const struct safety_weight default_flag_weights[] = { SAFETY_CONFIG_DEFAULT_WEIGHTS }; 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)]; /**
* @brief The default flag persistencies, that are loaded on boot.
*/
static const struct safety_persistence default_flag_persistencies[] = {SAFETY_CONFIG_DEFAULT_PERSIST};
/**
* @brief The working copy of the flag persistence table. It is protected by the @ref flag_persistencies_crc
* @note This is stored in CCM RAM
*/
static volatile struct safety_persistence IN_SECTION(.ccm.bss) flag_persistencies[COUNT_OF(default_flag_persistencies)];
/**
* @brief The CRC of the flag weight table @ref flag_persistencies.
*
* The CRC is calculated using the internal CRC module of the STM32F407 controller.
* See the refernece manual for the polynomial.
*
* @note This is stored in CCM RAM.
*/
static uint32_t IN_SECTION(.ccm.bss) flag_persistencies_crc; static uint32_t IN_SECTION(.ccm.bss) flag_persistencies_crc;
/**
* @brief The working copy of the flag weight table. It is protected by the @ref flag_weight_crc.
* @note This is stored in CCM RAM
*/
static volatile struct safety_weight IN_SECTION(.ccm.bss) flag_weights[COUNT_OF(default_flag_weights)]; static volatile struct safety_weight IN_SECTION(.ccm.bss) flag_weights[COUNT_OF(default_flag_weights)];
/**
* @brief The CRC of the flag weight table @ref flag_weights.
*
* The CRC is calculated using the internal CRC module of the STM32F407 controller.
* See the refernece manual for the polynomial.
*
* @note This is stored in CCM RAM.
*/
static uint32_t IN_SECTION(.ccm.bss) flag_weight_crc; static uint32_t IN_SECTION(.ccm.bss) flag_weight_crc;
/**
* @brief Convert a flag enum to the flag number.
*
* Flag numbers are used by the error memory to store flags.
* This function will fail and return 0xFF if multiple flags are ORed and
* passed as flag parameter.
*
* @param flag Flag enum
* @return Flag number or 0xFF in case of an error
*/
static uint8_t flag_enum_to_flag_no(enum safety_flag flag) static uint8_t flag_enum_to_flag_no(enum safety_flag flag)
{ {
uint32_t flag_mask; uint32_t flag_mask;
@ -158,6 +260,14 @@ static uint8_t flag_enum_to_flag_no(enum safety_flag flag)
return i; return i;
} }
/**
* @brief Convert a safety flag's number to its enum value.
*
* Flag numbers are used by the error memory to store flags.
*
* @param no The flag number.
* @return Flag enum
*/
static enum safety_flag flag_no_to_flag_enum(uint8_t no) static enum safety_flag flag_no_to_flag_enum(uint8_t no)
{ {
if (no >= COUNT_OF(flags)) if (no >= COUNT_OF(flags))
@ -166,7 +276,10 @@ static enum safety_flag flag_no_to_flag_enum(uint8_t no)
return (1U << no); return (1U << no);
} }
/**
* @brief Check the CRC chacksum of the flag weight table
* @return 0 if CRC is valid, else -1;
*/
static int flag_weight_table_crc_check(void) static int flag_weight_table_crc_check(void)
{ {
/* Check the flag weight table */ /* Check the flag weight table */
@ -179,6 +292,10 @@ static int flag_weight_table_crc_check(void)
return 0; return 0;
} }
/**
* @brief Check the CRC chacksum of the flag persistence table
* @return 0 if CRC is valid, else -1.
*/
static int flag_persistency_table_crc_check(void) static int flag_persistency_table_crc_check(void)
{ {
crc_unit_reset(); crc_unit_reset();
@ -190,6 +307,15 @@ static int flag_persistency_table_crc_check(void)
return 0; return 0;
} }
/**
* @brief Find the error flag structure for a given safety_flag enum
*
* Only one flag can be given at a time. Giving multiple flags by ORing them
* together, will not math any flag at all.
*
* @param flag Enum defining the flag.
* @return NULL in case nothing matched. Pointer otherwise.
*/
static volatile struct error_flag *find_error_flag(enum safety_flag flag) static volatile struct error_flag *find_error_flag(enum safety_flag flag)
{ {
uint32_t i; uint32_t i;
@ -227,20 +353,26 @@ static void init_safety_flag_weight_table_from_default(void)
flag_weight_crc = crc_unit_get_crc(); flag_weight_crc = crc_unit_get_crc();
} }
/**
* @brief Initialize the default persistence settings of all safety flags.
*
* This function copies the default persistence settings of the safety flags defined in
* @ref SAFETY_CONFIG_DEFAULT_PERSIST and computes the protection CRC over the settings.
*/
static void init_safety_flag_persistencies_from_default(void) static void init_safety_flag_persistencies_from_default(void)
{ {
uint32_t index; uint32_t index;
volatile struct safety_persistency *current_persistency; volatile struct safety_persistence *current_persistence;
/* Copy values */ /* Copy values */
memcpy((void *)flag_persistencies, default_flag_persistencies, sizeof(flag_persistencies)); memcpy((void *)flag_persistencies, default_flag_persistencies, sizeof(flag_persistencies));
/* Fill in flag pointers */ /* Fill in flag pointers */
for (index = 0; index < COUNT_OF(flag_persistencies); index++) { for (index = 0; index < COUNT_OF(flag_persistencies); index++) {
current_persistency = &flag_persistencies[index]; current_persistence = &flag_persistencies[index];
current_persistency->flag_ptr = find_error_flag(current_persistency->flag); current_persistence->flag_ptr = find_error_flag(current_persistence->flag);
if (current_persistency->flag_ptr) if (current_persistence->flag_ptr)
current_persistency->flag_ptr->persistency = current_persistency; current_persistence->flag_ptr->persistence = current_persistence;
} }
crc_unit_reset(); crc_unit_reset();
@ -250,6 +382,12 @@ static void init_safety_flag_persistencies_from_default(void)
/** /**
* @brief Apply the config overrrides stored in the safety memory. * @brief Apply the config overrrides stored in the safety memory.
*
* The config overrides are read from the safety memory and applied.
* The config overrides can override the following things:
*
* 1) Safety Weights (See @ref config_weight)
* 2) Flag Persistence
*/ */
static void apply_config_overrides(void) static void apply_config_overrides(void)
{ {
@ -275,11 +413,11 @@ static void apply_config_overrides(void)
flag->weight->weight = override.entry.weight_override.weight; flag->weight->weight = override.entry.weight_override.weight;
} }
break; break;
case SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTANCE: case SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE:
flag_enum = flag_no_to_flag_enum(override.entry.persistance_override.flag); flag_enum = flag_no_to_flag_enum(override.entry.persistance_override.flag);
flag = find_error_flag(flag_enum); flag = find_error_flag(flag_enum);
if (flag && flag->persistency) { if (flag && flag->persistence) {
flag->persistency->persistency = override.entry.persistance_override.persistance; flag->persistence->persistence = override.entry.persistance_override.persistance;
} }
break; break;
default: default:
@ -756,31 +894,34 @@ static void safety_controller_do_systick_checking()
/** /**
* @brief Handle weightet flags. * @brief Handle weightet flags.
* *
* This functions loops oer all weight entries and checks the corresponding flags. If a flag * This functions loops over all error flags and checks the weights. If a flag
* is set, the appropriate action defined by the flag weight is executed. * is set, the appropriate action defined by the flag weight is executed.
* @note If no flag weigth is present for a given error flag, it is treated as the most critical category
* (@ref SAFETY_FLAG_CONFIG_WEIGHT_PANIC)
*/ */
static void safety_controller_handle_weighted_flags() static void safety_controller_handle_weighted_flags()
{ {
uint32_t weight_index; uint32_t flag_index;
volatile struct safety_weight *current_weight; volatile struct error_flag *current_flag;
enum config_weight flag_weigth;
for (weight_index = 0; weight_index < COUNT_OF(flag_weights); weight_index++) { for (flag_index = 0u; flag_index < COUNT_OF(flags); flag_index++) {
current_weight = &flag_weights[weight_index]; current_flag = &flags[flag_index];
if (error_flag_get_status(current_weight->flag_ptr)) { flag_weigth = get_flag_weight(current_flag);
switch (current_weight->weight) { switch (flag_weigth) {
case SAFETY_FLAG_CONFIG_WEIGHT_NONE: case SAFETY_FLAG_CONFIG_WEIGHT_NONE:
break; break;
case SAFETY_FLAG_CONFIG_WEIGHT_PID: case SAFETY_FLAG_CONFIG_WEIGHT_PID:
oven_pid_abort(); oven_pid_abort();
break; break;
case SAFETY_FLAG_CONFIG_WEIGHT_PANIC: case SAFETY_FLAG_CONFIG_WEIGHT_PANIC:
/* Expected fallthrough */ /* EXPECTED FALLTHRU */
default: default:
oven_pid_abort(); oven_pid_abort();
panic_mode(); panic_mode();
break; break;
}
} }
} }
} }

View File

@ -486,7 +486,7 @@ static uint32_t convert_config_override_to_word(const struct config_override *co
data |= 0xAA0000A2UL; data |= 0xAA0000A2UL;
data |= ((uint32_t)conf_override->entry.weight_override.flag) << 16; data |= ((uint32_t)conf_override->entry.weight_override.flag) << 16;
data |= ((uint32_t)conf_override->entry.weight_override.weight) << 8; data |= ((uint32_t)conf_override->entry.weight_override.weight) << 8;
} else if (conf_override->type == SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTANCE) { } else if (conf_override->type == SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE) {
data |= 0xBB00008EUL; data |= 0xBB00008EUL;
data |= ((uint32_t)conf_override->entry.persistance_override.flag) << 16; data |= ((uint32_t)conf_override->entry.persistance_override.flag) << 16;
data |= ((uint32_t)(conf_override->entry.persistance_override.persistance ? 1UL : 0UL)) << 8; data |= ((uint32_t)(conf_override->entry.persistance_override.persistance ? 1UL : 0UL)) << 8;
@ -597,7 +597,7 @@ int safety_memory_get_config_override(uint32_t idx, struct config_override *conf
break; break;
case 0x8E: case 0x8E:
/* persistance override */ /* persistance override */
config_override->type = SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTANCE; config_override->type = SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE;
config_override->entry.persistance_override.flag = (data & 0xFF0000UL) >> 16; config_override->entry.persistance_override.flag = (data & 0xFF0000UL) >> 16;
config_override->entry.persistance_override.persistance = ((data & 0xFF00UL) >> 8) ? true : false; config_override->entry.persistance_override.persistance = ((data & 0xFF00UL) >> 8) ? true : false;
break; break;