Further rewrite safety handling
This commit is contained in:
		@@ -28,24 +28,10 @@
 | 
			
		||||
#include <helper-macros/helper-macros.h>
 | 
			
		||||
#include <stm-periph/clock-enable-manager.h>
 | 
			
		||||
 | 
			
		||||
enum safety_adc_check_result global_safety_adc_status;
 | 
			
		||||
 | 
			
		||||
enum safety_adc_check_result safety_adc_get_errors()
 | 
			
		||||
{
 | 
			
		||||
	return global_safety_adc_status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void safety_adc_clear_errors(void)
 | 
			
		||||
{
 | 
			
		||||
	global_safety_adc_status = SAFETY_ADC_CHECK_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void safety_adc_init()
 | 
			
		||||
{
 | 
			
		||||
	rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
 | 
			
		||||
 | 
			
		||||
	safety_adc_clear_errors();
 | 
			
		||||
 | 
			
		||||
	/* Enable temperature and VREFINT measurement */
 | 
			
		||||
	ADC->CCR |= ADC_CCR_TSVREFE;
 | 
			
		||||
 | 
			
		||||
@@ -65,38 +51,27 @@ void safety_adc_deinit()
 | 
			
		||||
	rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum safety_adc_check_result safety_adc_check_results(uint16_t vref_result, uint16_t temp_result,
 | 
			
		||||
						      float *vref_calculated, float *temp_calculated)
 | 
			
		||||
float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value)
 | 
			
		||||
{
 | 
			
		||||
	enum safety_adc_check_result res = SAFETY_ADC_CHECK_OK;
 | 
			
		||||
	float vref;
 | 
			
		||||
	float temp;
 | 
			
		||||
	float converted_val;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	vref = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)vref_result;
 | 
			
		||||
	if (vref_calculated) {
 | 
			
		||||
		*vref_calculated = vref;
 | 
			
		||||
 | 
			
		||||
	switch (channel) {
 | 
			
		||||
	case SAFETY_ADC_MEAS_TEMP:
 | 
			
		||||
		converted_val = (((float)channel / 4095.0f * 2500.0f - SAFETY_ADC_TEMP_NOM_MV) /
 | 
			
		||||
				 SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM;
 | 
			
		||||
		break;
 | 
			
		||||
	case SAFETY_ADC_MEAS_VREF:
 | 
			
		||||
		converted_val = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)analog_value;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		/* Generate NaN value as default return */
 | 
			
		||||
		converted_val = 0.0f / 0.0f;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	temp = (((float)temp_result / 4095.0f * 2500.0f -
 | 
			
		||||
			     SAFETY_ADC_TEMP_NOM_MV) / SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM;
 | 
			
		||||
	if (temp_calculated) {
 | 
			
		||||
		*temp_calculated = temp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ABS(vref - SAFETY_ADC_VREF_MVOLT) > SAFETY_ADC_VREF_TOL_MVOLT) {
 | 
			
		||||
		if (vref > SAFETY_ADC_VREF_MVOLT)
 | 
			
		||||
			res |= SAFETY_ADC_CHECK_VREF_HIGH;
 | 
			
		||||
		else
 | 
			
		||||
			res |= SAFETY_ADC_CHECK_VREF_LOW;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (temp < SAFETY_ADC_TEMP_LOW_LIM)
 | 
			
		||||
		res |= SAFETY_ADC_CHECK_TEMP_LOW;
 | 
			
		||||
	else if (temp < SAFETY_ADC_CHECK_TEMP_HIGH)
 | 
			
		||||
		res |= SAFETY_ADC_CHECK_TEMP_HIGH;
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
	return converted_val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int safety_adc_poll_result(uint16_t *adc_result)
 | 
			
		||||
@@ -136,60 +111,5 @@ void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement)
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_SWSTART;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint16_t safety_vref_meas_raw;
 | 
			
		||||
static bool safety_vref_valid = false;
 | 
			
		||||
static uint16_t safety_temp_meas_raw;
 | 
			
		||||
static bool safety_temp_valid = false;
 | 
			
		||||
static float safety_vref;
 | 
			
		||||
static float safety_temp;
 | 
			
		||||
 | 
			
		||||
enum safety_adc_check_result handle_safety_adc()
 | 
			
		||||
{
 | 
			
		||||
	static enum safety_adc_meas_channel safety_meas_channel = SAFETY_ADC_MEAS_VREF;
 | 
			
		||||
	enum safety_adc_check_result check_result;
 | 
			
		||||
	uint16_t result;
 | 
			
		||||
	int poll_status;
 | 
			
		||||
 | 
			
		||||
	poll_status = safety_adc_poll_result(&result);
 | 
			
		||||
 | 
			
		||||
	if (poll_status < 0) {
 | 
			
		||||
		safety_adc_trigger_meas(safety_meas_channel);
 | 
			
		||||
	} else if (poll_status > 0) {
 | 
			
		||||
		switch (safety_meas_channel) {
 | 
			
		||||
		case SAFETY_ADC_MEAS_TEMP:
 | 
			
		||||
			safety_temp_meas_raw = result;
 | 
			
		||||
			safety_temp_valid = true;
 | 
			
		||||
			safety_meas_channel = SAFETY_ADC_MEAS_VREF;
 | 
			
		||||
			break;
 | 
			
		||||
		case SAFETY_ADC_MEAS_VREF:
 | 
			
		||||
			safety_vref_meas_raw = result;
 | 
			
		||||
			safety_vref_valid = true;
 | 
			
		||||
			safety_meas_channel = SAFETY_ADC_MEAS_TEMP;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			safety_meas_channel = SAFETY_ADC_MEAS_VREF;
 | 
			
		||||
			return SAFETY_ADC_INTERNAL_ERROR;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (safety_temp_valid && safety_vref_valid) {
 | 
			
		||||
		check_result = safety_adc_check_results(safety_vref_meas_raw, safety_temp_meas_raw, &safety_vref, &safety_temp);
 | 
			
		||||
		global_safety_adc_status |= check_result;
 | 
			
		||||
	} else {
 | 
			
		||||
		check_result = SAFETY_ADC_CHECK_OK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return check_result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float safety_adc_get_temp()
 | 
			
		||||
{
 | 
			
		||||
	return safety_temp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float safety_adc_get_vref()
 | 
			
		||||
{
 | 
			
		||||
	return safety_vref;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,8 @@
 | 
			
		||||
#include <reflow-controller/safety/safety-controller.h>
 | 
			
		||||
#include <reflow-controller/safety/safety-config.h>
 | 
			
		||||
#include <reflow-controller/safety/watchdog.h>
 | 
			
		||||
#include <reflow-controller/safety/safety-adc.h>
 | 
			
		||||
#include <helper-macros/helper-macros.h>
 | 
			
		||||
#include <reflow-controller/systick.h>
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
@@ -42,6 +44,7 @@ struct error_flag {
 | 
			
		||||
struct timing_mon {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	enum timing_monitor monitor;
 | 
			
		||||
	enum safety_flag associated_flag;
 | 
			
		||||
	uint64_t min_delta;
 | 
			
		||||
	uint64_t max_delta;
 | 
			
		||||
	uint64_t last;
 | 
			
		||||
@@ -51,6 +54,7 @@ struct timing_mon {
 | 
			
		||||
struct analog_mon {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	enum analog_value_monitor monitor;
 | 
			
		||||
	enum safety_flag associated_flag;
 | 
			
		||||
	float min;
 | 
			
		||||
	float max;
 | 
			
		||||
	float value;
 | 
			
		||||
@@ -64,8 +68,8 @@ struct analog_mon {
 | 
			
		||||
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
 | 
			
		||||
 | 
			
		||||
#define ERR_FLAG_ENTRY(errflag, persistency) {.name=#errflag, .flag = (errflag), .error_state = false, .persistent = (persistency)}
 | 
			
		||||
#define TIM_MON_ENTRY(mon, min, max) {.name=#mon, .monitor = (mon), .min_delta = (min), .max_delta = (max), .last = 0ULL, .enabled= false}
 | 
			
		||||
#define ANA_MON_ENTRY(mon, min_value, max_value) {.name=#mon, .monitor = (mon), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = 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}
 | 
			
		||||
 | 
			
		||||
static struct error_flag flags[] = {
 | 
			
		||||
	ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false),
 | 
			
		||||
@@ -80,16 +84,59 @@ static struct error_flag flags[] = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct timing_mon timings[] = {
 | 
			
		||||
	TIM_MON_ENTRY(ERR_TIMING_PID, 1, 800),
 | 
			
		||||
	TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 1, 50),
 | 
			
		||||
	TIM_MON_ENTRY(ERR_TIMING_SAFETY_ADC, 220, 500),
 | 
			
		||||
	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),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct analog_mon analog_mons[] = {
 | 
			
		||||
	ANA_MON_ENTRY(ERR_AMON_VREF, 2480.0f, 2520.0f),
 | 
			
		||||
	ANA_MON_ENTRY(ERR_AMON_UC_TEMP, 0.0f, 55.0f),
 | 
			
		||||
	ANA_MON_ENTRY(ERR_AMON_VREF, 2480.0f, 2520.0f, ERR_FLAG_AMON_VREF),
 | 
			
		||||
	ANA_MON_ENTRY(ERR_AMON_UC_TEMP, 0.0f, 55.0f, ERR_FLAG_AMON_UC_TEMP),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct analog_mon *find_analog_mon(enum analog_value_monitor mon)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
	struct analog_mon *ret = NULL;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < COUNT_OF(analog_mons); i++) {
 | 
			
		||||
		if (analog_mons[i].monitor == mon)
 | 
			
		||||
			ret = &analog_mons[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct timing_mon *find_timing_mon(enum timing_monitor mon)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
	struct timing_mon *ret = NULL;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < COUNT_OF(timings); i++) {
 | 
			
		||||
		if (timings[i].monitor == mon)
 | 
			
		||||
			ret = &timings[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct error_flag *find_error_flag(enum safety_flag flag)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
	struct error_flag *ret = NULL;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < COUNT_OF(flags); i++) {
 | 
			
		||||
		if (flags[i].flag == flag)
 | 
			
		||||
			ret = &flags[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void safety_controller_process_checks()
 | 
			
		||||
{
 | 
			
		||||
	// TODO: Implement
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int safety_controller_report_error(enum safety_flag flag)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
@@ -102,11 +149,11 @@ int safety_controller_report_error(enum safety_flag flag)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	safety_controller_process_checks();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
void safety_controller_report_timing(enum timing_monitor monitor)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
@@ -115,22 +162,41 @@ void safety_controller_report_timing(enum timing_monitor monitor)
 | 
			
		||||
 | 
			
		||||
	timestamp = systick_get_global_tick();
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < COUNT_OF(timings); i++) {
 | 
			
		||||
		tim = &timings[i];
 | 
			
		||||
		if (tim->monitor & monitor) {
 | 
			
		||||
			tim->enabled = true;
 | 
			
		||||
			tim->last = timestamp;
 | 
			
		||||
		}
 | 
			
		||||
	tim = find_timing_mon(monitor);
 | 
			
		||||
	if (tim) {
 | 
			
		||||
		tim->last = timestamp;
 | 
			
		||||
		tim->enabled = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	safety_controller_process_checks();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void safety_controller_report_analog_value(enum analog_value_monitor monitor, float value)
 | 
			
		||||
{
 | 
			
		||||
	struct analog_mon *ana;
 | 
			
		||||
 | 
			
		||||
	/* Return if not a power of two */
 | 
			
		||||
	if (!is_power_of_two(monitor))
 | 
			
		||||
		return;
 | 
			
		||||
	ana = find_analog_mon(monitor);
 | 
			
		||||
	if (ana) {
 | 
			
		||||
		ana->valid = true;
 | 
			
		||||
		ana->value = value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	safety_controller_process_checks();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void safety_controller_init()
 | 
			
		||||
{
 | 
			
		||||
	safety_adc_init();
 | 
			
		||||
	watchdog_setup(WATCHDOG_PRESCALER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int safety_controller_handle()
 | 
			
		||||
{
 | 
			
		||||
	static
 | 
			
		||||
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	/* TODO: Handle safety ADC */
 | 
			
		||||
@@ -144,19 +210,49 @@ int safety_controller_handle()
 | 
			
		||||
 | 
			
		||||
int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
	struct timing_mon *tim;
 | 
			
		||||
 | 
			
		||||
	if (enable) {
 | 
			
		||||
		safety_controller_report_timing(monitor);
 | 
			
		||||
	} else {
 | 
			
		||||
		for (i = 0; i < COUNT_OF(timings); i++) {
 | 
			
		||||
			tim = &timings[i];
 | 
			
		||||
			if (tim->monitor & monitor) {
 | 
			
		||||
				tim->enabled = false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		tim = find_timing_mon(monitor);
 | 
			
		||||
		if (!tim)
 | 
			
		||||
			return -1;
 | 
			
		||||
		tim->enabled = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum analog_monitor_status safety_controller_get_analog_mon_value(enum analog_value_monitor monitor, float *value)
 | 
			
		||||
{
 | 
			
		||||
	struct analog_mon *mon;
 | 
			
		||||
	int ret = ANALOG_MONITOR_ERROR;
 | 
			
		||||
 | 
			
		||||
	if (!is_power_of_two(monitor))
 | 
			
		||||
		goto go_out;
 | 
			
		||||
 | 
			
		||||
	if (!value)
 | 
			
		||||
		goto go_out;
 | 
			
		||||
 | 
			
		||||
	mon = find_analog_mon(monitor);
 | 
			
		||||
	if (mon) {
 | 
			
		||||
		if (!mon->valid) {
 | 
			
		||||
			ret = ANALOG_MONITOR_INACTIVE;
 | 
			
		||||
			goto go_out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		*value = mon->value;
 | 
			
		||||
		if (mon->value < mon->min)
 | 
			
		||||
			ret = ANALOG_MONITOR_UNDER;
 | 
			
		||||
		else if (mon->value > mon->max)
 | 
			
		||||
			ret = ANALOG_MONITOR_OVER;
 | 
			
		||||
		else
 | 
			
		||||
			ret = ANALOG_MONITOR_OK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
go_out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user