safety state and input error detection
This commit is contained in:
parent
a7f6973efd
commit
8205253b5a
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@ -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"
|
||||
|
158
main/inputs.c
158
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,6 +122,12 @@ 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)
|
||||
{
|
||||
@ -180,129 +167,88 @@ void taskInput(void *pvParameters)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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);
|
@ -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*/
|
||||
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);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include <string.h>
|
||||
#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);
|
||||
|
||||
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)
|
||||
{
|
||||
ESP_LOGE(TAG, "%s Sensor not found!", sanityChecks[i].name);
|
||||
sanityChecks[i].status = SENSOR_NOT_FOUND;
|
||||
sSafetyState = SAFETY_SENSOR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sCurrentMeasurement.fCurrentValue == sanityChecks[i].fSensorTemperatureLast)
|
||||
{
|
||||
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 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].fSensorTemperatureLast = fSensorTemperatureCurrent;
|
||||
sanityChecks[i].fSensorTemperatureLast = sCurrentMeasurement.fCurrentValue;
|
||||
|
||||
if (fSensorTemperatureCurrent > sanityChecks[i].sSensorLimit.max)
|
||||
if (sCurrentMeasurement.fCurrentValue > sanityChecks[i].sSensorLimit.max)
|
||||
{
|
||||
ESP_LOGE(TAG, "%s Sensor reported too high value! %lf > %lf", sanityChecks[i].name, fSensorTemperatureCurrent, sanityChecks[i].sSensorLimit.max);
|
||||
sanityChecks[i].status = 1U;
|
||||
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 (fSensorTemperatureCurrent < sanityChecks[i].sSensorLimit.min)
|
||||
else if (sCurrentMeasurement.fCurrentValue < 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;
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
|
||||
eSafetyState getSafetyState(void)
|
||||
{
|
||||
eSafetyState state = SAFETY_NO_ERROR;
|
||||
if (xSemaphoreTake(xMutexAccessSafety, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
state = sSafetyState;
|
||||
xSemaphoreGive(xMutexAccessSafety);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
*/
|
@ -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);
|
||||
void getSensorSanityStates(sSensorSanityCheck *pSensorSanityChecks);
|
||||
eSafetyState getSafetyState(void);
|
Loading…
Reference in New Issue
Block a user