From 40633e03d89e2704de2f2623b9a4dbd091b1cc9a Mon Sep 17 00:00:00 2001 From: ismail Date: Fri, 22 Aug 2025 12:29:07 +0300 Subject: [PATCH 1/6] Add run limit feature for relay channels with NVS support - Introduced configuration options for enabling run limits in Kconfig. - Added APIs to get and set run limits for individual relay channels. - Implemented run limit timer functionality to automatically stop channels. - Updated NVS handling to store and retrieve run limit values. - Enhanced documentation in README and code comments to reflect new feature. Closes #1080 --- Kconfig | 32 +++++++++++++++ README.md | 43 +++++++++++++++++++- include/relay_chn.h | 50 +++++++++++++++++++++++ include/relay_chn_adapter.h | 56 ++++++++++++++++++++++++++ include/relay_chn_defs.h | 7 ++++ private_include/relay_chn_core.h | 14 +++++++ private_include/relay_chn_nvs.h | 20 +++++++++ private_include/relay_chn_priv_types.h | 4 ++ scripts/run_tests.sh | 4 +- src/relay_chn_core.c | 36 +++++++++++++++++ src/relay_chn_ctl_multi.c | 54 +++++++++++++++++++++++++ src/relay_chn_ctl_single.c | 48 ++++++++++++++++++++++ src/relay_chn_nvs.c | 19 +++++++++ 13 files changed, 384 insertions(+), 3 deletions(-) diff --git a/Kconfig b/Kconfig index 638e846..2d743d9 100644 --- a/Kconfig +++ b/Kconfig @@ -17,6 +17,12 @@ menu "Relay Channel Driver Configuration" help Number of relay channels between 1 and 8. + config RELAY_CHN_ENABLE_RUN_LIMIT + bool "Enable run limit for channels" + default n + help + Enable run limit for channels as an extra layer of output protection. + config RELAY_CHN_ENABLE_TILTING bool "Enable tilting on relay channels" default n @@ -61,4 +67,30 @@ menu "Relay Channel NVS Storage Configuration" The name of the custom NVS partition used for storing relay channel configuration. Make sure the name is exactly the same as label defined in the relevant partition table. +endmenu + +menu "Relay Channel Run Limit Configuration" + depends on RELAY_CHN_ENABLE_RUN_LIMIT + + config RELAY_CHN_RUN_LIMIT_MIN_SEC + int "Minimum run limit in seconds" + range 1 60 + default 10 + help + Minimum run limit in seconds for channels. + + config RELAY_CHN_RUN_LIMIT_MAX_SEC + int "Maximum run limit in seconds" + range 60 3600 + default 600 + help + Maximum run limit in seconds for channels. + + config RELAY_CHN_RUN_LIMIT_DEFAULT_SEC + int "Default run limit in seconds" + range 10 3600 + default 60 + help + Default run limit in seconds for channels. + endmenu \ No newline at end of file diff --git a/README.md b/README.md index 46d6b1d..599a024 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,21 @@ An ESP-IDF component for controlling relay channels, specifically designed for d - State monitoring and reporting - Optional sensitivty adjustable tilting feature - Optional NVS storage for persistent configuration +- Optional configurable run limit protection ## Description Each relay channel consists of 2 output relays controlled by 2 GPIO pins. The component provides APIs to control these relay pairs while ensuring safe operation, particularly for driving bipolar motors. To prevent mechanical strain on the motor, the component automatically manages direction changes with a configurable inertia delay, protecting it from abrupt reversals. Hence, the component handles all the required timing between the movement transitions automatically to ensure reliable operation. +The run limit feature provides an additional layer of protection by automatically stopping channels after a configurable time period. This is particularly useful for motor-driven applications where continuous operation beyond a certain duration could cause damage or safety issues. Each channel can have its own run limit setting, and when enabled, the component will automatically stop the channel once it has been running for the specified duration. + It also provides an optional tilting interface per channel base. Tilting makes a channel move with a specific pattern moving with small steps at a time. Tilting is specifically designed for controlling some types of curtains that need to be adjusted to let enter specific amount of day light. Since it operates on relays, the switching frequency is limited to 10Hz which complies with the most of the general purpose relays' requirements. The minimum frequency is 2Hz and the duty cycle is about 10% in all ranges. Another optional feature is NVS storage, which saves the configuration permanently across reboots of the device. These configurations are: - Direction +- Run limit duration - Tilt sensitivity - Last tilt position @@ -33,9 +37,16 @@ Configure the component through menuconfig under "Relay Channel Driver Configura - `CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS`: Time to wait before changing direction (200-1500ms, default: 800ms) - `CONFIG_RELAY_CHN_COUNT`: Number of relay channels (1-8, default: 1) +- `CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT`: Enable run limit protection (default: n) - `CONFIG_RELAY_CHN_ENABLE_TILTING`: Enable tilting interface on all channels. (default: n) - `CONFIG_RELAY_CHN_ENABLE_NVS`: Enable persistent storage in NVS (default: n) +When run limit is enabled (`CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT`), the following configuration options become available: + +- `CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC`: Minimum allowed run limit duration (1-60s, default: 10s) +- `CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC`: Maximum allowed run limit duration (60-3600s, default: 600s) +- `CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC`: Default run limit duration for channels (10-3600s, default: 60s) + When NVS storage is enabled (`CONFIG_RELAY_CHN_ENABLE_NVS`), additional configuration options become available: - `CONFIG_RELAY_CHN_NVS_NAMESPACE`: NVS namespace for storing relay channel data (default: "relay_chn") @@ -225,7 +236,37 @@ relay_chn_direction_t direction = relay_chn_get_direction(0); /* The listener is same for multi mode */ ``` -### 4. Tilting Interface (if enabled) +### 4. Run Limit Control (if enabled) + +For single mode: + +```c +// Assuming CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT is enabled + +// Get current run limit (in seconds) +uint16_t limit = relay_chn_get_run_limit(); + +// Set new run limit (in seconds) +relay_chn_set_run_limit(120); // Set to 120 seconds +``` + +For multi mode: + +```c +// Assuming CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT is enabled + +// Get run limit for channel #0 (in seconds) +uint16_t limit = relay_chn_get_run_limit(0); + +// Set new run limit for specific channels (in seconds) +relay_chn_set_run_limit(0, 120); // Set channel #0 to 120 seconds +relay_chn_set_run_limit(1, 180); // Set channel #1 to 180 seconds +relay_chn_set_run_limit(RELAY_CHN_ID_ALL, 90); // Set all channels to 90 seconds +``` +> [!NOTE] +> When a channel reaches its run limit, it will automatically stop. The run limit timer is reset whenever the channel starts running in either direction. + +### 5. Tilting Interface (if enabled) For single mode: diff --git a/include/relay_chn.h b/include/relay_chn.h index 9912860..9537a4b 100644 --- a/include/relay_chn.h +++ b/include/relay_chn.h @@ -146,6 +146,33 @@ void relay_chn_flip_direction(uint8_t chn_id); */ relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id); +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +/** + * @brief Get the run limit for the specified channel + * + * @param chn_id The ID of the relay channel to query. + * + * @return The run limit value for the relevant channel if the channel ID is valid. + * 0 if the channel ID is invalid. + */ +uint16_t relay_chn_get_run_limit(uint8_t chn_id); + +/** + * @brief Set the run limit for the specified channel + * + * Sets the time limit in seconds for the specified channel. It will not proceed + * if the channel ID is invalid. + * If the time_sec value is lesser than the CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC, + * the value will be set to CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC. + * If the time_sec value is greater than the CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC, + * the value will be set to CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC. + * + * @param chn_id The ID of the relay channel to query. + * @param time_sec The run limit time in seconds. + */ +void relay_chn_set_run_limit(uint8_t chn_id, uint16_t time_sec); +#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1 + #if CONFIG_RELAY_CHN_ENABLE_TILTING == 1 @@ -275,6 +302,29 @@ void relay_chn_flip_direction(void); */ relay_chn_direction_t relay_chn_get_direction(void); +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +/** + * @brief Get the run limit for the channel + * + * @return The run limit value for the channel. + */ +uint16_t relay_chn_get_run_limit(void); + +/** + * @brief Set the run limit for the channel + * + * Sets the time limit in seconds for the channel. It will not proceed + * if the channel ID is invalid. + * If the time_sec value is lesser than the CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC, + * the value will be set to CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC. + * If the time_sec value is greater than the CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC, + * the value will be set to CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC. + * + * @param time_sec The run limit time in seconds. + */ +void relay_chn_set_run_limit(uint16_t time_sec); +#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1 + #if CONFIG_RELAY_CHN_ENABLE_TILTING == 1 diff --git a/include/relay_chn_adapter.h b/include/relay_chn_adapter.h index dd66907..9db6196 100644 --- a/include/relay_chn_adapter.h +++ b/include/relay_chn_adapter.h @@ -101,6 +101,36 @@ static inline relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id) return relay_chn_ctl_get_direction(chn_id); } +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +/** + * @brief Get the run limit for the specified channel + * + * @param chn_id The ID of the relay channel to query. + * + * @return The run limit value for the relevant channel if the channel ID is valid. + * 0 if the channel ID is invalid. + */ +extern uint16_t relay_chn_ctl_get_run_limit(uint8_t chn_id); + +/** + * @brief Set the run limit for the specified channel + * + * @param chn_id The ID of the relay channel to query. + * @param time_sec The run limit time in seconds. + */ +extern void relay_chn_ctl_set_run_limit(uint8_t chn_id, uint16_t time_sec); + +static inline uint16_t relay_chn_get_run_limit(uint8_t chn_id) +{ + return relay_chn_ctl_get_run_limit(chn_id); +} + +static inline void relay_chn_set_run_limit(uint8_t chn_id, uint16_t time_sec) +{ + relay_chn_ctl_set_run_limit(chn_id, time_sec); +} +#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1 + #else /** @@ -179,6 +209,32 @@ static inline relay_chn_direction_t relay_chn_get_direction(void) return relay_chn_ctl_get_direction(); } +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +/** + * @brief Get the run limit for the channel + * + * @return The run limit value for the channel. + */ +extern uint16_t relay_chn_ctl_get_run_limit(void); + +/** + * @brief Set the run limit for the channel + * + * @param time_sec The run limit time in seconds. + */ +extern void relay_chn_ctl_set_run_limit(uint16_t time_sec); + +static inline uint16_t relay_chn_get_run_limit(void) +{ + return relay_chn_ctl_get_run_limit(); +} + +static inline void relay_chn_set_run_limit(uint16_t time_sec) +{ + relay_chn_ctl_set_run_limit(time_sec); +} +#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1 + #endif // RELAY_CHN_COUNT > 1 #ifdef __cplusplus diff --git a/include/relay_chn_defs.h b/include/relay_chn_defs.h index 855905e..9c52236 100644 --- a/include/relay_chn_defs.h +++ b/include/relay_chn_defs.h @@ -15,6 +15,7 @@ extern "C" { #define RELAY_CHN_COUNT CONFIG_RELAY_CHN_COUNT #define RELAY_CHN_ENABLE_TILTING CONFIG_RELAY_CHN_ENABLE_TILTING #define RELAY_CHN_ENABLE_NVS CONFIG_RELAY_CHN_ENABLE_NVS +#define RELAY_CHN_ENABLE_RUN_LIMIT CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT #if RELAY_CHN_ENABLE_NVS == 1 #define RELAY_CHN_NVS_NAMESPACE CONFIG_RELAY_CHN_NVS_NAMESPACE @@ -28,6 +29,12 @@ extern "C" { #define RELAY_CHN_ID_ALL RELAY_CHN_COUNT /*!< Special ID to address all channels */ #endif +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +#define RELAY_CHN_RUN_LIMIT_MIN_SEC CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC +#define RELAY_CHN_RUN_LIMIT_MAX_SEC CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC +#define RELAY_CHN_RUN_LIMIT_DEFAULT_SEC CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC +#endif + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/private_include/relay_chn_core.h b/private_include/relay_chn_core.h index d132e99..3f17928 100644 --- a/private_include/relay_chn_core.h +++ b/private_include/relay_chn_core.h @@ -33,6 +33,20 @@ ESP_EVENT_DECLARE_BASE(RELAY_CHN_CMD_EVENT); */ esp_err_t relay_chn_init_timer(relay_chn_ctl_t *chn_ctl); +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +/** + * @brief Initializes the relay channel run limit timer. + * + * This function creates a timer for the relay channel to handle run time limit. + * Required by *_ctl_* module. + * + * @param chn_ctl Pointer to the relay channel control structure. + * + * @return esp_err_t ESP_OK on success, or an error code on failure. + */ +esp_err_t relay_chn_init_run_limit_timer(relay_chn_ctl_t *chn_ctl); +#endif // RELAY_CHN_ENABLE_RUN_LIMIT + /** * @brief Issues a command to the relay channel. * diff --git a/private_include/relay_chn_nvs.h b/private_include/relay_chn_nvs.h index 7f44cee..09f84f2 100644 --- a/private_include/relay_chn_nvs.h +++ b/private_include/relay_chn_nvs.h @@ -45,6 +45,26 @@ esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t directio */ esp_err_t relay_chn_nvs_get_direction(uint8_t ch, relay_chn_direction_t *direction); +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +/** + * @brief Store relay channel run limit in NVS. + * + * @param[in] ch Channel number. + * @param[in] direction Run limit value to store. + * @return ESP_OK on success, error code otherwise. + */ +esp_err_t relay_chn_nvs_set_run_limit(uint8_t ch, uint16_t time_sec); + +/** + * @brief Retrieve relay channel run limit from NVS. + * + * @param[in] ch Channel number. + * @param[out] direction Pointer to store retrieved run limit value. + * @return ESP_OK on success, error code otherwise. + */ +esp_err_t relay_chn_nvs_get_run_limit(uint8_t ch, uint16_t *time_sec); +#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1 + #ifdef RELAY_CHN_ENABLE_TILTING /** * @brief Store tilt sensitivity in NVS. diff --git a/private_include/relay_chn_priv_types.h b/private_include/relay_chn_priv_types.h index 0967d86..c62a6f0 100644 --- a/private_include/relay_chn_priv_types.h +++ b/private_include/relay_chn_priv_types.h @@ -68,6 +68,10 @@ typedef struct { relay_chn_output_t *output; /*!< Output configuration of the relay channel */ relay_chn_cmd_t pending_cmd; /*!< The command that is pending to be issued */ esp_timer_handle_t inertia_timer; /*!< Timer to handle the opposite direction inertia time */ +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 + esp_timer_handle_t run_limit_timer; /*!< Timer to handle the run limit */ + uint16_t run_limit_sec; /*!< Run limit in seconds */ +#endif #if RELAY_CHN_ENABLE_TILTING == 1 relay_chn_tilt_ctl_t *tilt_ctl; /*!< Pointer to the tilt control structure if tilting is enabled */ #endif diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 5c4d82e..2320339 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -10,7 +10,7 @@ if [[ -z "$IDF_PATH" ]]; then fi # ==== 2. Valid Modes and Defaults ==== -valid_test_tags=("core" "tilt" "listener" "all" "relay_chn" "nvs") +valid_test_tags=("core" "tilt" "listener" "all" "relay_chn" "nvs" "run_limit") arg_tag="all" # Default to 'all' if no tag specified arg_clean=false arg_log=false @@ -24,7 +24,7 @@ print_help() { echo "This script builds and runs tests for the relay_chn component using QEMU." echo "" echo "Arguments:" - echo " -t, --tag [relay_chn|core|tilt|listener|nvs|all] Specify which test tag to run." + echo " -t, --tag [relay_chn|core|tilt|listener|nvs|run_limit|all] Specify which test tag to run." echo "" echo " If no tag is specified, it defaults to 'all'." echo "" diff --git a/src/relay_chn_core.c b/src/relay_chn_core.c index 0f2210d..a117ccf 100644 --- a/src/relay_chn_core.c +++ b/src/relay_chn_core.c @@ -46,6 +46,30 @@ esp_event_loop_handle_t relay_chn_event_loop = NULL; 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 +/* + * Run limit timer callback immediately dispatches a STOP command for the + * relevant channel as soon as the run limit time times out + */ +static void relay_chn_run_limit_timer_cb(void* arg) +{ + relay_chn_ctl_t* chn_ctl = (relay_chn_ctl_t*) arg; + relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_STOP); +} + +esp_err_t relay_chn_init_run_limit_timer(relay_chn_ctl_t *chn_ctl) +{ + char timer_name[32]; + snprintf(timer_name, sizeof(timer_name), "ch_%d_rlimit_timer", chn_ctl->id); + esp_timer_create_args_t timer_args = { + .callback = relay_chn_run_limit_timer_cb, + .arg = chn_ctl, + .name = timer_name + }; + return esp_timer_create(&timer_args, &chn_ctl->run_limit_timer); +} +#endif + // Timer callback function for relay channel direction change inertia. static void relay_chn_timer_cb(void* arg) { @@ -467,6 +491,10 @@ static void relay_chn_execute_stop(relay_chn_ctl_t *chn_ctl) // Invalidate the channel's timer if it is active esp_timer_stop(chn_ctl->inertia_timer); +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 + esp_timer_stop(chn_ctl->run_limit_timer); +#endif + // Save the last run time only if the previous state was either STATE FORWARD // or STATE_REVERSE. Then schedule a free command. if (previous_state == RELAY_CHN_STATE_FORWARD || previous_state == RELAY_CHN_STATE_REVERSE) { @@ -489,6 +517,10 @@ static void relay_chn_execute_forward(relay_chn_ctl_t *chn_ctl) } relay_chn_run_info_set_last_run_cmd(chn_ctl->run_info, RELAY_CHN_CMD_FORWARD); relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_FORWARD); + +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 + relay_chn_start_esp_timer_once(chn_ctl->run_limit_timer, chn_ctl->run_limit_sec * 1000); +#endif } static void relay_chn_execute_reverse(relay_chn_ctl_t *chn_ctl) @@ -499,6 +531,10 @@ static void relay_chn_execute_reverse(relay_chn_ctl_t *chn_ctl) } relay_chn_run_info_set_last_run_cmd(chn_ctl->run_info, RELAY_CHN_CMD_REVERSE); relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_REVERSE); + +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 + relay_chn_start_esp_timer_once(chn_ctl->run_limit_timer, chn_ctl->run_limit_sec * 1000); +#endif } static void relay_chn_execute_flip(relay_chn_ctl_t *chn_ctl) diff --git a/src/relay_chn_ctl_multi.c b/src/relay_chn_ctl_multi.c index 13c97e8..336c5f9 100644 --- a/src/relay_chn_ctl_multi.c +++ b/src/relay_chn_ctl_multi.c @@ -10,6 +10,10 @@ #include "relay_chn_ctl.h" #include "relay_chn_output.h" +#if RELAY_CHN_ENABLE_NVS == 1 +#include "relay_chn_nvs.h" +#endif + static const char *TAG = "RELAY_CHN_CTL"; static relay_chn_ctl_t chn_ctls[RELAY_CHN_COUNT]; @@ -30,6 +34,19 @@ esp_err_t relay_chn_ctl_init(relay_chn_output_t *outputs, relay_chn_run_info_t * chn_ctl->output = output; chn_ctl->run_info = run_info; +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 + uint16_t run_limit_sec = RELAY_CHN_RUN_LIMIT_DEFAULT_SEC; +#if RELAY_CHN_ENABLE_NVS == 1 + // Load run limit value from NVS + ret = relay_chn_nvs_get_run_limit(chn_ctl->id, &run_limit_sec); + if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGE(TAG, "Failed to load run limit from NVS for channel %d with error: %s", i, esp_err_to_name(ret)); + } +#endif + chn_ctl->run_limit_sec = run_limit_sec; + ret = relay_chn_init_run_limit_timer(chn_ctl); + ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize run limit timer"); +#endif ret = relay_chn_init_timer(chn_ctl); // Create direction change inertia timer ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create relay channel timer for channel %d", i); } @@ -44,6 +61,12 @@ void relay_chn_ctl_deinit() esp_timer_delete(chn_ctl->inertia_timer); chn_ctl->inertia_timer = NULL; } +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 + if (chn_ctl->run_limit_timer != NULL) { + esp_timer_delete(chn_ctl->run_limit_timer); + chn_ctl->run_limit_timer = NULL; + } +#endif } } @@ -123,6 +146,37 @@ relay_chn_direction_t relay_chn_ctl_get_direction(uint8_t chn_id) return relay_chn_output_get_direction(chn_ctl->output); } +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +uint16_t relay_chn_ctl_get_run_limit(uint8_t chn_id) +{ + if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) { + ESP_LOGE(TAG, "get_run_limit: Invalid channel ID: %d", chn_id); + return 0; + } + return chn_ctls[chn_id].run_limit_sec; +} + +void relay_chn_ctl_set_run_limit(uint8_t chn_id, uint16_t time_sec) +{ + if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) { + ESP_LOGE(TAG, "set_run_limit: Invalid channel ID: %d", chn_id); + return; + } + + // Check for boundaries + if (time_sec > RELAY_CHN_RUN_LIMIT_MAX_SEC) + time_sec = RELAY_CHN_RUN_LIMIT_MAX_SEC; + else if (time_sec < RELAY_CHN_RUN_LIMIT_MIN_SEC) + time_sec = RELAY_CHN_RUN_LIMIT_MIN_SEC; + + chn_ctls[chn_id].run_limit_sec = time_sec; + +#if RELAY_CHN_ENABLE_NVS == 1 + relay_chn_nvs_set_run_limit(chn_id, time_sec); +#endif +} +#endif + relay_chn_ctl_t *relay_chn_ctl_get(uint8_t chn_id) { if (!relay_chn_is_channel_id_valid(chn_id)) { diff --git a/src/relay_chn_ctl_single.c b/src/relay_chn_ctl_single.c index 0435b33..a56f226 100644 --- a/src/relay_chn_ctl_single.c +++ b/src/relay_chn_ctl_single.c @@ -4,11 +4,17 @@ * SPDX-License-Identifier: MIT */ +#include "esp_check.h" #include "relay_chn_priv_types.h" #include "relay_chn_core.h" #include "relay_chn_ctl.h" #include "relay_chn_output.h" +#if RELAY_CHN_ENABLE_NVS == 1 +#include "relay_chn_nvs.h" +#endif + +static const char *TAG = "RELAY_CHN_CTL"; static relay_chn_ctl_t chn_ctl; @@ -21,6 +27,20 @@ esp_err_t relay_chn_ctl_init(relay_chn_output_t *output, relay_chn_run_info_t *r chn_ctl.pending_cmd = RELAY_CHN_CMD_NONE; chn_ctl.output = output; chn_ctl.run_info = run_info; +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 + uint16_t run_limit_sec = RELAY_CHN_RUN_LIMIT_DEFAULT_SEC; + esp_err_t ret; +#if RELAY_CHN_ENABLE_NVS == 1 + // Load run limit value from NVS + ret = relay_chn_nvs_get_run_limit(chn_ctl.id, &run_limit_sec); + if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGE(TAG, "Failed to load run limit from NVS with error: %s", esp_err_to_name(ret)); + } +#endif + chn_ctl.run_limit_sec = run_limit_sec; + ret = relay_chn_init_run_limit_timer(&chn_ctl); + ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize run limit timer"); +#endif return relay_chn_init_timer(&chn_ctl); // Create direction change inertia timer } @@ -31,6 +51,12 @@ void relay_chn_ctl_deinit() esp_timer_delete(chn_ctl.inertia_timer); chn_ctl.inertia_timer = NULL; } +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 + if (chn_ctl.run_limit_timer != NULL) { + esp_timer_delete(chn_ctl.run_limit_timer); + chn_ctl.run_limit_timer = NULL; + } +#endif } /* relay_chn APIs */ @@ -68,6 +94,28 @@ relay_chn_direction_t relay_chn_ctl_get_direction() { return relay_chn_output_get_direction(chn_ctl.output); } + +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +uint16_t relay_chn_ctl_get_run_limit() +{ + return chn_ctl.run_limit_sec; +} + +void relay_chn_ctl_set_run_limit(uint16_t time_sec) +{ + // Check for boundaries + if (time_sec > RELAY_CHN_RUN_LIMIT_MAX_SEC) + time_sec = RELAY_CHN_RUN_LIMIT_MAX_SEC; + else if (time_sec < RELAY_CHN_RUN_LIMIT_MIN_SEC) + time_sec = RELAY_CHN_RUN_LIMIT_MIN_SEC; + + chn_ctl.run_limit_sec = time_sec; + +#if RELAY_CHN_ENABLE_NVS == 1 + relay_chn_nvs_set_run_limit(chn_ctl.id, time_sec); +#endif +} +#endif /* relay_chn APIs */ relay_chn_ctl_t *relay_chn_ctl_get() diff --git a/src/relay_chn_nvs.c b/src/relay_chn_nvs.c index e152693..04ec8df 100644 --- a/src/relay_chn_nvs.c +++ b/src/relay_chn_nvs.c @@ -8,6 +8,9 @@ #include "relay_chn_nvs.h" #define RELAY_CHN_KEY_DIR "dir" /*!< Direction key */ +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +#define RELAY_CHN_KEY_RLIM(ch) "rlim_%d" /*!< Run limit key */ +#endif #ifdef RELAY_CHN_ENABLE_TILTING #define RELAY_CHN_KEY_TSENS(ch) "tsens_%d" /*!< Tilt sensitivity key */ #define RELAY_CHN_KEY_TCNT(ch) "tcnt_%d" /*!< Tilt count key */ @@ -69,6 +72,22 @@ esp_err_t relay_chn_nvs_get_direction(uint8_t ch, relay_chn_direction_t *directi return ESP_OK; } +#if RELAY_CHN_ENABLE_RUN_LIMIT == 1 +esp_err_t relay_chn_nvs_set_run_limit(uint8_t ch, uint16_t time_sec) +{ + esp_err_t ret = nvs_set_u16(relay_chn_nvs, RELAY_CHN_KEY_RLIM(ch), time_sec); + ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set run limit for channel %d", ch); + return nvs_commit(relay_chn_nvs); +} + +esp_err_t relay_chn_nvs_get_run_limit(uint8_t ch, uint16_t *time_sec) +{ + ESP_RETURN_ON_FALSE(time_sec != NULL, ESP_ERR_INVALID_ARG, TAG, "Run limit value pointer is NULL"); + + return nvs_get_u16(relay_chn_nvs, RELAY_CHN_KEY_RLIM(ch), time_sec); +} +#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1 + #ifdef RELAY_CHN_ENABLE_TILTING esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity) { From 29803c063e5607e49ab0747d72e1927208ca25c1 Mon Sep 17 00:00:00 2001 From: ismail Date: Fri, 22 Aug 2025 12:41:58 +0300 Subject: [PATCH 2/6] Enhance unit test default sdkconfig files The sdkconfig.defaults files were enhanced to test the component against all individual configurations for more granularity, as well as with all combinations to ensure consistency and integrity across all configurations. --- ...config.defaults => sdkconfig.defaults.multi} | 4 +--- ..._nvs => sdkconfig.defaults.multi.custom_nvs} | 3 +-- test_apps/sdkconfig.defaults.multi.full | 17 +++++++++++++++++ test_apps/sdkconfig.defaults.multi.nvs | 8 ++++++++ test_apps/sdkconfig.defaults.multi.run_limit | 9 +++++++++ test_apps/sdkconfig.defaults.multi.tilt | 8 ++++++++ test_apps/sdkconfig.defaults.single | 5 +---- test_apps/sdkconfig.defaults.single.custom_nvs | 2 -- test_apps/sdkconfig.defaults.single.full | 16 ++++++++++++++++ test_apps/sdkconfig.defaults.single.nvs | 7 +++++++ test_apps/sdkconfig.defaults.single.run_limit | 8 ++++++++ test_apps/sdkconfig.defaults.single.tilt | 7 +++++++ 12 files changed, 83 insertions(+), 11 deletions(-) rename test_apps/{sdkconfig.defaults => sdkconfig.defaults.multi} (69%) rename test_apps/{sdkconfig.defaults.custom_nvs => sdkconfig.defaults.multi.custom_nvs} (79%) create mode 100644 test_apps/sdkconfig.defaults.multi.full create mode 100644 test_apps/sdkconfig.defaults.multi.nvs create mode 100644 test_apps/sdkconfig.defaults.multi.run_limit create mode 100644 test_apps/sdkconfig.defaults.multi.tilt create mode 100644 test_apps/sdkconfig.defaults.single.full create mode 100644 test_apps/sdkconfig.defaults.single.nvs create mode 100644 test_apps/sdkconfig.defaults.single.run_limit create mode 100644 test_apps/sdkconfig.defaults.single.tilt diff --git a/test_apps/sdkconfig.defaults b/test_apps/sdkconfig.defaults.multi similarity index 69% rename from test_apps/sdkconfig.defaults rename to test_apps/sdkconfig.defaults.multi index 53c4d00..6262a4c 100644 --- a/test_apps/sdkconfig.defaults +++ b/test_apps/sdkconfig.defaults.multi @@ -4,6 +4,4 @@ CONFIG_ESP_TASK_WDT_INIT=n # Relay Channel Driver Default Configuration for Testing # Keep this as short as possible for tests CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 -CONFIG_RELAY_CHN_COUNT=2 -CONFIG_RELAY_CHN_ENABLE_TILTING=y -CONFIG_RELAY_CHN_ENABLE_NVS=y \ No newline at end of file +CONFIG_RELAY_CHN_COUNT=8 \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.custom_nvs b/test_apps/sdkconfig.defaults.multi.custom_nvs similarity index 79% rename from test_apps/sdkconfig.defaults.custom_nvs rename to test_apps/sdkconfig.defaults.multi.custom_nvs index cc1df53..040c093 100644 --- a/test_apps/sdkconfig.defaults.custom_nvs +++ b/test_apps/sdkconfig.defaults.multi.custom_nvs @@ -9,7 +9,6 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/part_nvs.csv" # Relay Channel Driver Default Configuration for Testing # Keep this as short as possible for tests CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 -CONFIG_RELAY_CHN_COUNT=2 -CONFIG_RELAY_CHN_ENABLE_TILTING=y +CONFIG_RELAY_CHN_COUNT=8 CONFIG_RELAY_CHN_ENABLE_NVS=y CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=y \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.multi.full b/test_apps/sdkconfig.defaults.multi.full new file mode 100644 index 0000000..0388bf1 --- /dev/null +++ b/test_apps/sdkconfig.defaults.multi.full @@ -0,0 +1,17 @@ +# Disable task WDT for tests +CONFIG_ESP_TASK_WDT_INIT=n + +# Partition configuration +CONFIG_PARTITION_TABLE_SINGLE_APP=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/part_nvs.csv" + +# Relay Channel Driver Default Configuration for Testing +# Keep this as short as possible for tests +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 +CONFIG_RELAY_CHN_COUNT=8 +CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT=y +CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC=1 +CONFIG_RELAY_CHN_ENABLE_TILTING=y +CONFIG_RELAY_CHN_ENABLE_NVS=y +CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=y \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.multi.nvs b/test_apps/sdkconfig.defaults.multi.nvs new file mode 100644 index 0000000..5e3bbdd --- /dev/null +++ b/test_apps/sdkconfig.defaults.multi.nvs @@ -0,0 +1,8 @@ +# Disable task WDT for tests +CONFIG_ESP_TASK_WDT_INIT=n + +# Relay Channel Driver Default Configuration for Testing +# Keep this as short as possible for tests +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 +CONFIG_RELAY_CHN_COUNT=8 +CONFIG_RELAY_CHN_ENABLE_NVS=y \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.multi.run_limit b/test_apps/sdkconfig.defaults.multi.run_limit new file mode 100644 index 0000000..b5d1df4 --- /dev/null +++ b/test_apps/sdkconfig.defaults.multi.run_limit @@ -0,0 +1,9 @@ +# Disable task WDT for tests +CONFIG_ESP_TASK_WDT_INIT=n + +# Relay Channel Driver Default Configuration for Testing +# Keep this as short as possible for tests +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 +CONFIG_RELAY_CHN_COUNT=8 +CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT=y +CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC=1 \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.multi.tilt b/test_apps/sdkconfig.defaults.multi.tilt new file mode 100644 index 0000000..e3c4d79 --- /dev/null +++ b/test_apps/sdkconfig.defaults.multi.tilt @@ -0,0 +1,8 @@ +# Disable task WDT for tests +CONFIG_ESP_TASK_WDT_INIT=n + +# Relay Channel Driver Default Configuration for Testing +# Keep this as short as possible for tests +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 +CONFIG_RELAY_CHN_COUNT=8 +CONFIG_RELAY_CHN_ENABLE_TILTING=y \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.single b/test_apps/sdkconfig.defaults.single index b468a54..00de340 100644 --- a/test_apps/sdkconfig.defaults.single +++ b/test_apps/sdkconfig.defaults.single @@ -3,7 +3,4 @@ CONFIG_ESP_TASK_WDT_INIT=n # Relay Channel Driver Default Configuration for Testing # Keep this as short as possible for tests -CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 -CONFIG_RELAY_CHN_COUNT=1 -CONFIG_RELAY_CHN_ENABLE_TILTING=y -CONFIG_RELAY_CHN_ENABLE_NVS=y \ No newline at end of file +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.single.custom_nvs b/test_apps/sdkconfig.defaults.single.custom_nvs index 9cbcb0c..46f1e8e 100644 --- a/test_apps/sdkconfig.defaults.single.custom_nvs +++ b/test_apps/sdkconfig.defaults.single.custom_nvs @@ -9,7 +9,5 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/part_nvs.csv" # Relay Channel Driver Default Configuration for Testing # Keep this as short as possible for tests CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 -CONFIG_RELAY_CHN_COUNT=1 -CONFIG_RELAY_CHN_ENABLE_TILTING=y CONFIG_RELAY_CHN_ENABLE_NVS=y CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=y \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.single.full b/test_apps/sdkconfig.defaults.single.full new file mode 100644 index 0000000..79085de --- /dev/null +++ b/test_apps/sdkconfig.defaults.single.full @@ -0,0 +1,16 @@ +# Disable task WDT for tests +CONFIG_ESP_TASK_WDT_INIT=n + +# Partition configuration +CONFIG_PARTITION_TABLE_SINGLE_APP=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/part_nvs.csv" + +# Relay Channel Driver Default Configuration for Testing +# Keep this as short as possible for tests +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 +CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT=y +CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC=1 +CONFIG_RELAY_CHN_ENABLE_TILTING=y +CONFIG_RELAY_CHN_ENABLE_NVS=y +CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=y \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.single.nvs b/test_apps/sdkconfig.defaults.single.nvs new file mode 100644 index 0000000..d8a62fd --- /dev/null +++ b/test_apps/sdkconfig.defaults.single.nvs @@ -0,0 +1,7 @@ +# Disable task WDT for tests +CONFIG_ESP_TASK_WDT_INIT=n + +# Relay Channel Driver Default Configuration for Testing +# Keep this as short as possible for tests +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 +CONFIG_RELAY_CHN_ENABLE_NVS=y \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.single.run_limit b/test_apps/sdkconfig.defaults.single.run_limit new file mode 100644 index 0000000..71c2df9 --- /dev/null +++ b/test_apps/sdkconfig.defaults.single.run_limit @@ -0,0 +1,8 @@ +# Disable task WDT for tests +CONFIG_ESP_TASK_WDT_INIT=n + +# Relay Channel Driver Default Configuration for Testing +# Keep this as short as possible for tests +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 +CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT=y +CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC=1 \ No newline at end of file diff --git a/test_apps/sdkconfig.defaults.single.tilt b/test_apps/sdkconfig.defaults.single.tilt new file mode 100644 index 0000000..e111deb --- /dev/null +++ b/test_apps/sdkconfig.defaults.single.tilt @@ -0,0 +1,7 @@ +# Disable task WDT for tests +CONFIG_ESP_TASK_WDT_INIT=n + +# Relay Channel Driver Default Configuration for Testing +# Keep this as short as possible for tests +CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 +CONFIG_RELAY_CHN_ENABLE_TILTING=y \ No newline at end of file From fb4f34e895875c08530ef81c5d3afd4546e6b65b Mon Sep 17 00:00:00 2001 From: ismail Date: Fri, 22 Aug 2025 12:42:53 +0300 Subject: [PATCH 3/6] Add and execute unit tests for run limit feature --- test_apps/main/test_app_main.c | 10 ++- test_apps/main/test_relay_chn_core_multi.c | 98 ++++++++++++++++++++- test_apps/main/test_relay_chn_core_single.c | 78 +++++++++++++++- test_apps/main/test_relay_chn_nvs_multi.c | 17 ++++ test_apps/main/test_relay_chn_nvs_single.c | 16 ++++ test_apps/sdkconfig | 22 +++-- 6 files changed, 232 insertions(+), 9 deletions(-) diff --git a/test_apps/main/test_app_main.c b/test_apps/main/test_app_main.c index edabae1..460659c 100644 --- a/test_apps/main/test_app_main.c +++ b/test_apps/main/test_app_main.c @@ -28,6 +28,7 @@ void tearDown() reset_channels_to_idle_state(); } +#if CONFIG_RELAY_CHN_ENABLE_NVS == 1 static void test_nvs_flash_init(void) { esp_err_t ret; @@ -52,9 +53,11 @@ static void test_nvs_flash_init(void) } } #endif - TEST_ESP_OK(ret); +TEST_ESP_OK(ret); } +#endif +#if CONFIG_RELAY_CHN_ENABLE_NVS == 1 static void test_nvs_flash_deinit(void) { esp_err_t ret; @@ -65,11 +68,14 @@ static void test_nvs_flash_deinit(void) #endif TEST_ESP_OK(ret); } +#endif void app_main(void) { +#if CONFIG_RELAY_CHN_ENABLE_NVS == 1 // Init NVS once for all tests test_nvs_flash_init(); +#endif // Create relay_chn once for all tests TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count)); @@ -92,8 +98,10 @@ void app_main(void) // Destroy relay_chn relay_chn_destroy(); +#if CONFIG_RELAY_CHN_ENABLE_NVS == 1 // Deinit NVS test_nvs_flash_deinit(); +#endif ESP_LOGI(TEST_TAG, "All tests complete."); diff --git a/test_apps/main/test_relay_chn_core_multi.c b/test_apps/main/test_relay_chn_core_multi.c index 8b35c5c..b7904dd 100644 --- a/test_apps/main/test_relay_chn_core_multi.c +++ b/test_apps/main/test_relay_chn_core_multi.c @@ -344,4 +344,100 @@ TEST_CASE("Direction flip handles invalid channel ID gracefully", "[relay_chn][c relay_chn_flip_direction(invalid_ch); // Call with an invalid ID TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(invalid_ch)); -} \ No newline at end of file +} + +#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1 +#define TEST_RUN_LIMIT_SEC 5 +#define TEST_SHORT_RUN_LIMIT_SEC 2 +// ### Run Limit Tests +TEST_CASE("Test run limit initialization", "[relay_chn][run_limit]") +{ + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + // Should initialize with default value + TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC, relay_chn_get_run_limit(i)); + } +} + +TEST_CASE("Test run limit setting boundaries", "[relay_chn][run_limit]") +{ + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + // Test minimum boundary + relay_chn_set_run_limit(i, CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC - 1); + TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC, relay_chn_get_run_limit(i)); + + // Test maximum boundary + relay_chn_set_run_limit(i, CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC + 1); + TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC, relay_chn_get_run_limit(i)); + + // Test valid value + relay_chn_set_run_limit(i, TEST_RUN_LIMIT_SEC); + TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit(i)); + } +} + +TEST_CASE("Test run limit stops channel after timeout", "[relay_chn][run_limit]") +{ + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + // Set a short run limit for testing + relay_chn_set_run_limit(i, TEST_SHORT_RUN_LIMIT_SEC); + } + + relay_chn_run_forward(RELAY_CHN_ID_ALL); + + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + // Check running forward + TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i)); + } + + // Wait for run limit timeout + vTaskDelay(pdMS_TO_TICKS(TEST_SHORT_RUN_LIMIT_SEC * 1000 + test_delay_margin_ms)); + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i)); + } +} + +TEST_CASE("Test run limit reset on direction change and time out finally", "[relay_chn][run_limit]") +{ + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + // Set a short run limit + relay_chn_set_run_limit(i, TEST_SHORT_RUN_LIMIT_SEC); + + // Start running forward + relay_chn_run_forward(i); + } + + vTaskDelay(1000 / portTICK_PERIOD_MS); // Wait 1 second + + // Change direction before timeout + relay_chn_run_reverse(RELAY_CHN_ID_ALL); + + // Wait for the inertia period (after which the reverse command will be dispatched) + vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); + + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i)); + } + + // Timer should time out and stop the channel after the run limit time + vTaskDelay(pdMS_TO_TICKS(TEST_SHORT_RUN_LIMIT_SEC * 1000 + test_delay_margin_ms)); + + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i)); + } +} + +TEST_CASE("Test run limit persistence across stop/start", "[relay_chn][run_limit]") +{ + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + // Set initial run limit + relay_chn_set_run_limit(i, TEST_RUN_LIMIT_SEC); + + // Stop and start channel + relay_chn_stop(i); + relay_chn_run_forward(i); + + // Run limit should persist + TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit(i)); + } +} +#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1 \ No newline at end of file diff --git a/test_apps/main/test_relay_chn_core_single.c b/test_apps/main/test_relay_chn_core_single.c index 3c3f4a8..b21823f 100644 --- a/test_apps/main/test_relay_chn_core_single.c +++ b/test_apps/main/test_relay_chn_core_single.c @@ -171,4 +171,80 @@ TEST_CASE("Flipping a running channel stops it and flips direction", "[relay_chn vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction()); -} \ No newline at end of file +} + +#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1 +#define TEST_RUN_LIMIT_SEC 5 +#define TEST_SHORT_RUN_LIMIT_SEC 2 +// ### Run Limit Tests +TEST_CASE("Test run limit initialization", "[relay_chn][run_limit]") +{ + // Should initialize with default value + TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC, relay_chn_get_run_limit()); +} + +TEST_CASE("Test run limit setting boundaries", "[relay_chn][run_limit]") +{ + // Test minimum boundary + relay_chn_set_run_limit(CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC - 1); + TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC, relay_chn_get_run_limit()); + + // Test maximum boundary + relay_chn_set_run_limit(CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC + 1); + TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC, relay_chn_get_run_limit()); + + // Test valid value + relay_chn_set_run_limit(TEST_RUN_LIMIT_SEC); + TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit()); +} + +TEST_CASE("Test run limit stops channel after timeout", "[relay_chn][run_limit]") +{ + // Set a short run limit for testing + relay_chn_set_run_limit(TEST_SHORT_RUN_LIMIT_SEC); + + // Start running forward + relay_chn_run_forward(); + TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state()); + + // Wait for run limit timeout + vTaskDelay(pdMS_TO_TICKS(TEST_SHORT_RUN_LIMIT_SEC * 1000 + test_delay_margin_ms)); + TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state()); +} + +TEST_CASE("Test run limit reset on direction change and time out finally", "[relay_chn][run_limit]") +{ + // Set a short run limit + relay_chn_set_run_limit(TEST_SHORT_RUN_LIMIT_SEC); + + // Start running forward + relay_chn_run_forward(); + vTaskDelay(1000 / portTICK_PERIOD_MS); // Wait 1 second + + // Change direction before timeout + relay_chn_run_reverse(); + + // Wait for the inertia period (after which the reverse command will be dispatched) + vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); + + TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state()); + + // Timer should time out and stop the channel after the run limit time + vTaskDelay(pdMS_TO_TICKS(TEST_SHORT_RUN_LIMIT_SEC * 1000 + test_delay_margin_ms)); + + TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state()); +} + +TEST_CASE("Test run limit persistence across stop/start", "[relay_chn][run_limit]") +{ + // Set initial run limit + relay_chn_set_run_limit(TEST_RUN_LIMIT_SEC); + + // Stop and start channel + relay_chn_stop(); + relay_chn_run_forward(); + + // Run limit should persist + TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit()); +} +#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1 \ No newline at end of file diff --git a/test_apps/main/test_relay_chn_nvs_multi.c b/test_apps/main/test_relay_chn_nvs_multi.c index b21b3d5..d591dbb 100644 --- a/test_apps/main/test_relay_chn_nvs_multi.c +++ b/test_apps/main/test_relay_chn_nvs_multi.c @@ -84,6 +84,23 @@ TEST_CASE("Test relay_chn_nvs_erase_all", "[relay_chn][nvs]") TEST_ESP_OK(relay_chn_nvs_deinit()); } +#ifdef CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT +TEST_CASE("Test run limit setting and getting", "[relay_chn][nvs][run_limit]") +{ + TEST_ESP_OK(relay_chn_nvs_init()); + + const uint16_t run_limit_sec = 32; + for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { + TEST_ESP_OK(relay_chn_nvs_set_run_limit(i, run_limit_sec)); + + uint16_t run_limit_read; + TEST_ESP_OK(relay_chn_nvs_get_run_limit(i, &run_limit_read)); + TEST_ASSERT_EQUAL(run_limit_sec, run_limit_read); + } + TEST_ESP_OK(relay_chn_nvs_deinit()); +} +#endif + #ifdef RELAY_CHN_ENABLE_TILTING TEST_CASE("Test sensitivity setting and getting", "[relay_chn][nvs][tilt]") { diff --git a/test_apps/main/test_relay_chn_nvs_single.c b/test_apps/main/test_relay_chn_nvs_single.c index b6fb376..2872d5c 100644 --- a/test_apps/main/test_relay_chn_nvs_single.c +++ b/test_apps/main/test_relay_chn_nvs_single.c @@ -77,6 +77,22 @@ TEST_CASE("Test relay_chn_nvs_erase_all", "[relay_chn][nvs]") TEST_ESP_OK(relay_chn_nvs_deinit()); } +#ifdef CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT +TEST_CASE("Test run limit setting and getting", "[relay_chn][nvs][run_limit]") +{ + TEST_ESP_OK(relay_chn_nvs_init()); + + const uint16_t run_limit_sec = 32; + TEST_ESP_OK(relay_chn_nvs_set_run_limit(0, run_limit_sec)); + + uint16_t run_limit_read; + TEST_ESP_OK(relay_chn_nvs_get_run_limit(0, &run_limit_read)); + TEST_ASSERT_EQUAL(run_limit_sec, run_limit_read); + + TEST_ESP_OK(relay_chn_nvs_deinit()); +} +#endif + #ifdef RELAY_CHN_ENABLE_TILTING TEST_CASE("Test sensitivity setting and getting", "[relay_chn][nvs][tilt]") { diff --git a/test_apps/sdkconfig b/test_apps/sdkconfig index f47128a..7810c58 100644 --- a/test_apps/sdkconfig +++ b/test_apps/sdkconfig @@ -395,13 +395,13 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 # # Partition Table # -CONFIG_PARTITION_TABLE_SINGLE_APP=y +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set # CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set # CONFIG_PARTITION_TABLE_TWO_OTA is not set # CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set -# CONFIG_PARTITION_TABLE_CUSTOM is not set -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/part_nvs.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions/part_nvs.csv" CONFIG_PARTITION_TABLE_OFFSET=0x8000 CONFIG_PARTITION_TABLE_MD5=y # end of Partition Table @@ -1268,7 +1268,8 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y # Relay Channel Driver Configuration # CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200 -CONFIG_RELAY_CHN_COUNT=2 +CONFIG_RELAY_CHN_COUNT=8 +CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT=y CONFIG_RELAY_CHN_ENABLE_TILTING=y CONFIG_RELAY_CHN_ENABLE_NVS=y # end of Relay Channel Driver Configuration @@ -1277,8 +1278,17 @@ CONFIG_RELAY_CHN_ENABLE_NVS=y # Relay Channel NVS Storage Configuration # CONFIG_RELAY_CHN_NVS_NAMESPACE="relay_chn" -# CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION is not set +CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=y +CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME="app_data" # end of Relay Channel NVS Storage Configuration + +# +# Relay Channel Run Limit Configuration +# +CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC=1 +CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC=600 +CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC=60 +# end of Relay Channel Run Limit Configuration # end of Component config # CONFIG_IDF_EXPERIMENTAL_FEATURES is not set From e73c205e3d33d0be0afc135f341f402d01696f70 Mon Sep 17 00:00:00 2001 From: ismail Date: Fri, 22 Aug 2025 15:06:37 +0300 Subject: [PATCH 4/6] Optimize event loop resource size The event loop queue and task stack size is optimized to be determined by config factors. Fixes #1083 --- src/relay_chn_core.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/relay_chn_core.c b/src/relay_chn_core.c index a117ccf..d3913a5 100644 --- a/src/relay_chn_core.c +++ b/src/relay_chn_core.c @@ -22,6 +22,26 @@ #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"; @@ -99,10 +119,10 @@ esp_err_t relay_chn_init_timer(relay_chn_ctl_t *chn_ctl) static esp_err_t relay_chn_create_event_loop() { esp_event_loop_args_t loop_args = { - .queue_size = RELAY_CHN_COUNT * 8, + .queue_size = RELAY_CHN_EVENT_LOOP_QUEUE_SIZE, .task_name = "relay_chn_event_loop", .task_priority = ESP_TASKD_EVENT_PRIO - 1, - .task_stack_size = 2048, + .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); From 7a0f9b1420fb252572e9f46e71d5be3d2e5554d9 Mon Sep 17 00:00:00 2001 From: ismail Date: Fri, 22 Aug 2025 17:41:08 +0300 Subject: [PATCH 5/6] 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 --- CMakeLists.txt | 2 +- include/relay_chn.h | 3 - private_include/relay_chn_core.h | 12 +--- private_include/relay_chn_tilt.h | 4 +- src/relay_chn_core.c | 118 ++++++------------------------- src/relay_chn_tilt.c | 43 +++-------- 6 files changed, 34 insertions(+), 148 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7cda68..6f103e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,4 +23,4 @@ endif() idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${include_dirs} PRIV_INCLUDE_DIRS ${priv_include_dirs} - REQUIRES driver esp_timer esp_event nvs_flash) + REQUIRES driver esp_timer nvs_flash) diff --git a/include/relay_chn.h b/include/relay_chn.h index 9537a4b..de3b94c 100644 --- a/include/relay_chn.h +++ b/include/relay_chn.h @@ -9,9 +9,6 @@ * To prevent mechanical strain on the motor, the component automatically manages direction changes * 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 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 diff --git a/private_include/relay_chn_core.h b/private_include/relay_chn_core.h index 3f17928..3577b91 100644 --- a/private_include/relay_chn_core.h +++ b/private_include/relay_chn_core.h @@ -8,8 +8,6 @@ #include "esp_err.h" #include "esp_log.h" -#include "esp_event_base.h" -#include "esp_event.h" #include "esp_timer.h" #include "relay_chn_defs.h" #include "relay_chn_types.h" @@ -19,9 +17,6 @@ extern "C" { #endif -/// Event base used by *_core, *_ctl, and *_tilt modules. -ESP_EVENT_DECLARE_BASE(RELAY_CHN_CMD_EVENT); - /** * @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); /** - * @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 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); #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 } #endif \ No newline at end of file diff --git a/private_include/relay_chn_tilt.h b/private_include/relay_chn_tilt.h index ab1b5c9..30db7aa 100644 --- a/private_include/relay_chn_tilt.h +++ b/private_include/relay_chn_tilt.h @@ -15,7 +15,7 @@ extern "C" { /** * @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. * * @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. * - * 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. */ void relay_chn_tilt_deinit(void); diff --git a/src/relay_chn_core.c b/src/relay_chn_core.c index d3913a5..48a6321 100644 --- a/src/relay_chn_core.c +++ b/src/relay_chn_core.c @@ -22,31 +22,9 @@ #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"; -ESP_EVENT_DEFINE_BASE(RELAY_CHN_CMD_EVENT); - // Structure to hold a listener entry in the linked list. 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. 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 /* * 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); } -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_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); 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 // Initialize the tilt feature #if RELAY_CHN_COUNT > 1 @@ -196,10 +143,6 @@ void relay_chn_destroy(void) relay_chn_nvs_deinit(); #endif - // Destroy the event loop - esp_event_loop_delete(relay_chn_event_loop); - relay_chn_event_loop = NULL; - // Free the listeners while (listCURRENT_LIST_LENGTH(&relay_chn_listener_list) > 0) { 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 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 +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) { 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); } else { // 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); } -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); -} +// Dispatch relay channel command +void relay_chn_dispatch_cmd(relay_chn_ctl_t *chn_ctl, relay_chn_cmd_t cmd) { + ESP_LOGD(TAG, "relay_chn_dispatch_cmd: Command: %d", cmd); -static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) -{ - 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) { + switch (cmd) { case RELAY_CHN_CMD_STOP: relay_chn_execute_stop(chn_ctl); break; @@ -598,6 +515,13 @@ static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_ba default: 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) diff --git a/src/relay_chn_tilt.c b/src/relay_chn_tilt.c index c1f4a2d..7eaf97c 100644 --- a/src/relay_chn_tilt.c +++ b/src/relay_chn_tilt.c @@ -39,8 +39,6 @@ static const char *TAG = "RELAY_CHN_TILT"; * 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. typedef enum { @@ -78,21 +76,6 @@ static relay_chn_tilt_ctl_t tilt_ctl; #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. 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; } -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_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)); + ESP_LOGD(TAG, "relay_chn_tilt_dispatch_cmd: Command: %d", cmd); - switch(event_id) { + switch(cmd) { case RELAY_CHN_TILT_CMD_STOP: relay_chn_tilt_execute_stop(tilt_ctl); 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); break; 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 @@ -693,8 +675,10 @@ esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls) sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY; tilt_count = 0; #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 sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY; 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); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt count for channel %d", 0); #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 - - 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) @@ -736,8 +715,4 @@ void relay_chn_tilt_deinit() #else relay_chn_tilt_ctl_deinit(&tilt_ctl); #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); } \ No newline at end of file From cb38f71d8e39d55a7cf0f79e965a308b9c976987 Mon Sep 17 00:00:00 2001 From: ismail Date: Fri, 22 Aug 2025 17:42:24 +0300 Subject: [PATCH 6/6] Optimize a flip test case and execute tests upon removing esp_event --- test_apps/main/test_relay_chn_core_multi.c | 2 -- test_apps/sdkconfig | 11 ----------- 2 files changed, 13 deletions(-) diff --git a/test_apps/main/test_relay_chn_core_multi.c b/test_apps/main/test_relay_chn_core_multi.c index b7904dd..1abcd7b 100644 --- a/test_apps/main/test_relay_chn_core_multi.c +++ b/test_apps/main/test_relay_chn_core_multi.c @@ -322,12 +322,10 @@ TEST_CASE("Flipping a running channel stops it and flips direction", "[relay_chn // 1. Start channel running and verify state relay_chn_run_forward(ch); - vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch)); // 2. Flip the direction while running relay_chn_flip_direction(ch); - vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Give time for events to process // 3. The channel should stop as part of the flip process TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(ch)); diff --git a/test_apps/sdkconfig b/test_apps/sdkconfig index 7810c58..bc3790f 100644 --- a/test_apps/sdkconfig +++ b/test_apps/sdkconfig @@ -643,14 +643,6 @@ CONFIG_SPI_SLAVE_ISR_IN_IRAM=y # CONFIG_UART_ISR_IN_IRAM is not set # end of ESP-Driver:UART Configurations -# -# Event Loop Library -# -# CONFIG_ESP_EVENT_LOOP_PROFILING is not set -CONFIG_ESP_EVENT_POST_FROM_ISR=y -CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y -# end of Event Loop Library - # # Hardware Settings # @@ -1330,9 +1322,6 @@ CONFIG_STACK_CHECK_NONE=y # CONFIG_WARN_WRITE_STRINGS is not set CONFIG_ADC2_DISABLE_DAC=y # CONFIG_MCPWM_ISR_IN_IRAM is not set -# CONFIG_EVENT_LOOP_PROFILING is not set -CONFIG_POST_EVENTS_FROM_ISR=y -CONFIG_POST_EVENTS_FROM_IRAM_ISR=y # CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4