error handling and cleanup
This commit is contained in:
129
main/control.c
129
main/control.c
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file control.c
|
||||
* @brief Implementation of heating control module.
|
||||
*/
|
||||
|
||||
#include "control.h"
|
||||
#include "inputs.h"
|
||||
#include "outputs.h"
|
||||
@ -9,11 +14,16 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#define PERIODIC_INTERVAL 1U // Run control loop every 1 second
|
||||
#include <time.h>
|
||||
|
||||
/** @brief Task interval in seconds. */
|
||||
#define PERIODIC_INTERVAL 1U
|
||||
|
||||
static const char *TAG = "control";
|
||||
|
||||
static const char *TAG = "smart-oil-heater-control-system-control";
|
||||
static eControlState gControlState = CONTROL_STARTING;
|
||||
// Control table for daily schedules
|
||||
|
||||
/** @brief Weekly schedule table (from Kconfig). */
|
||||
static const sControlDay gControlTable[] = {
|
||||
{MONDAY,
|
||||
2U,
|
||||
@ -72,45 +82,49 @@ static const sControlDay gControlTable[] = {
|
||||
RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT,
|
||||
CHAMBER_TEMPERATURE_TARGET}}},
|
||||
};
|
||||
|
||||
static sControlTemperatureEntry gCurrentControlEntry =
|
||||
gControlTable[0].aTemperatureEntries[0];
|
||||
static SemaphoreHandle_t xMutexAccessControl = NULL;
|
||||
|
||||
// Function prototypes
|
||||
void taskControl(void *pvParameters);
|
||||
void findControlCurrentTemperatureEntry(void);
|
||||
void setControlState(eControlState state);
|
||||
/* Private function prototypes */
|
||||
static void taskControl(void *pvParameters);
|
||||
static void findControlCurrentTemperatureEntry(void);
|
||||
static void setControlState(eControlState state);
|
||||
|
||||
void initControl(void)
|
||||
esp_err_t initControl(void)
|
||||
{
|
||||
|
||||
xMutexAccessControl = xSemaphoreCreateRecursiveMutex();
|
||||
if (xMutexAccessControl == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Unable to create mutex");
|
||||
ESP_LOGE(TAG, "Failed to create mutex");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
xSemaphoreGiveRecursive(xMutexAccessControl);
|
||||
|
||||
BaseType_t taskCreated =
|
||||
xTaskCreate(taskControl, // Function to implement the task
|
||||
"taskControl", // Task name
|
||||
8192, // 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)
|
||||
);
|
||||
BaseType_t taskCreated = xTaskCreate(
|
||||
taskControl,
|
||||
"taskControl",
|
||||
8192,
|
||||
NULL,
|
||||
5,
|
||||
NULL);
|
||||
|
||||
if (taskCreated == pdPASS)
|
||||
{
|
||||
ESP_LOGI(TAG, "Task created successfully!");
|
||||
}
|
||||
else
|
||||
if (taskCreated != pdPASS)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to create task");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Initialized successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void taskControl(void *pvParameters)
|
||||
/**
|
||||
* @brief Main control task.
|
||||
* @param pvParameters Task parameters (unused).
|
||||
*/
|
||||
static void taskControl(void *pvParameters)
|
||||
{
|
||||
bool bHeatingInAction = false;
|
||||
bool bSummerMode = false;
|
||||
@ -121,7 +135,7 @@ void taskControl(void *pvParameters)
|
||||
{
|
||||
vTaskDelay(PERIODIC_INTERVAL * 1000U / portTICK_PERIOD_MS);
|
||||
|
||||
// Check for safety faults
|
||||
/* Check for safety faults */
|
||||
if (getSafetyState() != SAFETY_NO_ERROR)
|
||||
{
|
||||
ESP_LOGW(TAG, "Control not possible due to safety fault!");
|
||||
@ -136,7 +150,7 @@ void taskControl(void *pvParameters)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for SNTP faults
|
||||
/* Check for SNTP faults */
|
||||
if (getSntpState() != SYNC_SUCCESSFUL)
|
||||
{
|
||||
ESP_LOGW(TAG, "Control not possible due to SNTP fault!");
|
||||
@ -153,35 +167,30 @@ void taskControl(void *pvParameters)
|
||||
|
||||
findControlCurrentTemperatureEntry();
|
||||
|
||||
if (getOutdoorTemperature().fDampedValue >=
|
||||
SUMMER_MODE_TEMPERATURE_THRESHOLD_HIGH)
|
||||
/* Summer mode hysteresis */
|
||||
if (getOutdoorTemperature().fDampedValue >= SUMMER_MODE_TEMPERATURE_THRESHOLD_HIGH)
|
||||
{
|
||||
bSummerMode = true;
|
||||
}
|
||||
else if (getOutdoorTemperature().fDampedValue <=
|
||||
SUMMER_MODE_TEMPERATURE_THRESHOLD_LOW)
|
||||
else if (getOutdoorTemperature().fDampedValue <= SUMMER_MODE_TEMPERATURE_THRESHOLD_LOW)
|
||||
{
|
||||
bSummerMode = false;
|
||||
}
|
||||
|
||||
// Enable burner if outdoor temperature is low and return flow temperature
|
||||
// is cooled down
|
||||
/* Enable burner if needed */
|
||||
if (!bHeatingInAction && (burnerState != BURNER_FAULT))
|
||||
{
|
||||
if (bSummerMode)
|
||||
{
|
||||
// ESP_LOGI(TAG, "Outdoor temperature too warm: Disabling heating");
|
||||
setBurnerState(DISABLED);
|
||||
setSafetyControlState(DISABLED);
|
||||
setControlState(CONTROL_OUTDOOR_TOO_WARM);
|
||||
}
|
||||
else if ((getReturnFlowTemperature().average60s.fValue <=
|
||||
getControlCurrentTemperatureEntry().fReturnFlowTemperature) &&
|
||||
(getChamberTemperature().fCurrentValue <=
|
||||
CHAMBER_TEMPERATURE_THRESHOLD))
|
||||
(getChamberTemperature().fCurrentValue <= CHAMBER_TEMPERATURE_THRESHOLD))
|
||||
{
|
||||
ESP_LOGI(TAG,
|
||||
"Enabling burner: Return flow temperature target reached");
|
||||
ESP_LOGI(TAG, "Enabling burner: Return flow temperature target reached");
|
||||
burnerState = BURNER_UNKNOWN;
|
||||
bHeatingInAction = true;
|
||||
setBurnerState(ENABLED);
|
||||
@ -191,12 +200,11 @@ void taskControl(void *pvParameters)
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESP_LOGI(TAG, "Return flow temperature too warm: Disabling heating");
|
||||
setControlState(CONTROL_RETURN_FLOW_TOO_WARM);
|
||||
}
|
||||
}
|
||||
|
||||
// Disable burner if target temperature is reached or a fault occurred
|
||||
/* Disable burner if target reached or fault */
|
||||
if (bHeatingInAction)
|
||||
{
|
||||
if ((getChamberTemperature().fCurrentValue >=
|
||||
@ -233,9 +241,8 @@ void taskControl(void *pvParameters)
|
||||
}
|
||||
}
|
||||
|
||||
// Manage circulation pump
|
||||
if (getChamberTemperature().fCurrentValue <=
|
||||
CIRCULATION_PUMP_TEMPERATURE_THRESHOLD)
|
||||
/* Manage circulation pump */
|
||||
if (getChamberTemperature().fCurrentValue <= CIRCULATION_PUMP_TEMPERATURE_THRESHOLD)
|
||||
{
|
||||
// ESP_LOGI(TAG, "Burner cooled down: Disabling circulation pump");
|
||||
setCirculationPumpState(DISABLED);
|
||||
@ -248,9 +255,12 @@ void taskControl(void *pvParameters)
|
||||
} // End of while(1)
|
||||
}
|
||||
|
||||
void setControlState(eControlState state)
|
||||
/**
|
||||
* @brief Set the control state with mutex protection.
|
||||
* @param state New control state.
|
||||
*/
|
||||
static void setControlState(eControlState state)
|
||||
{
|
||||
|
||||
if (xSemaphoreTakeRecursive(xMutexAccessControl, pdMS_TO_TICKS(5000)) == pdTRUE)
|
||||
{
|
||||
gControlState = state;
|
||||
@ -264,7 +274,6 @@ void setControlState(eControlState state)
|
||||
|
||||
eControlState getControlState(void)
|
||||
{
|
||||
|
||||
eControlState ret = CONTROL_FAULT_SAFETY;
|
||||
|
||||
if (xSemaphoreTakeRecursive(xMutexAccessControl, pdMS_TO_TICKS(5000)) == pdTRUE)
|
||||
@ -282,7 +291,6 @@ eControlState getControlState(void)
|
||||
|
||||
eControlWeekday getControlCurrentWeekday(void)
|
||||
{
|
||||
// Get current time
|
||||
time_t now;
|
||||
struct tm timeinfo;
|
||||
time(&now);
|
||||
@ -293,24 +301,12 @@ eControlWeekday getControlCurrentWeekday(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds the active temperature control entry for the current time.
|
||||
*
|
||||
* Searches through the weekly schedule to find the most recent entry
|
||||
* that should be active at the current date/time. Falls back to the
|
||||
* last entry in the week if no suitable entry is found.
|
||||
* @brief Find the currently active temperature entry based on time.
|
||||
*/
|
||||
/**
|
||||
* @brief Finds the active temperature control entry for the current time.
|
||||
*
|
||||
* Searches through the weekly schedule to find the most recent entry
|
||||
* that should be active at the current date/time. Falls back to the
|
||||
* last entry in the week if no suitable entry is found.
|
||||
*/
|
||||
void findControlCurrentTemperatureEntry(void)
|
||||
static void findControlCurrentTemperatureEntry(void)
|
||||
{
|
||||
eControlWeekday currentDay = getControlCurrentWeekday();
|
||||
|
||||
// Get current time
|
||||
time_t now;
|
||||
struct tm timeinfo;
|
||||
time(&now);
|
||||
@ -361,14 +357,15 @@ void findControlCurrentTemperatureEntry(void)
|
||||
const sControlDay *sunday = &gControlTable[6];
|
||||
gCurrentControlEntry = sunday->aTemperatureEntries[sunday->entryCount - 1];
|
||||
}
|
||||
xSemaphoreGiveRecursive(xMutexAccessControl);
|
||||
/*
|
||||
ESP_LOGI(TAG, "Active entry found - Time: %02d:%02d, "
|
||||
"Return Temp: %lf, Chamber Temp: %lf",
|
||||
gCurrentControlEntry.timestamp.hour,
|
||||
gCurrentControlEntry.timestamp.minute,
|
||||
gCurrentControlEntry.fReturnFlowTemperature,
|
||||
gCurrentControlEntry.fChamberTemperature);
|
||||
*/
|
||||
"Return Temp: %lf, Chamber Temp: %lf",
|
||||
gCurrentControlEntry.timestamp.hour,
|
||||
gCurrentControlEntry.timestamp.minute,
|
||||
gCurrentControlEntry.fReturnFlowTemperature,
|
||||
gCurrentControlEntry.fChamberTemperature);
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user