/* Reflow Oven Controller * * Copyright (C) 2020 Mario Hüttel * * This file is part of the Reflow Oven Controller Project. * * The reflow oven controller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the reflow oven controller project. * If not, see . */ /** * @addtogroup safety-controller * @{ */ #include #include #include #include #include #include #include struct error_flag { const char *name; enum safety_flag flag; bool error_state; bool persistent; }; struct timing_mon { const char *name; enum timing_monitor monitor; uint64_t min_delta; uint64_t max_delta; uint64_t last; bool enabled; }; struct analog_mon { const char *name; enum analog_value_monitor monitor; float min; float max; float value; bool valid; }; #ifdef COUNT_OF #undef COUNT_OF #endif #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} static struct error_flag flags[] = { ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, false), ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OVERFLOW, true), ERR_FLAG_ENTRY(ERR_FLAG_TIMING_MEAS_ADC, false), ERR_FLAG_ENTRY(ERR_FLAG_TIMING_PID, false), ERR_FLAG_ENTRY(ERR_FLAG_AMON_UC_TEMP, true), ERR_FLAG_ENTRY(ERR_FLAG_AMON_VREF, false), ERR_FLAG_ENTRY(ERR_FLAG_STACK, true), }; 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), }; 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), }; int safety_controller_report_error(enum safety_flag flag) { uint32_t i; int ret = -1; for (i = 0; i < COUNT_OF(flags); i++) { if (flags[i].flag & flag) { flags[i].error_state = true; ret = 0; } } return ret; } /** @} */ void safety_controller_report_timing(enum timing_monitor monitor) { uint32_t i; struct timing_mon *tim; uint64_t timestamp; 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; } } } void safety_controller_init() { watchdog_setup(WATCHDOG_PRESCALER); } int safety_controller_handle() { int ret = 0; /* TODO: Handle safety ADC */ /* TODO: Check flags for PID and HALT */ ret |= watchdog_ack(WATCHDOG_MAGIC_KEY); return (ret ? -1 : 0); } 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; } } } return 0; }