|
|
|
|
@@ -4,7 +4,12 @@
|
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
|
#include "freertos/semphr.h"
|
|
|
|
|
#include "freertos/task.h"
|
|
|
|
|
#include "freertos/queue.h"
|
|
|
|
|
#include "esp_check.h"
|
|
|
|
|
#include "esp_log.h"
|
|
|
|
|
#include "nvs.h"
|
|
|
|
|
#include "relay_chn_nvs.h"
|
|
|
|
|
|
|
|
|
|
@@ -26,12 +31,71 @@
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// --- Task and message queue config ---
|
|
|
|
|
#define RELAY_CHN_NVS_QUEUE_LEN (8 + CONFIG_RELAY_CHN_COUNT * 8)
|
|
|
|
|
#define RELAY_CHN_NVS_TASK_STACK 2048
|
|
|
|
|
#define RELAY_CHN_NVS_COMMIT_TIMEOUT_MS 200
|
|
|
|
|
#define RELAY_CHN_NVS_TASK_PRIO (tskIDLE_PRIORITY + 4)
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
RELAY_CHN_NVS_OP_ERASE_ALL,
|
|
|
|
|
RELAY_CHN_NVS_OP_SET_DIRECTION,
|
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
|
|
|
RELAY_CHN_NVS_OP_SET_RUN_LIMIT,
|
|
|
|
|
#endif
|
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
|
|
|
RELAY_CHN_NVS_OP_SET_TILT_SENSITIVITY,
|
|
|
|
|
RELAY_CHN_NVS_OP_SET_TILT_COUNT,
|
|
|
|
|
#endif
|
|
|
|
|
RELAY_CHN_NVS_OP_DEINIT,
|
|
|
|
|
} relay_chn_nvs_op_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
relay_chn_nvs_op_t op;
|
|
|
|
|
uint8_t ch;
|
|
|
|
|
union {
|
|
|
|
|
uint16_t data_u16;
|
|
|
|
|
uint8_t data_u8;
|
|
|
|
|
} data;
|
|
|
|
|
} relay_chn_nvs_msg_t;
|
|
|
|
|
|
|
|
|
|
static const char *TAG = "RELAY_CHN_NVS";
|
|
|
|
|
|
|
|
|
|
static nvs_handle_t relay_chn_nvs;
|
|
|
|
|
static QueueHandle_t nvs_queue_handle = NULL;
|
|
|
|
|
static TaskHandle_t nvs_task_handle = NULL;
|
|
|
|
|
static SemaphoreHandle_t deinit_sem = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void relay_chn_nvs_task(void *arg);
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_init()
|
|
|
|
|
{
|
|
|
|
|
// Already initialized?
|
|
|
|
|
if (nvs_queue_handle != NULL) {
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deinit_sem = xSemaphoreCreateBinary();
|
|
|
|
|
if (!deinit_sem) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to create deinit semaphore");
|
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nvs_queue_handle = xQueueCreate(RELAY_CHN_NVS_QUEUE_LEN, sizeof(relay_chn_nvs_msg_t));
|
|
|
|
|
if (!nvs_queue_handle) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to create NVS queue");
|
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BaseType_t res = xTaskCreate(relay_chn_nvs_task, "task_rlch_nvs",
|
|
|
|
|
RELAY_CHN_NVS_TASK_STACK, NULL,
|
|
|
|
|
RELAY_CHN_NVS_TASK_PRIO, &nvs_task_handle);
|
|
|
|
|
if (res != pdPASS) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to create NVS task");
|
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t ret;
|
|
|
|
|
#if CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION
|
|
|
|
|
ret = nvs_open_from_partition(CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME,
|
|
|
|
|
@@ -52,7 +116,39 @@ esp_err_t relay_chn_nvs_init()
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t relay_chn_nvs_enqueue(relay_chn_nvs_msg_t *msg, const char *op_name)
|
|
|
|
|
{
|
|
|
|
|
if (!nvs_queue_handle) {
|
|
|
|
|
return ESP_ERR_INVALID_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (msg->op == RELAY_CHN_NVS_OP_DEINIT || msg->op == RELAY_CHN_NVS_OP_ERASE_ALL) {
|
|
|
|
|
// Send DEINIT or ERASE_ALL to the front and wait up to 1 sec if needed
|
|
|
|
|
if (xQueueSendToFront(nvs_queue_handle, msg, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
|
|
|
|
ESP_LOGW(TAG, "NVS queue is full, dropping %s for #%d", op_name, msg->ch);
|
|
|
|
|
return ESP_FAIL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Send async
|
|
|
|
|
if (xQueueSend(nvs_queue_handle, msg, 0) != pdTRUE) {
|
|
|
|
|
ESP_LOGW(TAG, "NVS queue is full, dropping %s for #%d", op_name, msg->ch);
|
|
|
|
|
return ESP_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t direction)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_nvs_msg_t msg = {
|
|
|
|
|
.op = RELAY_CHN_NVS_OP_SET_DIRECTION,
|
|
|
|
|
.ch = ch,
|
|
|
|
|
.data.data_u8 = (uint8_t) direction,
|
|
|
|
|
};
|
|
|
|
|
return relay_chn_nvs_enqueue(&msg, "SET_DIRECTION");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t relay_chn_nvs_task_set_direction(uint8_t ch, uint8_t direction)
|
|
|
|
|
{
|
|
|
|
|
uint8_t direction_val = 0;
|
|
|
|
|
esp_err_t ret = nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, &direction_val);
|
|
|
|
|
@@ -63,24 +159,38 @@ esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t directio
|
|
|
|
|
direction_val |= (((uint8_t) direction) << ch); // Set the new direction bit
|
|
|
|
|
ret = nvs_set_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, direction_val);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set direction for channel %d", ch);
|
|
|
|
|
return nvs_commit(relay_chn_nvs);
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_get_direction(uint8_t ch, relay_chn_direction_t *direction)
|
|
|
|
|
esp_err_t relay_chn_nvs_get_direction(uint8_t ch, relay_chn_direction_t *direction, relay_chn_direction_t default_val)
|
|
|
|
|
{
|
|
|
|
|
ESP_RETURN_ON_FALSE(direction != NULL, ESP_ERR_INVALID_ARG, TAG, "Direction pointer is NULL");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t direction_val;
|
|
|
|
|
esp_err_t ret = nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, &direction_val);
|
|
|
|
|
if (ret != ESP_OK) {
|
|
|
|
|
return ret; // Return error if the key does not exist
|
|
|
|
|
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
|
|
|
|
*direction = default_val;
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
} else if (ret != ESP_OK) {
|
|
|
|
|
return ret; // A real error occurred, return it
|
|
|
|
|
}
|
|
|
|
|
// If ret is ESP_OK, direction_val has the stored value.
|
|
|
|
|
*direction = (relay_chn_direction_t)((direction_val >> ch) & 0x01);
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
|
|
|
esp_err_t relay_chn_nvs_set_run_limit(uint8_t ch, uint16_t limit_sec)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_nvs_msg_t msg = {
|
|
|
|
|
.op = RELAY_CHN_NVS_OP_SET_RUN_LIMIT,
|
|
|
|
|
.ch = ch,
|
|
|
|
|
.data.data_u16 = limit_sec,
|
|
|
|
|
};
|
|
|
|
|
return relay_chn_nvs_enqueue(&msg, "SET_RUN_LIMIT");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t relay_chn_nvs_task_set_run_limit(uint8_t ch, uint16_t limit_sec)
|
|
|
|
|
{
|
|
|
|
|
esp_err_t ret;
|
|
|
|
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
|
|
|
|
@@ -91,25 +201,41 @@ esp_err_t relay_chn_nvs_set_run_limit(uint8_t ch, uint16_t limit_sec)
|
|
|
|
|
ret = nvs_set_u16(relay_chn_nvs, RELAY_CHN_KEY_RLIM, limit_sec);
|
|
|
|
|
#endif
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set run limit for channel %d", ch);
|
|
|
|
|
return nvs_commit(relay_chn_nvs);
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_get_run_limit(uint8_t ch, uint16_t *limit_sec)
|
|
|
|
|
esp_err_t relay_chn_nvs_get_run_limit(uint8_t ch, uint16_t *limit_sec, uint16_t default_val)
|
|
|
|
|
{
|
|
|
|
|
ESP_RETURN_ON_FALSE(limit_sec != NULL, ESP_ERR_INVALID_ARG, TAG, "Run limit value pointer is NULL");
|
|
|
|
|
|
|
|
|
|
esp_err_t ret;
|
|
|
|
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
|
|
|
|
char key[NVS_KEY_NAME_MAX_SIZE];
|
|
|
|
|
snprintf(key, sizeof(key), RELAY_CHN_KEY_RLIM_FMT, ch);
|
|
|
|
|
return nvs_get_u16(relay_chn_nvs, key, limit_sec);
|
|
|
|
|
ret = nvs_get_u16(relay_chn_nvs, key, limit_sec);
|
|
|
|
|
#else
|
|
|
|
|
return nvs_get_u16(relay_chn_nvs, RELAY_CHN_KEY_RLIM, limit_sec);
|
|
|
|
|
ret = nvs_get_u16(relay_chn_nvs, RELAY_CHN_KEY_RLIM, limit_sec);
|
|
|
|
|
#endif
|
|
|
|
|
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
|
|
|
|
*limit_sec = default_val;
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
|
|
|
|
|
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
|
|
|
esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_nvs_msg_t msg = {
|
|
|
|
|
.op = RELAY_CHN_NVS_OP_SET_TILT_SENSITIVITY,
|
|
|
|
|
.ch = ch,
|
|
|
|
|
.data.data_u8 = sensitivity,
|
|
|
|
|
};
|
|
|
|
|
return relay_chn_nvs_enqueue(&msg, "SET_TILT_SENSITIVITY");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t relay_chn_nvs_task_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity)
|
|
|
|
|
{
|
|
|
|
|
esp_err_t ret;
|
|
|
|
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
|
|
|
|
@@ -120,23 +246,39 @@ esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity)
|
|
|
|
|
ret = nvs_set_u8(relay_chn_nvs, RELAY_CHN_KEY_TSENS, sensitivity);
|
|
|
|
|
#endif
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set tilt sensitivity for channel %d", ch);
|
|
|
|
|
return nvs_commit(relay_chn_nvs);
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_get_tilt_sensitivity(uint8_t ch, uint8_t *sensitivity)
|
|
|
|
|
esp_err_t relay_chn_nvs_get_tilt_sensitivity(uint8_t ch, uint8_t *sensitivity, uint8_t default_val)
|
|
|
|
|
{
|
|
|
|
|
ESP_RETURN_ON_FALSE(sensitivity != NULL, ESP_ERR_INVALID_ARG, TAG, "Sensitivity pointer is NULL");
|
|
|
|
|
|
|
|
|
|
esp_err_t ret;
|
|
|
|
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
|
|
|
|
char key[NVS_KEY_NAME_MAX_SIZE];
|
|
|
|
|
snprintf(key, sizeof(key), RELAY_CHN_KEY_TSENS_FMT, ch);
|
|
|
|
|
return nvs_get_u8(relay_chn_nvs, key, sensitivity);
|
|
|
|
|
ret = nvs_get_u8(relay_chn_nvs, key, sensitivity);
|
|
|
|
|
#else
|
|
|
|
|
return nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_TSENS, sensitivity);
|
|
|
|
|
ret = nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_TSENS, sensitivity);
|
|
|
|
|
#endif
|
|
|
|
|
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
|
|
|
|
*sensitivity = default_val;
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_set_tilt_count(uint8_t ch, uint16_t tilt_count)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_nvs_msg_t msg = {
|
|
|
|
|
.op = RELAY_CHN_NVS_OP_SET_TILT_COUNT,
|
|
|
|
|
.ch = ch,
|
|
|
|
|
.data.data_u16 = tilt_count,
|
|
|
|
|
};
|
|
|
|
|
return relay_chn_nvs_enqueue(&msg, "SET_TILT_COUNT");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t relay_chn_nvs_task_set_tilt_count(uint8_t ch, uint16_t tilt_count)
|
|
|
|
|
{
|
|
|
|
|
esp_err_t ret;
|
|
|
|
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
|
|
|
|
@@ -147,35 +289,164 @@ esp_err_t relay_chn_nvs_set_tilt_count(uint8_t ch, uint16_t tilt_count)
|
|
|
|
|
ret = nvs_set_u16(relay_chn_nvs, RELAY_CHN_KEY_TCNT, tilt_count);
|
|
|
|
|
#endif
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to save tilt_count tilt counter");
|
|
|
|
|
return nvs_commit(relay_chn_nvs);
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_get_tilt_count(uint8_t ch, uint16_t *tilt_count)
|
|
|
|
|
esp_err_t relay_chn_nvs_get_tilt_count(uint8_t ch, uint16_t *tilt_count, uint16_t default_val)
|
|
|
|
|
{
|
|
|
|
|
ESP_RETURN_ON_FALSE(tilt_count != NULL, ESP_ERR_INVALID_ARG, TAG, "Counter pointers are NULL");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
esp_err_t ret;
|
|
|
|
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
|
|
|
|
char key[NVS_KEY_NAME_MAX_SIZE];
|
|
|
|
|
snprintf(key, sizeof(key), RELAY_CHN_KEY_TCNT_FMT, ch);
|
|
|
|
|
return nvs_get_u16(relay_chn_nvs, key, tilt_count);
|
|
|
|
|
ret = nvs_get_u16(relay_chn_nvs, key, tilt_count);
|
|
|
|
|
#else
|
|
|
|
|
return nvs_get_u16(relay_chn_nvs, RELAY_CHN_KEY_TCNT, tilt_count);
|
|
|
|
|
ret = nvs_get_u16(relay_chn_nvs, RELAY_CHN_KEY_TCNT, tilt_count);
|
|
|
|
|
#endif
|
|
|
|
|
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
|
|
|
|
*tilt_count = default_val;
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_erase_all()
|
|
|
|
|
{
|
|
|
|
|
relay_chn_nvs_msg_t msg = {
|
|
|
|
|
.op = RELAY_CHN_NVS_OP_ERASE_ALL,
|
|
|
|
|
};
|
|
|
|
|
return relay_chn_nvs_enqueue(&msg, "ERASE_ALL");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t do_nvs_deinit()
|
|
|
|
|
{
|
|
|
|
|
relay_chn_nvs_msg_t msg = {
|
|
|
|
|
.op = RELAY_CHN_NVS_OP_DEINIT,
|
|
|
|
|
};
|
|
|
|
|
return relay_chn_nvs_enqueue(&msg, "DEINIT");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t do_nvs_erase_all()
|
|
|
|
|
{
|
|
|
|
|
// Flush all pending SET operations since ERASE_ALL requested
|
|
|
|
|
xQueueReset(nvs_queue_handle);
|
|
|
|
|
// Erase all key-value pairs in the relay_chn NVS namespace
|
|
|
|
|
esp_err_t ret = nvs_erase_all(relay_chn_nvs);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to erase all keys in NVS namespace '%s'", CONFIG_RELAY_CHN_NVS_NAMESPACE);
|
|
|
|
|
|
|
|
|
|
// Commit the changes
|
|
|
|
|
return nvs_commit(relay_chn_nvs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t relay_chn_nvs_deinit()
|
|
|
|
|
{
|
|
|
|
|
nvs_close(relay_chn_nvs);
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void relay_chn_nvs_deinit()
|
|
|
|
|
{
|
|
|
|
|
if (nvs_task_handle) {
|
|
|
|
|
if (do_nvs_deinit() == ESP_OK) {
|
|
|
|
|
if (deinit_sem && xSemaphoreTake(deinit_sem, pdMS_TO_TICKS(2000)) != pdTRUE) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to get deinit confirmation from NVS task. Forcing deletion.");
|
|
|
|
|
vTaskDelete(nvs_task_handle); // Last resort
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to send deinit message to NVS task. Forcing deletion.");
|
|
|
|
|
vTaskDelete(nvs_task_handle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (nvs_queue_handle) {
|
|
|
|
|
vQueueDelete(nvs_queue_handle);
|
|
|
|
|
nvs_queue_handle = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (deinit_sem) {
|
|
|
|
|
vSemaphoreDelete(deinit_sem);
|
|
|
|
|
deinit_sem = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close NVS handle here, after task has stopped and queue is deleted.
|
|
|
|
|
nvs_close(relay_chn_nvs);
|
|
|
|
|
nvs_task_handle = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t relay_chn_nvs_task_process_message(const relay_chn_nvs_msg_t *msg, bool *running, bool *dirty)
|
|
|
|
|
{
|
|
|
|
|
esp_err_t ret = ESP_OK;
|
|
|
|
|
switch (msg->op) {
|
|
|
|
|
case RELAY_CHN_NVS_OP_SET_DIRECTION:
|
|
|
|
|
ret = relay_chn_nvs_task_set_direction(msg->ch, msg->data.data_u8);
|
|
|
|
|
if (ret == ESP_OK) *dirty = true;
|
|
|
|
|
break;
|
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
|
|
|
case RELAY_CHN_NVS_OP_SET_RUN_LIMIT:
|
|
|
|
|
ret = relay_chn_nvs_task_set_run_limit(msg->ch, msg->data.data_u16);
|
|
|
|
|
if (ret == ESP_OK) *dirty = true;
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
|
|
|
case RELAY_CHN_NVS_OP_SET_TILT_SENSITIVITY:
|
|
|
|
|
ret = relay_chn_nvs_task_set_tilt_sensitivity(msg->ch, msg->data.data_u8);
|
|
|
|
|
if (ret == ESP_OK) *dirty = true;
|
|
|
|
|
break;
|
|
|
|
|
case RELAY_CHN_NVS_OP_SET_TILT_COUNT:
|
|
|
|
|
ret = relay_chn_nvs_task_set_tilt_count(msg->ch, msg->data.data_u16);
|
|
|
|
|
if (ret == ESP_OK) *dirty = true;
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
case RELAY_CHN_NVS_OP_ERASE_ALL:
|
|
|
|
|
ret = do_nvs_erase_all();
|
|
|
|
|
if (ret == ESP_OK) *dirty = true;
|
|
|
|
|
break;
|
|
|
|
|
case RELAY_CHN_NVS_OP_DEINIT:
|
|
|
|
|
*running = false;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ESP_LOGE(TAG, "Unknown operation in NVS queue: %d", msg->op);
|
|
|
|
|
ret = ESP_ERR_INVALID_ARG;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The ESP-IDF NVS functions are protected by an internal mutex. If this task is killed
|
|
|
|
|
* while it's holding that mutex, the mutex is never released, which may result in
|
|
|
|
|
* deadlocks. This is why this task must be terminated gracefully.
|
|
|
|
|
*/
|
|
|
|
|
static void relay_chn_nvs_task(void *arg)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_nvs_msg_t msg;
|
|
|
|
|
bool dirty = false;
|
|
|
|
|
bool running = true;
|
|
|
|
|
|
|
|
|
|
while (running) {
|
|
|
|
|
// Block indefinitely waiting for the first message of a potential batch.
|
|
|
|
|
if (xQueueReceive(nvs_queue_handle, &msg, portMAX_DELAY) == pdTRUE) {
|
|
|
|
|
// A batch of operations has started. Use a do-while to process the first message
|
|
|
|
|
// and any subsequent messages that arrive within the timeout.
|
|
|
|
|
do {
|
|
|
|
|
esp_err_t ret = relay_chn_nvs_task_process_message(&msg, &running, &dirty);
|
|
|
|
|
if (ret != ESP_OK) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to process operation %d for #%d with error %s", msg.op, msg.ch, esp_err_to_name(ret));
|
|
|
|
|
}
|
|
|
|
|
} while (running && xQueueReceive(nvs_queue_handle, &msg, pdMS_TO_TICKS(RELAY_CHN_NVS_COMMIT_TIMEOUT_MS)) == pdTRUE);
|
|
|
|
|
|
|
|
|
|
// The burst of messages is over (timeout occurred). Commit if anything changed.
|
|
|
|
|
if (dirty) {
|
|
|
|
|
esp_err_t commit_ret = nvs_commit(relay_chn_nvs);
|
|
|
|
|
if (commit_ret == ESP_OK) {
|
|
|
|
|
dirty = false;
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGE(TAG, "NVS batch commit failed");
|
|
|
|
|
// Don't reset dirty flag, so we can try to commit again later.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Before exiting, do one final commit if there are pending changes.
|
|
|
|
|
if (dirty) {
|
|
|
|
|
if (nvs_commit(relay_chn_nvs) != ESP_OK) {
|
|
|
|
|
ESP_LOGE(TAG, "Final NVS commit failed on deinit");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
xSemaphoreGive(deinit_sem);
|
|
|
|
|
nvs_task_handle = NULL;
|
|
|
|
|
vTaskDelete(NULL);
|
|
|
|
|
}
|