From 8205253b5a38740dcae455d2b61097b7b38846e6f50781adc5335720ff0b3f7e Mon Sep 17 00:00:00 2001 From: localhorst Date: Fri, 13 Dec 2024 19:26:16 +0100 Subject: [PATCH] safety state and input error detection --- .vscode/settings.json | 7 +- main/inputs.c | 218 ++++++++++++++++-------------------------- main/inputs.h | 37 +++++-- main/metrics.c | 45 ++++++--- main/safety.c | 102 +++++++++++++------- main/safety.h | 23 ++++- 6 files changed, 236 insertions(+), 196 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 29ec818..884c37d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,7 +12,12 @@ "inputs.h": "c", "cstdlib": "c", "typeinfo": "c", - "limits": "c" + "limits": "c", + "bit": "c", + "type_traits": "c", + "cmath": "c", + "*.tcc": "c", + "*.inc": "c" }, "idf.openOcdConfigs": [ "board/esp32-wrover-kit-3.3v.cfg" diff --git a/main/inputs.c b/main/inputs.c index c0c7ecc..d792219 100644 --- a/main/inputs.c +++ b/main/inputs.c @@ -6,27 +6,8 @@ #include "inputs.h" -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - #define MAX_DN18B20_SENSORS 4U #define PERIODIC_INTERVAL 1U // read and compute the inputs every 1sec -#define AVG10_SAMPLE_SIZE 10U -#define AVG60_SAMPLE_SIZE 60U - -typedef struct _Average -{ - float value; - float samples[MAX(AVG10_SAMPLE_SIZE, AVG60_SAMPLE_SIZE)]; - size_t bufferIndex; - size_t bufferCount; -} sAverage; - -typedef struct _Measurement -{ - float value; - sAverage average10s; - sAverage average60s; -} sMeasurement; static const char *TAG = "smart-oil-heater-control-system-inputs"; const uint8_t uBurnerFaultPin = 19U; @@ -43,10 +24,10 @@ size_t sSensorCount = 0U; static SemaphoreHandle_t xMutexAccessInputs = NULL; static eBurnerErrorState sBurnerErrorState; -static sMeasurement fChamperTemperature; -static sMeasurement fOutdoorTemperature; -static sMeasurement fInletFlowTemperature; -static sMeasurement fReturnFlowTemperature; +static sMeasurement sChamperTemperature; +static sMeasurement sOutdoorTemperature; +static sMeasurement sInletFlowTemperature; +static sMeasurement sReturnFlowTemperature; void taskInput(void *pvParameters); void updateAverage(sMeasurement *pMeasurement); @@ -92,7 +73,7 @@ void initInputs(void) void updateAverage(sMeasurement *pMeasurement) { /* Average form the last 10sec */ - pMeasurement->average10s.samples[pMeasurement->average10s.bufferIndex] = pMeasurement->value; + pMeasurement->average10s.samples[pMeasurement->average10s.bufferIndex] = pMeasurement->fCurrentValue; pMeasurement->average10s.bufferIndex = (pMeasurement->average10s.bufferIndex + 1) % AVG10_SAMPLE_SIZE; if (pMeasurement->average10s.bufferCount < AVG10_SAMPLE_SIZE) @@ -102,7 +83,7 @@ void updateAverage(sMeasurement *pMeasurement) if (pMeasurement->average10s.bufferCount == 0U) { - pMeasurement->average10s.value = pMeasurement->value; + pMeasurement->average10s.fValue = pMeasurement->fCurrentValue; } float sum = 0.0; @@ -111,10 +92,10 @@ void updateAverage(sMeasurement *pMeasurement) sum += pMeasurement->average10s.samples[i]; } - pMeasurement->average10s.value = sum / pMeasurement->average10s.bufferCount; + pMeasurement->average10s.fValue = sum / pMeasurement->average10s.bufferCount; /* Average form the last 60sec */ - pMeasurement->average60s.samples[pMeasurement->average60s.bufferIndex] = pMeasurement->value; + pMeasurement->average60s.samples[pMeasurement->average60s.bufferIndex] = pMeasurement->fCurrentValue; pMeasurement->average60s.bufferIndex = (pMeasurement->average60s.bufferIndex + 1) % AVG60_SAMPLE_SIZE; if (pMeasurement->average60s.bufferCount < AVG60_SAMPLE_SIZE) @@ -124,7 +105,7 @@ void updateAverage(sMeasurement *pMeasurement) if (pMeasurement->average60s.bufferCount == 0U) { - pMeasurement->average60s.value = pMeasurement->value; + pMeasurement->average60s.fValue = pMeasurement->fCurrentValue; } sum = 0.0; @@ -133,7 +114,7 @@ void updateAverage(sMeasurement *pMeasurement) sum += pMeasurement->average60s.samples[i]; } - pMeasurement->average60s.value = sum / pMeasurement->average60s.bufferCount; + pMeasurement->average60s.fValue = sum / pMeasurement->average60s.bufferCount; } void taskInput(void *pvParameters) @@ -141,168 +122,133 @@ void taskInput(void *pvParameters) while (1) { vTaskDelay(PERIODIC_INTERVAL * 1000U / portTICK_PERIOD_MS); + if (xSemaphoreTake(xMutexAccessInputs, portMAX_DELAY) == pdTRUE) + { + sChamperTemperature.state = MEASUREMENT_FAULT; + sOutdoorTemperature.state = MEASUREMENT_FAULT; + sInletFlowTemperature.state = MEASUREMENT_FAULT; + sReturnFlowTemperature.state = MEASUREMENT_FAULT; - if (gpio_get_level(uBurnerFaultPin) == 1) - { - sBurnerErrorState = FAULT; - } - else - { - sBurnerErrorState = NO_ERROR; - } - - if (ds18x20_scan_devices(uDS18B20Pin, uOneWireAddresses, MAX_DN18B20_SENSORS, &sSensorCount) != ESP_OK) - { - ESP_LOGE(TAG, "1-Wire device scan error!"); - } - - if (!sSensorCount) - { - ESP_LOGW(TAG, "No 1-Wire devices detected!"); - } - else - { - ESP_LOGI(TAG, "%d 1-Wire devices detected", sSensorCount); - - if (sSensorCount > MAX_DN18B20_SENSORS) + if (gpio_get_level(uBurnerFaultPin) == 1) { - sSensorCount = MAX_DN18B20_SENSORS; - ESP_LOGW(TAG, "More 1-Wire devices found than expected!"); - } - - if (ds18x20_measure_and_read_multi(uDS18B20Pin, uOneWireAddresses, sSensorCount, fDS18B20Temps) != ESP_OK) - { - ESP_LOGE(TAG, "1-Wire devices read error"); + sBurnerErrorState = FAULT; } else { - for (int j = 0; j < sSensorCount; j++) + sBurnerErrorState = NO_ERROR; + } + + if (ds18x20_scan_devices(uDS18B20Pin, uOneWireAddresses, MAX_DN18B20_SENSORS, &sSensorCount) != ESP_OK) + { + ESP_LOGE(TAG, "1-Wire device scan error!"); + } + + if (!sSensorCount) + { + ESP_LOGW(TAG, "No 1-Wire devices detected!"); + } + else + { + ESP_LOGI(TAG, "%d 1-Wire devices detected", sSensorCount); + + if (sSensorCount > MAX_DN18B20_SENSORS) { - float temp_c = fDS18B20Temps[j]; - ESP_LOGI(TAG, "Sensor: %08" PRIx64 " reports %lf°C", (uint64_t)uOneWireAddresses[j], temp_c); - if (xSemaphoreTake(xMutexAccessInputs, portMAX_DELAY) == pdTRUE) + sSensorCount = MAX_DN18B20_SENSORS; + ESP_LOGW(TAG, "More 1-Wire devices found than expected!"); + } + + if (ds18x20_measure_and_read_multi(uDS18B20Pin, uOneWireAddresses, sSensorCount, fDS18B20Temps) != ESP_OK) + { + ESP_LOGE(TAG, "1-Wire devices read error"); + } + else + { + for (int j = 0; j < sSensorCount; j++) { + float temp_c = fDS18B20Temps[j]; + ESP_LOGI(TAG, "Sensor: %08" PRIx64 " reports %lf°C", (uint64_t)uOneWireAddresses[j], temp_c); + switch ((uint64_t)uOneWireAddresses[j]) { case ((uint64_t)uChamperTempSensorAddr): - fChamperTemperature.value = temp_c; - updateAverage(&fChamperTemperature); + sChamperTemperature.fCurrentValue = temp_c; + sChamperTemperature.state = MEASUREMENT_NO_ERROR; + updateAverage(&sChamperTemperature); break; case ((uint64_t)uOutdoorTempSensorAddr): - fOutdoorTemperature.value = temp_c; - updateAverage(&fOutdoorTemperature); + sOutdoorTemperature.fCurrentValue = temp_c; + sOutdoorTemperature.state = MEASUREMENT_NO_ERROR; + updateAverage(&sOutdoorTemperature); break; case ((uint64_t)uInletFlowTempSensorAddr): - fInletFlowTemperature.value = temp_c; - updateAverage(&fInletFlowTemperature); + sInletFlowTemperature.fCurrentValue = temp_c; + sInletFlowTemperature.state = MEASUREMENT_NO_ERROR; + updateAverage(&sInletFlowTemperature); break; case ((uint64_t)uReturnFlowTempSensorAddr): - fReturnFlowTemperature.value = temp_c; - updateAverage(&fReturnFlowTemperature); + sReturnFlowTemperature.fCurrentValue = temp_c; + sReturnFlowTemperature.state = MEASUREMENT_NO_ERROR; + updateAverage(&sReturnFlowTemperature); break; default: break; } - xSemaphoreGive(xMutexAccessInputs); } } } + xSemaphoreGive(xMutexAccessInputs); } } } -float getChamberTemperature(eMeasurementMode mode) +sMeasurement getChamberTemperature(void) { - float ret = 0.0f; + sMeasurement ret; + ret.state = MEASUREMENT_FAULT; if (xSemaphoreTake(xMutexAccessInputs, portMAX_DELAY) == pdTRUE) { - switch (mode) - { - case CURRENT: - ret = fChamperTemperature.value; - break; - case AVERAGE_10S: - ret = fChamperTemperature.average10s.value; - break; - case AVERAGE_60S: - ret = fChamperTemperature.average60s.value; - break; - default: - break; - } + ret = sChamperTemperature; xSemaphoreGive(xMutexAccessInputs); } return ret; } -float getOutdoorTemperature(eMeasurementMode mode) + +sMeasurement getOutdoorTemperature(void) { - float ret = 0.0f; + sMeasurement ret; + ret.state = MEASUREMENT_FAULT; if (xSemaphoreTake(xMutexAccessInputs, portMAX_DELAY) == pdTRUE) { - switch (mode) - { - case CURRENT: - ret = fOutdoorTemperature.value; - break; - case AVERAGE_10S: - ret = fOutdoorTemperature.average10s.value; - break; - case AVERAGE_60S: - ret = fOutdoorTemperature.average60s.value; - break; - default: - break; - } + ret = sOutdoorTemperature; xSemaphoreGive(xMutexAccessInputs); } return ret; } -float getInletFlowTemperature(eMeasurementMode mode) + +sMeasurement getInletFlowTemperature(void) { - float ret = 0.0f; + sMeasurement ret; + ret.state = MEASUREMENT_FAULT; if (xSemaphoreTake(xMutexAccessInputs, portMAX_DELAY) == pdTRUE) { - switch (mode) - { - case CURRENT: - ret = fInletFlowTemperature.value; - break; - case AVERAGE_10S: - ret = fInletFlowTemperature.average10s.value; - break; - case AVERAGE_60S: - ret = fInletFlowTemperature.average60s.value; - break; - default: - break; - } + ret = sInletFlowTemperature; xSemaphoreGive(xMutexAccessInputs); } return ret; } -float getReturnFlowTemperature(eMeasurementMode mode) + +sMeasurement getReturnFlowTemperature(void) { - float ret = 0.0f; + sMeasurement ret; + ret.state = MEASUREMENT_FAULT; if (xSemaphoreTake(xMutexAccessInputs, portMAX_DELAY) == pdTRUE) { - switch (mode) - { - case CURRENT: - ret = fReturnFlowTemperature.value; - break; - case AVERAGE_10S: - ret = fReturnFlowTemperature.average10s.value; - break; - case AVERAGE_60S: - ret = fReturnFlowTemperature.average60s.value; - break; - default: - break; - } + ret = sReturnFlowTemperature; xSemaphoreGive(xMutexAccessInputs); } return ret; } + eBurnerErrorState getBurnerError(void) { eBurnerErrorState ret = FAULT; diff --git a/main/inputs.h b/main/inputs.h index 0307ffe..2630507 100644 --- a/main/inputs.h +++ b/main/inputs.h @@ -1,21 +1,40 @@ #pragma once +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define AVG10_SAMPLE_SIZE 10U +#define AVG60_SAMPLE_SIZE 60U + typedef enum _BurnerErrorState { NO_ERROR, FAULT } eBurnerErrorState; -typedef enum _MeasurementMode +typedef enum _MeasurementErrorState { - CURRENT, - AVERAGE_10S, - AVERAGE_60S -} eMeasurementMode; + MEASUREMENT_NO_ERROR, + MEASUREMENT_FAULT +} eMeasurementErrorState; + +typedef struct _Average +{ + float fValue; + float samples[MAX(AVG10_SAMPLE_SIZE, AVG60_SAMPLE_SIZE)]; + size_t bufferIndex; + size_t bufferCount; +} sAverage; + +typedef struct _Measurement +{ + float fCurrentValue; + sAverage average10s; + sAverage average60s; + eMeasurementErrorState state; +} sMeasurement; void initInputs(void); -float getChamberTemperature(eMeasurementMode mode); -float getOutdoorTemperature(eMeasurementMode mode); -float getInletFlowTemperature(eMeasurementMode mode); -float getReturnFlowTemperature(eMeasurementMode mode); +sMeasurement getChamberTemperature(void); +sMeasurement getOutdoorTemperature(void); +sMeasurement getInletFlowTemperature(void); +sMeasurement getReturnFlowTemperature(void); eBurnerErrorState getBurnerError(void); \ No newline at end of file diff --git a/main/metrics.c b/main/metrics.c index e0f8bfd..4b8b201 100644 --- a/main/metrics.c +++ b/main/metrics.c @@ -19,6 +19,7 @@ #include "metrics.h" #include "outputs.h" #include "inputs.h" +#include "safety.h" static EventGroupHandle_t s_wifi_event_group; @@ -42,7 +43,7 @@ void initMetrics(void) BaseType_t taskCreated = xTaskCreate( taskMetrics, // Function to implement the task "taskMetrics", // Task name - 4096, // Stack size (in words, not bytes) + 16384, // Stack size (in words, not bytes) NULL, // Parameters to the task function (none in this case) 5, // Task priority (higher number = higher priority) NULL // Task handle (optional) @@ -123,62 +124,78 @@ void taskMetrics(void *pvParameters) /*Chamber Temperature*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature"); - aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature(CURRENT); + aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().fCurrentValue; u16MetricCounter++; /*Outdoor Temperature*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature"); - aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature(CURRENT); + aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().fCurrentValue; u16MetricCounter++; /*Chamber Temperature*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature"); - aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature(CURRENT); + aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().fCurrentValue; u16MetricCounter++; /*Chamber Temperature*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature"); - aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature(CURRENT); + aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().fCurrentValue; u16MetricCounter++; /*Chamber Temperature Average 10s*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_avg10"); - aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature(AVERAGE_10S); + aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average10s.fValue; u16MetricCounter++; /*Outdoor Temperature Average 10s*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_avg10"); - aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature(AVERAGE_10S); + aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average10s.fValue; u16MetricCounter++; /*Chamber Temperature Average 10s*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg10"); - aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature(AVERAGE_10S); + aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average10s.fValue; u16MetricCounter++; /*Chamber Temperature Average 10s*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_avg10"); - aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature(AVERAGE_10S); + aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average10s.fValue; u16MetricCounter++; - /*Chamber Temperature Average 60s*/ + /*Chamber Temperature Average 60s*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_avg60"); - aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature(AVERAGE_60S); + aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average60s.fValue; u16MetricCounter++; /*Outdoor Temperature Average 60s*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_avg60"); - aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature(AVERAGE_60S); + aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average60s.fValue; u16MetricCounter++; /*Chamber Temperature Average 60s*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg60"); - aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature(AVERAGE_60S); + aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average60s.fValue; u16MetricCounter++; /*Chamber Temperature Average 60s*/ strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_avg60"); - aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature(AVERAGE_60S); + aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average60s.fValue; + u16MetricCounter++; + + /*Sensor status*/ + sSensorSanityCheck aChecks[NUMBER_OF_SENSOR_SANITY_CHECKS]; + getSensorSanityStates(aChecks); + for (size_t i = 0; i < NUMBER_OF_SENSOR_SANITY_CHECKS; i++) + { + strcpy(aMetrics[u16MetricCounter].caMetricName, aChecks[i].name); + strcat(aMetrics[u16MetricCounter].caMetricName, "_status"); + aMetrics[u16MetricCounter].fMetricValue = aChecks[i].status; + u16MetricCounter++; + } + + /*Safety state*/ + strcpy(aMetrics[u16MetricCounter].caMetricName, "safety_state"); + aMetrics[u16MetricCounter].fMetricValue = getSafetyState(); u16MetricCounter++; vSetMetrics(aMetrics, u16MetricCounter); diff --git a/main/safety.c b/main/safety.c index f0f0f87..5925326 100644 --- a/main/safety.c +++ b/main/safety.c @@ -1,6 +1,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" +#include #include "safety.h" #define PERIODIC_INTERVAL 1U // run safety checks every 1sec @@ -8,11 +9,12 @@ static const char *TAG = "smart-oil-heater-control-system-safety"; static SemaphoreHandle_t xMutexAccessSafety = NULL; -sSensorSanityCheck sanityChecks[NUMBER_OF_SENSOR_SANITY_CHECKS] = { - {0U, "chamber_temperature", {95.0f, -10.0f}, 0.0f, 0U, getChamberTemperature}, - {0U, "outdoor_temperature", {45.0f, -20.0f}, 0.0f, 0U, getOutdoorTemperature}, - {0U, "inlet_flow_temperature", {95.0f, -10.0f}, 0.0f, 0U, getInletFlowTemperature}, - {0U, "return_flow_temperature", {95.0f, -10.0f}, 0.0f, 0U, getReturnFlowTemperature}}; +static sSensorSanityCheck sanityChecks[NUMBER_OF_SENSOR_SANITY_CHECKS] = { + {SENSOR_NO_ERROR, "chamber_temperature", {95.0f, -10.0f}, 0.0f, 0U, getChamberTemperature}, + {SENSOR_NO_ERROR, "outdoor_temperature", {45.0f, -20.0f}, 0.0f, 0U, getOutdoorTemperature}, + {SENSOR_NO_ERROR, "inlet_flow_temperature", {95.0f, -10.0f}, 0.0f, 0U, getInletFlowTemperature}, + {SENSOR_NO_ERROR, "return_flow_temperature", {95.0f, -10.0f}, 0.0f, 0U, getReturnFlowTemperature}}; +static eSafetyState sSafetyState = SAFETY_NO_ERROR; void taskSafety(void *pvParameters); void checkSensorSanity(void); @@ -30,7 +32,7 @@ void initSafety(void) BaseType_t taskCreated = xTaskCreate( taskSafety, // Function to implement the task "taskSafety", // Task name - 2048, // Stack size (in words, not bytes) + 4096, // Stack size (in words, not bytes) NULL, // Parameters to the task function (none in this case) 5, // Task priority (higher number = higher priority) NULL // Task handle (optional) @@ -52,13 +54,18 @@ void taskSafety(void *pvParameters) { vTaskDelay(PERIODIC_INTERVAL * 1000U / portTICK_PERIOD_MS); - checkSensorSanity(); + if (xSemaphoreTake(xMutexAccessSafety, portMAX_DELAY) == pdTRUE) + { + + checkSensorSanity(); + xSemaphoreGive(xMutexAccessSafety); + } } } void checkSensorSanity(void) { - + sSafetyState = SAFETY_NO_ERROR; for (int i = 0; i < NUMBER_OF_SENSOR_SANITY_CHECKS; i++) { // printf("Check sanity of sensor %s:\n", sanityChecks[i].name); @@ -66,34 +73,47 @@ void checkSensorSanity(void) // printf(" Sensor Limits: Max = %.2f, Min = %.2f\n", sanityChecks[i].sSensorLimit.max, sanityChecks[i].sSensorLimit.min); // printf(" Last Sensor Temperature: %.2f\n", sanityChecks[i].fSensorTemperatureLast); - const float fSensorTemperatureCurrent = sanityChecks[i].getSensor(CURRENT); - if (fSensorTemperatureCurrent == sanityChecks[i].fSensorTemperatureLast) + const sMeasurement sCurrentMeasurement = sanityChecks[i].getSensor(); + + if (sCurrentMeasurement.state == MEASUREMENT_FAULT) { - sanityChecks[i].uUnchangedCounter++; - if (sanityChecks[i].uUnchangedCounter >= (SENSOR_GRACE_PERIOD / PERIODIC_INTERVAL)) - { - ESP_LOGE(TAG, "%s Sensor reported unchanged value! %lf == %lf", sanityChecks[i].name, fSensorTemperatureCurrent, sanityChecks[i].fSensorTemperatureLast); - sanityChecks[i].status = 1U; - } + ESP_LOGE(TAG, "%s Sensor not found!", sanityChecks[i].name); + sanityChecks[i].status = SENSOR_NOT_FOUND; + sSafetyState = SAFETY_SENSOR_ERROR; } else { - sanityChecks[i].fSensorTemperatureLast = fSensorTemperatureCurrent; - - if (fSensorTemperatureCurrent > sanityChecks[i].sSensorLimit.max) + if (sCurrentMeasurement.fCurrentValue == sanityChecks[i].fSensorTemperatureLast) { - ESP_LOGE(TAG, "%s Sensor reported too high value! %lf > %lf", sanityChecks[i].name, fSensorTemperatureCurrent, sanityChecks[i].sSensorLimit.max); - sanityChecks[i].status = 1U; - } - else if (fSensorTemperatureCurrent < sanityChecks[i].sSensorLimit.min) - { - ESP_LOGE(TAG, "%s Sensor reported too low value! %lf < %lf", sanityChecks[i].name, fSensorTemperatureCurrent, sanityChecks[i].sSensorLimit.min); - sanityChecks[i].status = 1U; + sanityChecks[i].uUnchangedCounter++; + if (sanityChecks[i].uUnchangedCounter >= (SENSOR_GRACE_PERIOD / PERIODIC_INTERVAL)) + { + ESP_LOGE(TAG, "%s Sensor reported unchanged value! %lf == %lf", sanityChecks[i].name, sCurrentMeasurement.fCurrentValue, sanityChecks[i].fSensorTemperatureLast); + sanityChecks[i].status = SENSOR_UNCHANGED; + sSafetyState = SAFETY_SENSOR_ERROR; + } } else { - sanityChecks[i].uUnchangedCounter = 0U; - sanityChecks[i].status = 0U; + sanityChecks[i].fSensorTemperatureLast = sCurrentMeasurement.fCurrentValue; + + if (sCurrentMeasurement.fCurrentValue > sanityChecks[i].sSensorLimit.max) + { + ESP_LOGE(TAG, "%s Sensor reported too high value! %lf > %lf", sanityChecks[i].name, sCurrentMeasurement.fCurrentValue, sanityChecks[i].sSensorLimit.max); + sanityChecks[i].status = SENSOR_TOO_HIGH; + sSafetyState = SAFETY_SENSOR_ERROR; + } + else if (sCurrentMeasurement.fCurrentValue < sanityChecks[i].sSensorLimit.min) + { + ESP_LOGE(TAG, "%s Sensor reported too low value! %lf < %lf", sanityChecks[i].name, sCurrentMeasurement.fCurrentValue, sanityChecks[i].sSensorLimit.min); + sanityChecks[i].status = SENSOR_TOO_LOW; + sSafetyState = SAFETY_SENSOR_ERROR; + } + else + { + sanityChecks[i].uUnchangedCounter = 0U; + sanityChecks[i].status = SENSOR_NO_ERROR; + } } } // printf(" Status: %u\n", sanityChecks[i].status); @@ -106,9 +126,27 @@ void setSafeState(void) setBurnerState(DISABLED); } -/* -sSafetyStateElement *getSafetyStates(void) +void getSensorSanityStates(sSensorSanityCheck *pSensorSanityChecks) { - return safetyStates; + if (xSemaphoreTake(xMutexAccessSafety, portMAX_DELAY) == pdTRUE) + { + for (size_t i = 0; i < NUMBER_OF_SENSOR_SANITY_CHECKS; i++) + { + // Copy only the needed attributes + pSensorSanityChecks[i].status = sanityChecks[i].status; + strcpy(pSensorSanityChecks[i].name, sanityChecks[i].name); + } + xSemaphoreGive(xMutexAccessSafety); + } } -*/ \ No newline at end of file + +eSafetyState getSafetyState(void) +{ + eSafetyState state = SAFETY_NO_ERROR; + if (xSemaphoreTake(xMutexAccessSafety, portMAX_DELAY) == pdTRUE) + { + state = sSafetyState; + xSemaphoreGive(xMutexAccessSafety); + } + return state; +} \ No newline at end of file diff --git a/main/safety.h b/main/safety.h index b8eb133..663fc7d 100644 --- a/main/safety.h +++ b/main/safety.h @@ -6,7 +6,22 @@ #define MAX_ERROR_STRING_SIZE 64U #define NUMBER_OF_SENSOR_SANITY_CHECKS 4U -typedef float (*GetSensorValue)(eMeasurementMode); +typedef enum _SensorErrorState +{ + SENSOR_NO_ERROR, + SENSOR_TOO_HIGH, + SENSOR_TOO_LOW, + SENSOR_UNCHANGED, + SENSOR_NOT_FOUND +} eSensorErrorState; + +typedef enum _SafetyState +{ + SAFETY_NO_ERROR, + SAFETY_SENSOR_ERROR, +} eSafetyState; + +typedef sMeasurement (*GetSensorValue)(); typedef struct _TemperatureSensorLimit { float max; // Maximum temperature limit @@ -14,7 +29,7 @@ typedef struct _TemperatureSensorLimit } sTemperatureSensorLimit; typedef struct _SensorSanityCheck { - uint8_t status; + eSensorErrorState status; char name[MAX_ERROR_STRING_SIZE]; sTemperatureSensorLimit sSensorLimit; float fSensorTemperatureLast; @@ -23,5 +38,5 @@ typedef struct _SensorSanityCheck } sSensorSanityCheck; void initSafety(void); - -//sSensorSanityCheck *getSafetyStates(void); \ No newline at end of file +void getSensorSanityStates(sSensorSanityCheck *pSensorSanityChecks); +eSafetyState getSafetyState(void); \ No newline at end of file