Compare commits

..

3 Commits

5 changed files with 256 additions and 31 deletions

View File

@ -23,7 +23,6 @@
* @{ * @{
*/ */
#ifndef __SAFETY_CONTROLLER_H__ #ifndef __SAFETY_CONTROLLER_H__
#define __SAFETY_CONTROLLER_H__ #define __SAFETY_CONTROLLER_H__
@ -32,30 +31,39 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
enum analog_monitor_status {ANALOG_MONITOR_OK = 0, /**
ANALOG_MONITOR_ERROR, * @brief State of an analog monitor
ANALOG_MONITOR_INACTIVE, */
ANALOG_MONITOR_OVER, enum analog_monitor_status {ANALOG_MONITOR_OK = 0, /**< @brief Monitor set up and ok */
ANALOG_MONITOR_UNDER}; ANALOG_MONITOR_ERROR, /**< @brief An internal error occured */
ANALOG_MONITOR_INACTIVE, /**< @brief Monitor inactive. Reading is not valid */
ANALOG_MONITOR_OVER, /**< @brief Value too high */
ANALOG_MONITOR_UNDER}; /**< @brief Value too low */
/**
* @brief Info structure describing an analog monitor
*/
struct analog_monitor_info { struct analog_monitor_info {
float value; float value; /**< @brief Current analog value */
float min; float min; /**< @brief Minumum value allowed */
float max; float max; /**< @brief Maximum value allowed */
enum analog_monitor_status status; enum analog_monitor_status status; /**< @brief Current monitor status */
uint64_t timestamp; uint64_t timestamp; /**< @brief ms timestamp when @ref analog_monitor_info::value was taken. */
};
struct timing_monitor_info {
uint64_t last_run;
uint64_t min;
uint64_t max;
bool enabled;
uint64_t delta;
}; };
/** /**
* @brief Initialize the safety controller * @brief Info structure describing a timing monitor
*/
struct timing_monitor_info {
uint64_t last_run; /**< @brief Timestamp, when the monitor was last triggered */
uint64_t min; /**< @brief Minimum delay between two activations in ms */
uint64_t max; /**< @brief Maximum delay between two activations in ms */
bool enabled; /**< @brief Monitor enabled */
uint64_t delta; /**< @brief Last delta between two activations */
};
/**
* @brief Initialize the safety controller.
* *
* After a call to this function the controller is iniotlaized and the watchdog is set up. * After a call to this function the controller is iniotlaized and the watchdog is set up.
* You have to call safety_controller_handle * You have to call safety_controller_handle
@ -70,42 +78,177 @@ void safety_controller_init();
*/ */
int safety_controller_handle(); int safety_controller_handle();
/**
* @brief Report one or multiple errors to the safety controller
*
* When passing multipe error glags, the flags have to be ORed together.
*
* @param flag Error flag to report
* @return 0 if successful.
*/
int safety_controller_report_error(enum safety_flag flag); int safety_controller_report_error(enum safety_flag flag);
/**
* @brief Report one or multiple error flags with a key.
*
* When setting a \p key on an error flag. The error flag can only be cleared,
* by passing the same key value to the @ref safety_controller_ack_flag_with_key function.
*
* @param flag Error flag to report
* @param key Key
* @return 0 if successful
*/
int safety_controller_report_error_with_key(enum safety_flag flag, uint32_t key); int safety_controller_report_error_with_key(enum safety_flag flag, uint32_t key);
/**
* @brief Report timing to a timing monitor.
* @param monitor Monitor to report
*/
void safety_controller_report_timing(enum timing_monitor monitor); void safety_controller_report_timing(enum timing_monitor monitor);
/**
* @brief Report an analog value to an analog value monitor
* @param monitor Monitor to report
* @param value Analog value
*/
void safety_controller_report_analog_value(enum analog_value_monitor monitor, float value); void safety_controller_report_analog_value(enum analog_value_monitor monitor, float value);
/**
* @brief Enable or disable a timing monitor.
* @param monitor Monitor to enable
* @param enable State to set the monitor to.
* @return 0 if successful.
*/
int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable); int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable);
/**
* @brief Get the value of an analog monitor.
* @param monitor Monitor to get value from
* @param[out] value The analog value
* @returns Status of the analog monitor. \p value only valid, if return value does not indicate an internal error,
* or an inactive monitor.
*/
enum analog_monitor_status safety_controller_get_analog_mon_value(enum analog_value_monitor monitor, float *value); enum analog_monitor_status safety_controller_get_analog_mon_value(enum analog_value_monitor monitor, float *value);
/**
* @brief Get error flag state and optionally acknowledge the flag
*
* If the flag is persistent, it cannot be ack'ed. In this case this function
* does not return an error code.
*
* @param flag Error flag
* @param[out] status state of the flag.
* @param try_ack Try to ack the flag. This might fail, if the flag is persistent.
* @return 0 if successful.
*/
int safety_controller_get_flag(enum safety_flag flag, bool *status, bool try_ack); int safety_controller_get_flag(enum safety_flag flag, bool *status, bool try_ack);
/**
* @brief Ack an error flag
* @param flag Error flag to ack
* @return 0 if successful, -2 if flag is persistent or keyed. All other values: Errors
*/
int safety_controller_ack_flag(enum safety_flag flag); int safety_controller_ack_flag(enum safety_flag flag);
/**
* @brief Acknowledge error flag with a key
* @param flag Error flag
* @param key Key
* @return 0 if successful, -2 if flag is persistent or key wrong. All other values: Errors
*/
int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key); int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key);
/**
* @brief Get an ored status of multiple flags.
* @param mask Flags to check
* @return True if errors. False if no errors.
*/
bool safety_controller_get_flags_by_mask(enum safety_flag mask); bool safety_controller_get_flags_by_mask(enum safety_flag mask);
/**
* @brief Get the count of error flags
* @return Error flag count
*/
uint32_t safety_controller_get_flag_count(); uint32_t safety_controller_get_flag_count();
/**
* @brief Get the count of analog monitors
* @return Analog monitor count
*/
uint32_t safety_controller_get_analog_monitor_count(); uint32_t safety_controller_get_analog_monitor_count();
/**
* @brief Get an error flag's name by its index.
*
* The name of the flag will be cropped, if the buffersize is too small.
* Paramter \p buffsize may not be zero.
*
* @param index 0 based index.
* @param[out] buffer Buffer to write the name to.
* @param buffsize Buffer size. This has to be big enough to hold the name and the \0-terminator
* @return 0 of successful
*/
int safety_controller_get_flag_name_by_index(uint32_t index, char *buffer, size_t buffsize); int safety_controller_get_flag_name_by_index(uint32_t index, char *buffer, size_t buffsize);
/**
* @brief Get the safety flag by its internal index.
* @param index 0 based index.
* @param[out] status Current flag state. May be NULL.
* @param[out] flag_enum Flag enum used in SW. May be NULL.
* @return 0 if successful; else: negative
*/
int safety_controller_get_flag_by_index(uint32_t index, bool *status, enum safety_flag *flag_enum); int safety_controller_get_flag_by_index(uint32_t index, bool *status, enum safety_flag *flag_enum);
/**
* @brief Get an analog monitor info by the monitor's index
* @param index 0 based index
* @param[out] info Info structure.
* @return 0 if successful.
* -1001, if \p index out of range
* -1002, if \p info is NULL
*/
int safety_controller_get_analog_mon_by_index(uint32_t index, struct analog_monitor_info *info); int safety_controller_get_analog_mon_by_index(uint32_t index, struct analog_monitor_info *info);
/**
* @brief Get the name of an analog monitor by its index
*
* The buffer has to be large enough to hold the name plus a null terminator.
* If the buffer is not large enough, The name will be cropped.
* Parameter \p buffsize may not be zero.
*
* @param index 0 based index
* @param buffer Buffer to write name to
* @param buffsize Buffer size
* @return
*/
int safety_controller_get_analog_mon_name_by_index(uint32_t index, char *buffer, size_t buffsize); int safety_controller_get_analog_mon_name_by_index(uint32_t index, char *buffer, size_t buffsize);
/**
* @brief Get timing monitor information by index
* @param index 0 based index
* @param[out] info Info
* @return 0 if successful
*/
int safety_controller_get_timing_mon_by_index(uint32_t index, struct timing_monitor_info *info); int safety_controller_get_timing_mon_by_index(uint32_t index, struct timing_monitor_info *info);
/**
* @brief Get the name of a timing monitor by its index
*
* The buffer has to be large enough to hold the name plus a null terminator.
* If the buffer is not large enough, The name will be cropped.
* Parameter \p buffsize may not be zero.
*
* @param index 0 based index
* @param buffer Buffer to write name to.
* @param buffsize Buffer size
* @return 0 if successful
*/
int safety_controller_get_timing_mon_name_by_index(uint32_t index, char *buffer, size_t buffsize); int safety_controller_get_timing_mon_name_by_index(uint32_t index, char *buffer, size_t buffsize);
/**
* @brief Get the count of timing monitors
* @return Timing monitor count
*/
uint32_t safety_controller_get_timing_monitor_count(); uint32_t safety_controller_get_timing_monitor_count();
#endif /* __SAFETY_CONTROLLER_H__ */ #endif /* __SAFETY_CONTROLLER_H__ */

View File

@ -37,6 +37,10 @@ int32_t stack_check_get_usage();
*/ */
int32_t stack_check_get_free(); int32_t stack_check_get_free();
/**
* @brief Check if the current free stack space is bigger than @ref STACK_CHECK_MIN_HEAP_GAP
* @return 0: enough space available, -1: stack space low
*/
static inline int stack_check_collision() static inline int stack_check_collision()
{ {
int ret = 0; int ret = 0;
@ -49,6 +53,10 @@ static inline int stack_check_collision()
return ret; return ret;
} }
/**
* @brief Get the current stack pointer value
* @return
*/
static inline uint32_t read_stack_pointer() static inline uint32_t read_stack_pointer()
{ {
uint32_t stack_pointer; uint32_t stack_pointer;

View File

@ -52,7 +52,6 @@ void panic_mode(void)
oven_driver_set_power(0); oven_driver_set_power(0);
oven_driver_apply_power_level(); oven_driver_apply_power_level();
/* TODO: implement panic mode */
if (!safety_memory_get_boot_status(&boot_status)) { if (!safety_memory_get_boot_status(&boot_status)) {
boot_status.reset_from_panic = 0xFFFFFFFF; boot_status.reset_from_panic = 0xFFFFFFFF;
(void)safety_memory_set_boot_status(&boot_status); (void)safety_memory_set_boot_status(&boot_status);

View File

@ -313,12 +313,7 @@ static enum safety_flag flag_no_to_flag_enum(uint8_t no)
return (1U << no); return (1U << no);
} }
int safety_controller_report_error(enum safety_flag flag) static int report_error(enum safety_flag flag, uint32_t key, bool prevent_error_mem_enty)
{
return safety_controller_report_error_with_key(flag, 0x0UL);
}
int safety_controller_report_error_with_key(enum safety_flag flag, uint32_t key)
{ {
uint32_t i; uint32_t i;
int ret = -1; int ret = -1;
@ -333,7 +328,7 @@ 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].error_state_inv = !flags[i].error_state;
flags[i].key = key; flags[i].key = key;
if (check_flag_persistent(&flags[i]) && !old_state) { if (check_flag_persistent(&flags[i]) && !old_state && !prevent_error_mem_enty) {
err_mem_entry.counter = 1; err_mem_entry.counter = 1;
err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag); err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag);
err_mem_entry.type = SAFETY_MEMORY_ERR_ENTRY_FLAG; err_mem_entry.type = SAFETY_MEMORY_ERR_ENTRY_FLAG;
@ -349,6 +344,16 @@ int safety_controller_report_error_with_key(enum safety_flag flag, uint32_t key)
return ret; return ret;
} }
int safety_controller_report_error(enum safety_flag flag)
{
return safety_controller_report_error_with_key(flag, 0x0UL);
}
int safety_controller_report_error_with_key(enum safety_flag flag, uint32_t key)
{
return report_error(flag, key, false);
}
void safety_controller_report_timing(enum timing_monitor monitor) void safety_controller_report_timing(enum timing_monitor monitor)
{ {
volatile struct timing_mon *tim; volatile struct timing_mon *tim;
@ -387,9 +392,42 @@ void safety_controller_report_analog_value(enum analog_value_monitor monitor, fl
} }
/**
* @brief Return the flags, which are set in the error memory
* @param flags Flags read from error memory
* @return 0 if ok, != 0 if error
*/
static enum safety_flag get_safety_flags_from_error_mem(enum safety_flag *flags)
{
uint32_t count;
uint32_t idx;
int res;
enum safety_flag return_flags = 0;
struct error_memory_entry entry;
if (!flags)
return -1001;
res = safety_memory_get_error_entry_count(&count);
if (res)
return -1;
for (idx = 0; idx < count; idx++) {
res = safety_memory_get_error_entry(idx, &entry);
if (entry.type == SAFETY_MEMORY_ERR_ENTRY_FLAG) {
return_flags |= flag_no_to_flag_enum(entry.flag_num);
}
}
*flags = return_flags;
return 0;
}
void safety_controller_init() void safety_controller_init()
{ {
enum safety_memory_state found_memory_state; enum safety_memory_state found_memory_state;
enum safety_flag flags_in_err_mem = ERR_FLAG_NO_FLAG;
int res;
/* Init the safety memory */ /* Init the safety memory */
if (safety_memory_init(&found_memory_state)) { if (safety_memory_init(&found_memory_state)) {
@ -407,6 +445,14 @@ void safety_controller_init()
if (found_memory_state == SAFETY_MEMORY_INIT_CORRUPTED) if (found_memory_state == SAFETY_MEMORY_INIT_CORRUPTED)
safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT); safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT);
else if (found_memory_state == SAFETY_MEMORY_INIT_VALID_MEMORY) {
/* restore the corrupt flag flag */
res = get_safety_flags_from_error_mem(&flags_in_err_mem);
if (res)
panic_mode();
if (flags_in_err_mem & ERR_FLAG_SAFETY_MEM_CORRUPT)
report_error(ERR_FLAG_SAFETY_MEM_CORRUPT, 0, true);
}
/* Init default flag states */ /* Init default flag states */
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_UNSTABLE, safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_UNSTABLE,

View File

@ -49,6 +49,27 @@ static shellmatta_instance_t shell;
static char shell_buffer[512]; static char shell_buffer[512];
static char IN_SECTION(.ccm.bss) history_buffer[600]; static char IN_SECTION(.ccm.bss) history_buffer[600];
static bool check_opt(const char *args, uint32_t len, const char *opt_to_check)
{
char str[128];
const char *ptr;
static const char * const tokens = "\t ";
strncpy(str, args, sizeof(str));
str[sizeof(str) - 1] = 0;
/* Tokenize the string */
ptr = strtok(str, tokens);
while (ptr) {
if (strcmp(ptr, opt_to_check) == 0)
return true;
ptr = strtok(NULL, tokens);
}
return false;
}
static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle, static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle,
const char *arguments, const char *arguments,
uint32_t length) uint32_t length)
@ -354,10 +375,15 @@ static shellmatta_retCode_t shell_cmd_read_flags(const shellmatta_handle_t handl
uint32_t i; uint32_t i;
char name[64]; char name[64];
bool flag; bool flag;
bool tryack;
int status; int status;
enum safety_flag flag_enum;
struct analog_monitor_info amon_info; struct analog_monitor_info amon_info;
struct timing_monitor_info timing_info; struct timing_monitor_info timing_info;
/* Check for the --ack option */
tryack = check_opt(arguments, length, "--ack");
shellmatta_printf(handle, "Error flags\r\n" shellmatta_printf(handle, "Error flags\r\n"
"-----------\r\n"); "-----------\r\n");
@ -369,12 +395,15 @@ static shellmatta_retCode_t shell_cmd_read_flags(const shellmatta_handle_t handl
continue; continue;
} }
status = safety_controller_get_flag_by_index(i, &flag, NULL); status = safety_controller_get_flag_by_index(i, &flag, &flag_enum);
if (status) { if (status) {
shellmatta_printf(handle, "Error getting flag value %lu\r\n", i); shellmatta_printf(handle, "Error getting flag value %lu\r\n", i);
continue; continue;
} }
if (tryack)
safety_controller_ack_flag(flag_enum);
shellmatta_printf(handle, "\t%2lu) %-20s\t[%s]\r\n", i+1, name, (flag ? "\e[1;31mERR\e[m" : "\e[32mOK\e[m")); shellmatta_printf(handle, "\t%2lu) %-20s\t[%s]\r\n", i+1, name, (flag ? "\e[1;31mERR\e[m" : "\e[32mOK\e[m"));
} }
@ -624,8 +653,8 @@ static shellmatta_cmd_t cmd[17] = {
{ {
.cmd = "safety-flags", .cmd = "safety-flags",
.cmdAlias = "flags", .cmdAlias = "flags",
.helpText = "", .helpText = "Reads and may clear safety flags",
.usageText = "", .usageText = "flags [--ack]",
.cmdFct = shell_cmd_read_flags, .cmdFct = shell_cmd_read_flags,
.next = &cmd[13], .next = &cmd[13],
}, },