Optimize timer callbacks

It turned out that esp_event was adding extra complexity to the code base and it was completely unnecessary. So it has been removed from the component completely. The actions are now executed directly in the `relay_chn_distpacth_cmd()` and `relay_chn_tilt_dispatch_cmd()` functions.
This change has simplified the component as well as reduced the memory footprint.

Fixes #1084, refs #1083
This commit is contained in:
2025-08-22 17:41:08 +03:00
parent e73c205e3d
commit 7a0f9b1420
6 changed files with 34 additions and 148 deletions

View File

@@ -23,4 +23,4 @@ endif()
idf_component_register(SRCS ${srcs} idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include_dirs} INCLUDE_DIRS ${include_dirs}
PRIV_INCLUDE_DIRS ${priv_include_dirs} PRIV_INCLUDE_DIRS ${priv_include_dirs}
REQUIRES driver esp_timer esp_event nvs_flash) REQUIRES driver esp_timer nvs_flash)

View File

@@ -9,9 +9,6 @@
* To prevent mechanical strain on the motor, the component automatically manages direction changes * To prevent mechanical strain on the motor, the component automatically manages direction changes
* with a configurable inertia delay, protecting it from abrupt reversals. * with a configurable inertia delay, protecting it from abrupt reversals.
* The STOP command overrides any other command and clears the pending command if any. * The STOP command overrides any other command and clears the pending command if any.
*
* The module internally uses a custom esp event loop to handle relay commands serially to ensure
* reliability and prevent conflict operations. Also, the esp timer is used to manage the direction change inertia.
*/ */
#pragma once #pragma once

View File

@@ -8,8 +8,6 @@
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_event_base.h"
#include "esp_event.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "relay_chn_defs.h" #include "relay_chn_defs.h"
#include "relay_chn_types.h" #include "relay_chn_types.h"
@@ -19,9 +17,6 @@
extern "C" { extern "C" {
#endif #endif
/// Event base used by *_core, *_ctl, and *_tilt modules.
ESP_EVENT_DECLARE_BASE(RELAY_CHN_CMD_EVENT);
/** /**
* @brief Initializes the relay channel timer. * @brief Initializes the relay channel timer.
* *
@@ -59,7 +54,7 @@ esp_err_t relay_chn_init_run_limit_timer(relay_chn_ctl_t *chn_ctl);
void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd); void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd);
/** /**
* @brief Dispatches a relay channel command to the event loop. * @brief Dispatches a relay channel command.
* *
* @param chn_ctl Pointer to the relay channel control structure. * @param chn_ctl Pointer to the relay channel control structure.
* @param cmd The command to dispatch. * @param cmd The command to dispatch.
@@ -118,11 +113,6 @@ char *relay_chn_state_str(relay_chn_state_t state);
bool relay_chn_is_channel_id_valid(uint8_t chn_id); bool relay_chn_is_channel_id_valid(uint8_t chn_id);
#endif // RELAY_CHN_COUNT > 1 #endif // RELAY_CHN_COUNT > 1
#if RELAY_CHN_ENABLE_TILTING == 1
/// Relay channel event loop handle declaration for *_tilt module.
extern esp_event_loop_handle_t relay_chn_event_loop;
#endif // RELAY_CHN_ENABLE_TILTING
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -15,7 +15,7 @@ extern "C" {
/** /**
* @brief Initialize relay channel tilt controls. * @brief Initialize relay channel tilt controls.
* *
* Sets up tilt functionality for relay channels including timers and event handlers. * Sets up tilt functionality for relay channels including timers.
* Must be called before using any other tilt functions. * Must be called before using any other tilt functions.
* *
* @param[in] chn_ctls Array of relay channel control structures. * @param[in] chn_ctls Array of relay channel control structures.
@@ -27,7 +27,7 @@ esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls);
/** /**
* @brief Deinitialize relay channel tilt controls. * @brief Deinitialize relay channel tilt controls.
* *
* Cleans up tilt resources including timers and event handlers. * Cleans up tilt resources including timers.
* Should be called when tilt functionality is no longer needed. * Should be called when tilt functionality is no longer needed.
*/ */
void relay_chn_tilt_deinit(void); void relay_chn_tilt_deinit(void);

View File

@@ -22,31 +22,9 @@
#include "relay_chn_core.h" #include "relay_chn_core.h"
/*
Determine the event loop's queue and task stack sizes depending on
the configuration and memory requirements
*/
#if RELAY_CHN_ENABLE_TILTING == 1
#define EVENT_QUEUE_BASE_SIZE 32
#define EVENT_QUEUE_SIZE_BY_CHN 24
#define TASK_STACK_BASE_SIZE 4096
#else
#define EVENT_QUEUE_BASE_SIZE 16
#define EVENT_QUEUE_SIZE_BY_CHN 12
#define TASK_STACK_BASE_SIZE 2048
#endif
#define RELAY_CHN_EVENT_LOOP_QUEUE_SIZE \
(EVENT_QUEUE_BASE_SIZE + (EVENT_QUEUE_SIZE_BY_CHN * RELAY_CHN_COUNT))
#define RELAY_CHN_EVENT_LOOP_TASK_STACK_SIZE \
(TASK_STACK_BASE_SIZE + (RELAY_CHN_EVENT_LOOP_QUEUE_SIZE * RELAY_CHN_COUNT))
static const char *TAG = "RELAY_CHN_CORE"; static const char *TAG = "RELAY_CHN_CORE";
ESP_EVENT_DEFINE_BASE(RELAY_CHN_CMD_EVENT);
// Structure to hold a listener entry in the linked list. // Structure to hold a listener entry in the linked list.
typedef struct relay_chn_listener_entry_type { typedef struct relay_chn_listener_entry_type {
@@ -57,15 +35,6 @@ typedef struct relay_chn_listener_entry_type {
// The list that holds references to the registered listeners. // The list that holds references to the registered listeners.
static List_t relay_chn_listener_list; static List_t relay_chn_listener_list;
// Define the event loop for global access both for this module and tilt module.
esp_event_loop_handle_t relay_chn_event_loop = NULL;
// Private function declarations
// Event handler for the relay channel command event
static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 #if RELAY_CHN_ENABLE_RUN_LIMIT == 1
/* /*
* Run limit timer callback immediately dispatches a STOP command for the * Run limit timer callback immediately dispatches a STOP command for the
@@ -116,24 +85,6 @@ esp_err_t relay_chn_init_timer(relay_chn_ctl_t *chn_ctl)
return esp_timer_create(&timer_args, &chn_ctl->inertia_timer); return esp_timer_create(&timer_args, &chn_ctl->inertia_timer);
} }
static esp_err_t relay_chn_create_event_loop()
{
esp_event_loop_args_t loop_args = {
.queue_size = RELAY_CHN_EVENT_LOOP_QUEUE_SIZE,
.task_name = "relay_chn_event_loop",
.task_priority = ESP_TASKD_EVENT_PRIO - 1,
.task_stack_size = RELAY_CHN_EVENT_LOOP_TASK_STACK_SIZE,
.task_core_id = tskNO_AFFINITY
};
esp_err_t ret = esp_event_loop_create(&loop_args, &relay_chn_event_loop);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create event loop for relay channel");
ret = esp_event_handler_register_with(relay_chn_event_loop,
RELAY_CHN_CMD_EVENT,
ESP_EVENT_ANY_ID,
relay_chn_event_handler, NULL);
return ret;
}
esp_err_t relay_chn_create(const uint8_t* gpio_map, uint8_t gpio_count) esp_err_t relay_chn_create(const uint8_t* gpio_map, uint8_t gpio_count)
{ {
ESP_RETURN_ON_FALSE(gpio_map != NULL, ESP_ERR_INVALID_ARG, TAG, "gpio_map cannot be NULL"); ESP_RETURN_ON_FALSE(gpio_map != NULL, ESP_ERR_INVALID_ARG, TAG, "gpio_map cannot be NULL");
@@ -163,10 +114,6 @@ esp_err_t relay_chn_create(const uint8_t* gpio_map, uint8_t gpio_count)
ret = relay_chn_ctl_init(outputs, run_infos); ret = relay_chn_ctl_init(outputs, run_infos);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel control"); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel control");
// Create relay channel command event loop
ret = relay_chn_create_event_loop();
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create relay channel event loop");
#if RELAY_CHN_ENABLE_TILTING == 1 #if RELAY_CHN_ENABLE_TILTING == 1
// Initialize the tilt feature // Initialize the tilt feature
#if RELAY_CHN_COUNT > 1 #if RELAY_CHN_COUNT > 1
@@ -196,10 +143,6 @@ void relay_chn_destroy(void)
relay_chn_nvs_deinit(); relay_chn_nvs_deinit();
#endif #endif
// Destroy the event loop
esp_event_loop_delete(relay_chn_event_loop);
relay_chn_event_loop = NULL;
// Free the listeners // Free the listeners
while (listCURRENT_LIST_LENGTH(&relay_chn_listener_list) > 0) { while (listCURRENT_LIST_LENGTH(&relay_chn_listener_list) > 0) {
ListItem_t *pxItem = listGET_HEAD_ENTRY(&relay_chn_listener_list); ListItem_t *pxItem = listGET_HEAD_ENTRY(&relay_chn_listener_list);
@@ -283,31 +226,6 @@ void relay_chn_unregister_listener(relay_chn_state_listener_t listener)
} }
// Dispatch relay channel command to its event loop
void relay_chn_dispatch_cmd(relay_chn_ctl_t *chn_ctl, relay_chn_cmd_t cmd) {
if (cmd == RELAY_CHN_CMD_NONE) {
return;
}
// Since the event_loop library creates a deep copy of the event data,
// and we need to pass the pointer of the relevant channel, here we need
// to pass the pointer to the pointer of the channel (&chn_ctl) so that
// the pointer value is preserved in the event data.
esp_event_post_to(relay_chn_event_loop,
RELAY_CHN_CMD_EVENT,
cmd,
&chn_ctl,
sizeof(chn_ctl),
portMAX_DELAY);
#if RELAY_CHN_ENABLE_TILTING == 1
// Reset the tilt counter when the command is either FORWARD or REVERSE
if (cmd == RELAY_CHN_CMD_FORWARD || cmd == RELAY_CHN_CMD_REVERSE) {
relay_chn_tilt_reset_count(chn_ctl->tilt_ctl);
}
#endif
}
esp_err_t relay_chn_start_esp_timer_once(esp_timer_handle_t esp_timer, uint32_t time_ms) esp_err_t relay_chn_start_esp_timer_once(esp_timer_handle_t esp_timer, uint32_t time_ms)
{ {
esp_err_t ret = esp_timer_start_once(esp_timer, time_ms * 1000); esp_err_t ret = esp_timer_start_once(esp_timer, time_ms * 1000);
@@ -498,6 +416,14 @@ bool relay_chn_is_channel_id_valid(uint8_t chn_id)
#endif // RELAY_CHN_COUNT > 1 #endif // RELAY_CHN_COUNT > 1
static void relay_chn_execute_idle(relay_chn_ctl_t *chn_ctl)
{
chn_ctl->pending_cmd = RELAY_CHN_CMD_NONE;
// Invalidate the channel's timer if it is active
esp_timer_stop(chn_ctl->inertia_timer);
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_IDLE);
}
static void relay_chn_execute_stop(relay_chn_ctl_t *chn_ctl) static void relay_chn_execute_stop(relay_chn_ctl_t *chn_ctl)
{ {
if (relay_chn_output_stop(chn_ctl->output) != ESP_OK) { if (relay_chn_output_stop(chn_ctl->output) != ESP_OK) {
@@ -525,7 +451,8 @@ static void relay_chn_execute_stop(relay_chn_ctl_t *chn_ctl)
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS); relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
} else { } else {
// If the channel was not running one of the run or fwd, issue a free command immediately // If the channel was not running one of the run or fwd, issue a free command immediately
relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_IDLE); // relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_IDLE);
relay_chn_execute_idle(chn_ctl);
} }
} }
@@ -565,21 +492,11 @@ static void relay_chn_execute_flip(relay_chn_ctl_t *chn_ctl)
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS); relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
} }
void relay_chn_execute_idle(relay_chn_ctl_t *chn_ctl) // Dispatch relay channel command
{ void relay_chn_dispatch_cmd(relay_chn_ctl_t *chn_ctl, relay_chn_cmd_t cmd) {
chn_ctl->pending_cmd = RELAY_CHN_CMD_NONE; ESP_LOGD(TAG, "relay_chn_dispatch_cmd: Command: %d", cmd);
// Invalidate the channel's timer if it is active
esp_timer_stop(chn_ctl->inertia_timer);
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_IDLE);
}
static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) switch (cmd) {
{
relay_chn_ctl_t* chn_ctl = *(relay_chn_ctl_t**) event_data;
ESP_RETURN_VOID_ON_FALSE(chn_ctl != NULL, TAG, "event_data is NULL");
ESP_LOGD(TAG, "relay_chn_event_handler: Command: %s", relay_chn_cmd_str(event_id));
switch (event_id) {
case RELAY_CHN_CMD_STOP: case RELAY_CHN_CMD_STOP:
relay_chn_execute_stop(chn_ctl); relay_chn_execute_stop(chn_ctl);
break; break;
@@ -598,6 +515,13 @@ static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_ba
default: default:
ESP_LOGD(TAG, "Unknown relay channel command!"); ESP_LOGD(TAG, "Unknown relay channel command!");
} }
#if RELAY_CHN_ENABLE_TILTING == 1
// Reset the tilt counter when the command is either FORWARD or REVERSE
if (cmd == RELAY_CHN_CMD_FORWARD || cmd == RELAY_CHN_CMD_REVERSE) {
relay_chn_tilt_reset_count(chn_ctl->tilt_ctl);
}
#endif
} }
char *relay_chn_cmd_str(relay_chn_cmd_t cmd) char *relay_chn_cmd_str(relay_chn_cmd_t cmd)

View File

@@ -39,8 +39,6 @@ static const char *TAG = "RELAY_CHN_TILT";
* 100 / (RELAY_CHN_TILT_RUN_MAX_MS - RELAY_CHN_TILT_RUN_MIN_MS) ) * 100 / (RELAY_CHN_TILT_RUN_MAX_MS - RELAY_CHN_TILT_RUN_MIN_MS) )
/**@}*/ /**@}*/
ESP_EVENT_DEFINE_BASE(RELAY_CHN_TILT_CMD_EVENT_BASE);
/// @brief Tilt steps. /// @brief Tilt steps.
typedef enum { typedef enum {
@@ -78,21 +76,6 @@ static relay_chn_tilt_ctl_t tilt_ctl;
#endif #endif
esp_err_t relay_chn_tilt_dispatch_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd)
{
if (cmd == RELAY_CHN_TILT_CMD_NONE) return ESP_ERR_INVALID_ARG;
// Since the event_loop library creates a deep copy of the event data,
// and we need to pass the pointer of the relevant tilt control, here we need
// to pass the pointer to the pointer of the tilt_control (&tilt_ctl) so that
// the pointer value is preserved in the event data.
return esp_event_post_to(relay_chn_event_loop,
RELAY_CHN_TILT_CMD_EVENT_BASE,
cmd,
&tilt_ctl,
sizeof(tilt_ctl), portMAX_DELAY);
}
// Returns the required timing before tilting depending on the last run. // Returns the required timing before tilting depending on the last run.
static uint32_t relay_chn_tilt_get_required_timing_before_tilting(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd) static uint32_t relay_chn_tilt_get_required_timing_before_tilting(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd)
{ {
@@ -561,13 +544,11 @@ static void relay_chn_tilt_execute_pause(relay_chn_tilt_ctl_t *tilt_ctl)
tilt_ctl->step = RELAY_CHN_TILT_STEP_MOVE; tilt_ctl->step = RELAY_CHN_TILT_STEP_MOVE;
} }
static void relay_chn_tilt_event_handler(void *handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) esp_err_t relay_chn_tilt_dispatch_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd)
{ {
relay_chn_tilt_ctl_t* tilt_ctl = *(relay_chn_tilt_ctl_t**) event_data; ESP_LOGD(TAG, "relay_chn_tilt_dispatch_cmd: Command: %d", cmd);
ESP_RETURN_VOID_ON_FALSE(tilt_ctl != NULL, TAG, "event_data is NULL");
ESP_LOGD(TAG, "relay_chn_event_handler: Command: %s", relay_chn_cmd_str(event_id));
switch(event_id) { switch(cmd) {
case RELAY_CHN_TILT_CMD_STOP: case RELAY_CHN_TILT_CMD_STOP:
relay_chn_tilt_execute_stop(tilt_ctl); relay_chn_tilt_execute_stop(tilt_ctl);
break; break;
@@ -582,8 +563,9 @@ static void relay_chn_tilt_event_handler(void *handler_arg, esp_event_base_t eve
relay_chn_update_state(tilt_ctl->chn_ctl, RELAY_CHN_STATE_TILT_REVERSE); relay_chn_update_state(tilt_ctl->chn_ctl, RELAY_CHN_STATE_TILT_REVERSE);
break; break;
default: default:
ESP_LOGW(TAG, "Unexpected relay channel tilt command: %ld!", event_id); ESP_LOGW(TAG, "Unexpected relay channel tilt command: %d!", cmd);
} }
return ESP_OK;
} }
// Timer callback for the relay_chn_tilt_control_t::tilt_timer // Timer callback for the relay_chn_tilt_control_t::tilt_timer
@@ -693,8 +675,10 @@ esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls)
sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY; sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
tilt_count = 0; tilt_count = 0;
#endif // RELAY_CHN_ENABLE_NVS == 1 #endif // RELAY_CHN_ENABLE_NVS == 1
relay_chn_tilt_ctl_init(&tilt_ctls[i], &chn_ctls[i], tilt_count, sensitivity); ret = relay_chn_tilt_ctl_init(&tilt_ctls[i], &chn_ctls[i], tilt_count, sensitivity);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to init tilt control for channel %d", i);
} }
return ESP_OK;
#else #else
sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY; sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
tilt_count = 0; tilt_count = 0;
@@ -704,13 +688,8 @@ esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls)
ret = relay_chn_tilt_load_tilt_count(0, &tilt_count); ret = relay_chn_tilt_load_tilt_count(0, &tilt_count);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt count for channel %d", 0); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt count for channel %d", 0);
#endif // RELAY_CHN_ENABLE_NVS == 1 #endif // RELAY_CHN_ENABLE_NVS == 1
relay_chn_tilt_ctl_init(&tilt_ctl, chn_ctls, tilt_count, sensitivity); return relay_chn_tilt_ctl_init(&tilt_ctl, chn_ctls, tilt_count, sensitivity);
#endif // RELAY_CHN_COUNT > 1 #endif // RELAY_CHN_COUNT > 1
return esp_event_handler_register_with(relay_chn_event_loop,
RELAY_CHN_TILT_CMD_EVENT_BASE,
ESP_EVENT_ANY_ID,
relay_chn_tilt_event_handler, NULL);
} }
void relay_chn_tilt_ctl_deinit(relay_chn_tilt_ctl_t *tilt_ctl) void relay_chn_tilt_ctl_deinit(relay_chn_tilt_ctl_t *tilt_ctl)
@@ -736,8 +715,4 @@ void relay_chn_tilt_deinit()
#else #else
relay_chn_tilt_ctl_deinit(&tilt_ctl); relay_chn_tilt_ctl_deinit(&tilt_ctl);
#endif // RELAY_CHN_COUNT > 1 #endif // RELAY_CHN_COUNT > 1
esp_event_handler_unregister_with(relay_chn_event_loop,
RELAY_CHN_TILT_CMD_EVENT_BASE,
ESP_EVENT_ANY_ID,
relay_chn_tilt_event_handler);
} }