Issue #18: Write init of safety memory
This commit is contained in:
		@@ -30,10 +30,12 @@
 | 
			
		||||
#include <reflow-controller/stack-check.h>
 | 
			
		||||
#include <helper-macros/helper-macros.h>
 | 
			
		||||
#include <reflow-controller/systick.h>
 | 
			
		||||
#include <reflow-controller/safety/fault.h>
 | 
			
		||||
#include <stm32/stm32f4xx.h>
 | 
			
		||||
#include <cmsis/core_cm4.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <reflow-controller/safety/safety-memory.h>
 | 
			
		||||
 | 
			
		||||
struct error_flag {
 | 
			
		||||
	const char *name;
 | 
			
		||||
@@ -248,6 +250,15 @@ void safety_controller_report_analog_value(enum analog_value_monitor monitor, fl
 | 
			
		||||
 | 
			
		||||
void safety_controller_init()
 | 
			
		||||
{
 | 
			
		||||
	enum safety_memory_state found_memory_state;
 | 
			
		||||
 | 
			
		||||
	/* Init the safety memory */
 | 
			
		||||
	if (safety_memory_init(&found_memory_state)) {
 | 
			
		||||
		/* Trigger panic mode! */
 | 
			
		||||
		panic_mode();
 | 
			
		||||
	}
 | 
			
		||||
	if (found_memory_state == SAFETY_MEMORY_INIT_CORRUPTED)
 | 
			
		||||
		safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT);
 | 
			
		||||
 | 
			
		||||
	/* Init default flag states */
 | 
			
		||||
	safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_UNSTABLE,
 | 
			
		||||
 
 | 
			
		||||
@@ -19,4 +19,189 @@
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <reflow-controller/safety/safety-memory.h>
 | 
			
		||||
#include <stm-periph/crc-unit.h>
 | 
			
		||||
#include <stm-periph/backup-ram.h>
 | 
			
		||||
 | 
			
		||||
#define wordsize_of(x) ((sizeof(x) / 4U) / ((sizeof(x) % 4U) ? 0U : 1U))
 | 
			
		||||
 | 
			
		||||
static enum safety_memory_state safety_memory_get_header(struct safety_memory_header *header)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	int res;
 | 
			
		||||
	enum safety_memory_state ret;
 | 
			
		||||
 | 
			
		||||
	if (!header)
 | 
			
		||||
		return SAFETY_MEMORY_INIT_CORRUPTED;
 | 
			
		||||
 | 
			
		||||
	res = backup_ram_get_data(0UL, (uint32_t *)header, wordsize_of(struct safety_memory_header));
 | 
			
		||||
	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 */
 | 
			
		||||
		ret = SAFETY_MEMORY_INIT_FRESH;
 | 
			
		||||
		goto return_val;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res = 0;
 | 
			
		||||
	if (header->boot_status_offset < wordsize_of(struct safety_memory_header))
 | 
			
		||||
		res++;
 | 
			
		||||
	if (header->config_overrides_offset < header->boot_status_offset + wordsize_of(struct safety_memory_boot_status))
 | 
			
		||||
		res++;
 | 
			
		||||
	if (header->config_overrides_len > SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT)
 | 
			
		||||
		res++;
 | 
			
		||||
	if (header->err_memory_offset < header->config_overrides_offset + header->config_overrides_len)
 | 
			
		||||
		res++;
 | 
			
		||||
	if (header->err_memory_end >= backup_ram_get_size_in_words() || header->err_memory_end < header->err_memory_offset)
 | 
			
		||||
		res++;
 | 
			
		||||
 | 
			
		||||
	if (res) {
 | 
			
		||||
		/* Error detected: Write new header */
 | 
			
		||||
		ret = SAFETY_MEMORY_INIT_CORRUPTED;
 | 
			
		||||
	} else {
 | 
			
		||||
		ret = SAFETY_MEMORY_INIT_VALID_MEMORY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
return_val:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void safety_memory_write_new_header(void)
 | 
			
		||||
{
 | 
			
		||||
	struct safety_memory_header header;
 | 
			
		||||
 | 
			
		||||
	header.boot_status_offset = sizeof(struct safety_memory_header);
 | 
			
		||||
	header.config_overrides_offset = header.boot_status_offset + sizeof(struct safety_memory_boot_status)/4;
 | 
			
		||||
	header.err_memory_offset = header.config_overrides_offset + SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT;
 | 
			
		||||
	header.err_memory_end = header.err_memory_offset;
 | 
			
		||||
 | 
			
		||||
	backup_ram_wipe();
 | 
			
		||||
	backup_ram_write_data(0UL, (uint32_t *)&header, wordsize_of(header));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int safety_memory_check_crc()
 | 
			
		||||
{
 | 
			
		||||
	struct safety_memory_header header;
 | 
			
		||||
	enum safety_memory_state state = safety_memory_get_header(&header);
 | 
			
		||||
	uint32_t crc_offset;
 | 
			
		||||
	uint32_t data;
 | 
			
		||||
	uint32_t addr;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	if (state != SAFETY_MEMORY_INIT_VALID_MEMORY)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	crc_offset = header.err_memory_end;
 | 
			
		||||
 | 
			
		||||
	crc_unit_reset();
 | 
			
		||||
 | 
			
		||||
	for (addr = 0; addr < crc_offset; addr++) {
 | 
			
		||||
		res = backup_ram_get_data(addr, &data, 1UL);
 | 
			
		||||
		if (res)
 | 
			
		||||
			return -2000;
 | 
			
		||||
		crc_unit_input(data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res = backup_ram_get_data(crc_offset, &data, 1UL);
 | 
			
		||||
	if (res)
 | 
			
		||||
		return -2001;
 | 
			
		||||
 | 
			
		||||
	if (crc_unit_get_crc() != data)
 | 
			
		||||
		return -3000;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int safety_memory_gen_crc()
 | 
			
		||||
{
 | 
			
		||||
	struct safety_memory_header header;
 | 
			
		||||
	uint32_t word_addr;
 | 
			
		||||
	uint32_t data;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	crc_unit_reset();
 | 
			
		||||
	for (word_addr = 0; word_addr < header.err_memory_end; word_addr++) {
 | 
			
		||||
		res = backup_ram_get_data(word_addr, &data, 1);
 | 
			
		||||
		if (res)
 | 
			
		||||
			return -2;
 | 
			
		||||
		crc_unit_input(data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Write CRC */
 | 
			
		||||
	data = crc_unit_get_crc();
 | 
			
		||||
	res = backup_ram_write_data(header.err_memory_end, &data, 1UL);
 | 
			
		||||
	if (res)
 | 
			
		||||
		return -3;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int safety_memory_init(enum safety_memory_state *found_state)
 | 
			
		||||
{
 | 
			
		||||
	struct safety_memory_header header;
 | 
			
		||||
	int res;
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
 | 
			
		||||
	if (!found_state)
 | 
			
		||||
		return -1001;
 | 
			
		||||
 | 
			
		||||
	crc_unit_init();
 | 
			
		||||
	backup_ram_init(true);
 | 
			
		||||
 | 
			
		||||
	*found_state = safety_memory_get_header(&header);
 | 
			
		||||
 | 
			
		||||
	switch (*found_state) {
 | 
			
		||||
	case SAFETY_MEMORY_INIT_VALID_MEMORY:
 | 
			
		||||
		/* Valid memory detected. Check CRC */
 | 
			
		||||
		res = safety_memory_check_crc();
 | 
			
		||||
		if (res)
 | 
			
		||||
			*found_state = SAFETY_MEMORY_INIT_CORRUPTED;
 | 
			
		||||
		break;
 | 
			
		||||
	case SAFETY_MEMORY_INIT_FRESH:
 | 
			
		||||
		safety_memory_write_new_header();
 | 
			
		||||
		break;
 | 
			
		||||
	case SAFETY_MEMORY_INIT_CORRUPTED:
 | 
			
		||||
	default:
 | 
			
		||||
		*found_state = SAFETY_MEMORY_INIT_CORRUPTED;
 | 
			
		||||
		safety_memory_write_new_header();
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check if memory header was written newly */
 | 
			
		||||
	if (*found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) {
 | 
			
		||||
		/* If yes, generate new CRC checksum */
 | 
			
		||||
		res = safety_memory_gen_crc();
 | 
			
		||||
		if (res)
 | 
			
		||||
			ret = -100;
 | 
			
		||||
		else
 | 
			
		||||
			ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int safety_memory_get_boot_status(struct safety_memory_boot_status *status);
 | 
			
		||||
 | 
			
		||||
int safety_memory_get_error_entry_count(uint32_t *count);
 | 
			
		||||
 | 
			
		||||
int safety_memory_check(void)
 | 
			
		||||
{
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	res = safety_memory_check_crc();
 | 
			
		||||
	return -!!res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int safety_memory_get_error_entry(uint32_t idx, struct error_memory_entry *entry);
 | 
			
		||||
 | 
			
		||||
int safety_memory_insert_error_entry(struct error_memory_entry *entry);
 | 
			
		||||
 | 
			
		||||
int safety_memory_insert_config_override(struct config_override *config_override);
 | 
			
		||||
 | 
			
		||||
int safety_memory_get_config_override_count(uint32_t *count);
 | 
			
		||||
 | 
			
		||||
int safety_memory_get_config_override(uint32_t idx, struct config_override *config_override);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user