Further work on safety controller
This commit is contained in:
		@@ -32,6 +32,8 @@ enum safety_flag {
 | 
				
			|||||||
	ERR_FLAG_AMON_VREF = (1<<6),
 | 
						ERR_FLAG_AMON_VREF = (1<<6),
 | 
				
			||||||
	ERR_FLAG_AMON_UC_TEMP = (1<<7),
 | 
						ERR_FLAG_AMON_UC_TEMP = (1<<7),
 | 
				
			||||||
	ERR_FLAG_STACK = (1<<8),
 | 
						ERR_FLAG_STACK = (1<<8),
 | 
				
			||||||
 | 
						ERR_FLAG_SAFETY_ADC = (1<<9),
 | 
				
			||||||
 | 
						ERR_FLAG_SYSTICK = (1<<10),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum timing_monitor {
 | 
					enum timing_monitor {
 | 
				
			||||||
@@ -51,12 +53,16 @@ enum analog_value_monitor {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
#define WATCHDOG_MAGIC_KEY 0x1a2c56F4
 | 
					#define WATCHDOG_MAGIC_KEY 0x1a2c56F4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUGBUILD
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief If one, the watchdog is halted whenever the core is halted by the debugger.
 | 
					 * @brief If one, the watchdog is halted whenever the core is halted by the debugger.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This is only applicable in a debug build. In release mode, the watchdog stays always enabled
 | 
					 * This is only applicable in a debug build. In release mode, the watchdog stays always enabled
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define WATCHDOG_HALT_DEBUG (1)
 | 
					#define WATCHDOG_HALT_DEBUG (1)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define WATCHDOG_HALT_DEBUG (0)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WATCHDOG_PRESCALER 4
 | 
					#define WATCHDOG_PRESCALER 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,7 +62,9 @@ int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool safety_controller_get_flag(enum safety_flag);
 | 
					int safety_controller_get_flag(enum safety_flag flag, bool *status, bool try_ack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int safety_controller_ack_flag(enum safety_flag flag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __SAFETY_CONTROLLER_H__ */
 | 
					#endif /* __SAFETY_CONTROLLER_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@
 | 
				
			|||||||
#include <reflow-controller/safety/safety-config.h>
 | 
					#include <reflow-controller/safety/safety-config.h>
 | 
				
			||||||
#include <reflow-controller/safety/watchdog.h>
 | 
					#include <reflow-controller/safety/watchdog.h>
 | 
				
			||||||
#include <reflow-controller/safety/safety-adc.h>
 | 
					#include <reflow-controller/safety/safety-adc.h>
 | 
				
			||||||
 | 
					#include <reflow-controller/stack-check.h>
 | 
				
			||||||
#include <helper-macros/helper-macros.h>
 | 
					#include <helper-macros/helper-macros.h>
 | 
				
			||||||
#include <reflow-controller/systick.h>
 | 
					#include <reflow-controller/systick.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,16 +82,21 @@ static struct error_flag flags[] = {
 | 
				
			|||||||
	ERR_FLAG_ENTRY(ERR_FLAG_AMON_UC_TEMP, true),
 | 
						ERR_FLAG_ENTRY(ERR_FLAG_AMON_UC_TEMP, true),
 | 
				
			||||||
	ERR_FLAG_ENTRY(ERR_FLAG_AMON_VREF, false),
 | 
						ERR_FLAG_ENTRY(ERR_FLAG_AMON_VREF, false),
 | 
				
			||||||
	ERR_FLAG_ENTRY(ERR_FLAG_STACK, true),
 | 
						ERR_FLAG_ENTRY(ERR_FLAG_STACK, true),
 | 
				
			||||||
 | 
						ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_ADC, true),
 | 
				
			||||||
 | 
						ERR_FLAG_ENTRY(ERR_FLAG_SYSTICK, true),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct timing_mon timings[] = {
 | 
					static struct timing_mon timings[] = {
 | 
				
			||||||
	TIM_MON_ENTRY(ERR_TIMING_PID, 1, 800, ERR_FLAG_TIMING_PID),
 | 
						TIM_MON_ENTRY(ERR_TIMING_PID, 1, 800, ERR_FLAG_TIMING_PID),
 | 
				
			||||||
	TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 1, 50, ERR_FLAG_TIMING_MEAS_ADC),
 | 
						TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 1, 50, ERR_FLAG_TIMING_MEAS_ADC),
 | 
				
			||||||
 | 
						TIM_MON_ENTRY(ERR_TIMING_SAFETY_ADC, 1, 250, ERR_FLAG_SAFETY_ADC),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct analog_mon analog_mons[] = {
 | 
					static struct analog_mon analog_mons[] = {
 | 
				
			||||||
	ANA_MON_ENTRY(ERR_AMON_VREF, 2480.0f, 2520.0f, ERR_FLAG_AMON_VREF),
 | 
						ANA_MON_ENTRY(ERR_AMON_VREF, SAFETY_ADC_VREF_MVOLT - SAFETY_ADC_VREF_TOL_MVOLT,
 | 
				
			||||||
	ANA_MON_ENTRY(ERR_AMON_UC_TEMP, 0.0f, 55.0f, ERR_FLAG_AMON_UC_TEMP),
 | 
							      SAFETY_ADC_VREF_MVOLT + SAFETY_ADC_VREF_TOL_MVOLT, ERR_FLAG_AMON_VREF),
 | 
				
			||||||
 | 
						ANA_MON_ENTRY(ERR_AMON_UC_TEMP, SAFETY_ADC_TEMP_LOW_LIM, SAFETY_ADC_TEMP_HIGH_LIM,
 | 
				
			||||||
 | 
							      ERR_FLAG_AMON_UC_TEMP),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct analog_mon *find_analog_mon(enum analog_value_monitor mon)
 | 
					static struct analog_mon *find_analog_mon(enum analog_value_monitor mon)
 | 
				
			||||||
@@ -132,9 +138,49 @@ static struct error_flag *find_error_flag(enum safety_flag flag)
 | 
				
			|||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void safety_controller_process_active_timing_mons()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint32_t i;
 | 
				
			||||||
 | 
						struct timing_mon *current_mon;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < COUNT_OF(timings); i++) {
 | 
				
			||||||
 | 
							current_mon = &timings[i];
 | 
				
			||||||
 | 
							if (current_mon->enabled) {
 | 
				
			||||||
 | 
								if (systick_ticks_have_passed(current_mon->last, current_mon->max_delta))
 | 
				
			||||||
 | 
									safety_controller_report_error(current_mon->associated_flag);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void safety_controller_process_checks()
 | 
					static void safety_controller_process_checks()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// TODO: Implement
 | 
						static bool startup_completed = false;
 | 
				
			||||||
 | 
						static uint64_t last_systick = 0;
 | 
				
			||||||
 | 
						enum analog_monitor_status amon_state;
 | 
				
			||||||
 | 
						float amon_value;
 | 
				
			||||||
 | 
						uint64_t systick;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						systick = systick_get_global_tick();
 | 
				
			||||||
 | 
						if (systick == last_systick) {
 | 
				
			||||||
 | 
							safety_controller_report_error(ERR_FLAG_SYSTICK);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (systick >= 1000) {
 | 
				
			||||||
 | 
							startup_completed = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (startup_completed) {
 | 
				
			||||||
 | 
							amon_state = safety_controller_get_analog_mon_value(ERR_AMON_VREF, &amon_value);
 | 
				
			||||||
 | 
							if (amon_state != ANALOG_MONITOR_OK)
 | 
				
			||||||
 | 
								safety_controller_report_error(ERR_FLAG_AMON_VREF);
 | 
				
			||||||
 | 
							amon_state = safety_controller_get_analog_mon_value(ERR_AMON_UC_TEMP, &amon_value);
 | 
				
			||||||
 | 
							if (amon_state != ANALOG_MONITOR_OK)
 | 
				
			||||||
 | 
								safety_controller_report_error(ERR_FLAG_AMON_UC_TEMP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						safety_controller_process_active_timing_mons();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int safety_controller_report_error(enum safety_flag flag)
 | 
					int safety_controller_report_error(enum safety_flag flag)
 | 
				
			||||||
@@ -156,7 +202,6 @@ int safety_controller_report_error(enum safety_flag flag)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void safety_controller_report_timing(enum timing_monitor monitor)
 | 
					void safety_controller_report_timing(enum timing_monitor monitor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t i;
 | 
					 | 
				
			||||||
	struct timing_mon *tim;
 | 
						struct timing_mon *tim;
 | 
				
			||||||
	uint64_t timestamp;
 | 
						uint64_t timestamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -164,6 +209,12 @@ void safety_controller_report_timing(enum timing_monitor monitor)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	tim = find_timing_mon(monitor);
 | 
						tim = find_timing_mon(monitor);
 | 
				
			||||||
	if (tim) {
 | 
						if (tim) {
 | 
				
			||||||
 | 
							if (tim->enabled) {
 | 
				
			||||||
 | 
								if (!systick_ticks_have_passed(tim->last, tim->min_delta)) {
 | 
				
			||||||
 | 
									safety_controller_report_error(tim->associated_flag);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tim->last = timestamp;
 | 
							tim->last = timestamp;
 | 
				
			||||||
		tim->enabled = true;
 | 
							tim->enabled = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -193,13 +244,65 @@ void safety_controller_init()
 | 
				
			|||||||
	watchdog_setup(WATCHDOG_PRESCALER);
 | 
						watchdog_setup(WATCHDOG_PRESCALER);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void safety_controller_check_stack()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int32_t free_stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free_stack = stack_check_get_free();
 | 
				
			||||||
 | 
						if (free_stack < SAFETY_MIN_STACK_FREE)
 | 
				
			||||||
 | 
							safety_controller_report_error(ERR_FLAG_STACK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void safety_controller_handle_safety_adc()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static enum safety_adc_meas_channel current_channel = SAFETY_ADC_MEAS_TEMP;
 | 
				
			||||||
 | 
						int poll_result;
 | 
				
			||||||
 | 
						uint16_t result;
 | 
				
			||||||
 | 
						float analog_value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						poll_result = safety_adc_poll_result(&result);
 | 
				
			||||||
 | 
						if (poll_result) {
 | 
				
			||||||
 | 
							if (poll_result == -1) {
 | 
				
			||||||
 | 
								switch (current_channel) {
 | 
				
			||||||
 | 
								case SAFETY_ADC_MEAS_TEMP:
 | 
				
			||||||
 | 
									current_channel = SAFETY_ADC_MEAS_VREF;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case SAFETY_ADC_MEAS_VREF:
 | 
				
			||||||
 | 
									/* Expected fallthru */
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									current_channel = SAFETY_ADC_MEAS_TEMP;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								safety_adc_trigger_meas(current_channel);
 | 
				
			||||||
 | 
							} else if (poll_result == 1) {
 | 
				
			||||||
 | 
								analog_value = safety_adc_convert_channel(current_channel, result);
 | 
				
			||||||
 | 
								safety_controller_report_timing(ERR_TIMING_SAFETY_ADC);
 | 
				
			||||||
 | 
								switch (current_channel) {
 | 
				
			||||||
 | 
								case SAFETY_ADC_MEAS_TEMP:
 | 
				
			||||||
 | 
									safety_controller_report_analog_value(ERR_AMON_UC_TEMP, analog_value);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case SAFETY_ADC_MEAS_VREF:
 | 
				
			||||||
 | 
									safety_controller_report_analog_value(ERR_AMON_VREF, analog_value);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									safety_controller_report_error(ERR_FLAG_SAFETY_ADC);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int safety_controller_handle()
 | 
					int safety_controller_handle()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static
 | 
						static
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: Handle safety ADC */
 | 
						safety_controller_check_stack();
 | 
				
			||||||
 | 
						safety_controller_handle_safety_adc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						safety_controller_process_checks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: Check flags for PID and HALT */
 | 
						/* TODO: Check flags for PID and HALT */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -255,4 +358,46 @@ go_out:
 | 
				
			|||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int safety_controller_get_flag(enum safety_flag flag, bool *status, bool try_ack)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct error_flag *found_flag;
 | 
				
			||||||
 | 
						int ret = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!status)
 | 
				
			||||||
 | 
							return -1002;
 | 
				
			||||||
 | 
						if (!is_power_of_two(flag))
 | 
				
			||||||
 | 
							return -1001;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						found_flag = find_error_flag(flag);
 | 
				
			||||||
 | 
						if (found_flag) {
 | 
				
			||||||
 | 
							*status = found_flag->error_state;
 | 
				
			||||||
 | 
							if (try_ack && !found_flag->persistent)
 | 
				
			||||||
 | 
								found_flag->error_state = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int safety_controller_ack_flag(enum safety_flag flag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret = -1;
 | 
				
			||||||
 | 
						struct error_flag *found_flag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!is_power_of_two(flag)) {
 | 
				
			||||||
 | 
							return -1001;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						found_flag = find_error_flag(flag);
 | 
				
			||||||
 | 
						if (found_flag) {
 | 
				
			||||||
 | 
							if (!found_flag->persistent) {
 | 
				
			||||||
 | 
								found_flag->error_state = false;
 | 
				
			||||||
 | 
								ret = 0;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ret = -2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @} */
 | 
					/** @} */
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user