opt/1085-optimization-and-cleanup #37
4
.gitignore
vendored
4
.gitignore
vendored
@@ -56,6 +56,10 @@ tools/test_apps/**/build_*_*/
|
|||||||
tools/test_apps/**/sdkconfig
|
tools/test_apps/**/sdkconfig
|
||||||
tools/test_apps/**/sdkconfig.old
|
tools/test_apps/**/sdkconfig.old
|
||||||
|
|
||||||
|
# autogenerated config files
|
||||||
|
sdkconfig
|
||||||
|
test_apps/sdkconfig
|
||||||
|
|
||||||
TEST_LOGS/
|
TEST_LOGS/
|
||||||
build_summary_*.xml
|
build_summary_*.xml
|
||||||
|
|
||||||
|
|||||||
2
.vscode/c_cpp_properties.json
vendored
2
.vscode/c_cpp_properties.json
vendored
@@ -3,7 +3,7 @@
|
|||||||
{
|
{
|
||||||
"name": "ESP-IDF",
|
"name": "ESP-IDF",
|
||||||
"compilerPath": "${config:idf.toolsPath}/tools/riscv32-esp-elf/esp-14.2.0_20241119/riscv32-esp-elf/bin/riscv32-esp-elf-gcc",
|
"compilerPath": "${config:idf.toolsPath}/tools/riscv32-esp-elf/esp-14.2.0_20241119/riscv32-esp-elf/bin/riscv32-esp-elf-gcc",
|
||||||
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
|
"compileCommands": "${workspaceFolder}/test_apps/build/compile_commands.json",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"${config:idf.espIdfPath}/components/**",
|
"${config:idf.espIdfPath}/components/**",
|
||||||
"${config:idf.espIdfPathWin}/components/**",
|
"${config:idf.espIdfPathWin}/components/**",
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ set(priv_include_dirs "private_include")
|
|||||||
|
|
||||||
set(srcs "src/relay_chn_core.c"
|
set(srcs "src/relay_chn_core.c"
|
||||||
"src/relay_chn_output.c"
|
"src/relay_chn_output.c"
|
||||||
"src/relay_chn_run_info.c")
|
"src/relay_chn_run_info.c"
|
||||||
|
"src/relay_chn_notify.c")
|
||||||
|
|
||||||
if(CONFIG_RELAY_CHN_ENABLE_TILTING)
|
if(CONFIG_RELAY_CHN_ENABLE_TILTING)
|
||||||
list(APPEND srcs "src/relay_chn_tilt.c")
|
list(APPEND srcs "src/relay_chn_tilt.c")
|
||||||
|
|||||||
61
README.md
61
README.md
@@ -31,6 +31,16 @@ Another optional feature is NVS storage, which saves the configuration permanent
|
|||||||
- Tilt sensitivity
|
- Tilt sensitivity
|
||||||
- Last tilt position
|
- Last tilt position
|
||||||
|
|
||||||
|
### NVS Operation Details
|
||||||
|
When NVS storage is enabled (CONFIG_RELAY_CHN_ENABLE_NVS=y), the component creates a dedicated background task to manage all NVS write operations. This design has important implications for how you use the NVS-related functions:
|
||||||
|
- **Asynchronous Writes:** All `set` operations (e.g., `relay_chn_flip_direction()`, `relay_chn_set_run_limit()`) are asynchronous. They add the write request to a queue and return immediately, preventing the calling task from being blocked.
|
||||||
|
- **Synchronous Reads:** All get operations (e.g., `relay_chn_get_direction()`) are synchronous. They read the value directly from the NVS storage and will block the calling task until the read is complete.
|
||||||
|
- **Batched Commits:** To optimize performance and minimize flash wear, the NVS task uses a batching mechanism for writes. It collects multiple write requests and commits them to the NVS flash in a single operation after a short period of inactivity (typically 200ms).
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Due to the asynchronous and batched nature of write operations, a call to a get function may not immediately reflect a value that was just written by a set function. Your application should account for this small delay.
|
||||||
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Configure the component through menuconfig under "Relay Channel Driver Configuration":
|
Configure the component through menuconfig under "Relay Channel Driver Configuration":
|
||||||
@@ -180,26 +190,29 @@ For multi mode
|
|||||||
// Run channel #0 forward
|
// Run channel #0 forward
|
||||||
relay_chn_run_forward(0);
|
relay_chn_run_forward(0);
|
||||||
// Run all channels forward
|
// Run all channels forward
|
||||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
relay_chn_run_forward_all();
|
||||||
|
|
||||||
// Run channel #1 reverse
|
// Run channel #1 reverse
|
||||||
relay_chn_run_reverse(1);
|
relay_chn_run_reverse(1);
|
||||||
// Run all channels reverse
|
// Run all channels reverse
|
||||||
relay_chn_run_reverse(RELAY_CHN_ID_ALL);
|
relay_chn_run_reverse_all();
|
||||||
|
|
||||||
// Stop channel #1
|
// Stop channel #1
|
||||||
relay_chn_stop(1);
|
relay_chn_stop(1);
|
||||||
// Stop all channels
|
// Stop all channels
|
||||||
relay_chn_stop(RELAY_CHN_ID_ALL);
|
relay_chn_stop_all();
|
||||||
|
|
||||||
// Flip direction of channel #0
|
// Flip direction of channel #0
|
||||||
relay_chn_flip_direction(0);
|
relay_chn_flip_direction(0);
|
||||||
// Flip direction of all channels
|
// Flip direction of all channels
|
||||||
relay_chn_flip_direction(RELAY_CHN_ID_ALL);
|
relay_chn_flip_direction_all();
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Monitor channel state
|
### 3. Monitor channel state
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Listener callbacks are executed from the context of the notification dispatcher task. To ensure system responsiveness and prevent event loss, callbacks must be lightweight and non-blocking. Avoid any long-running operations or functions that may block, such as `vTaskDelay()` or semaphore takes with long timeouts, inside the callback.
|
||||||
|
|
||||||
For single mode:
|
For single mode:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
@@ -227,12 +240,21 @@ For multi mode:
|
|||||||
```c
|
```c
|
||||||
// Get channel #0 state
|
// Get channel #0 state
|
||||||
relay_chn_state_t state = relay_chn_get_state(0);
|
relay_chn_state_t state = relay_chn_get_state(0);
|
||||||
|
|
||||||
|
// Get states for all channels
|
||||||
|
relay_chn_state_t states[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
relay_chn_get_states(states);
|
||||||
|
|
||||||
// Get the string representation of the state of the channel #0
|
// Get the string representation of the state of the channel #0
|
||||||
char *state_str = relay_chn_get_state_str(0);
|
char *state_str = relay_chn_get_state_str(0);
|
||||||
|
|
||||||
// Get channel #0 direction
|
// Get channel #0 direction
|
||||||
relay_chn_direction_t direction = relay_chn_get_direction(0);
|
relay_chn_direction_t direction = relay_chn_get_direction(0);
|
||||||
|
|
||||||
|
// Get directions for all channels
|
||||||
|
relay_chn_direction_t directions[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
relay_chn_get_directions(directions);
|
||||||
|
|
||||||
/* The listener is same for multi mode */
|
/* The listener is same for multi mode */
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -261,7 +283,11 @@ uint16_t limit = relay_chn_get_run_limit(0);
|
|||||||
// Set new run limit for specific channels (in seconds)
|
// 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(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(1, 180); // Set channel #1 to 180 seconds
|
||||||
relay_chn_set_run_limit(RELAY_CHN_ID_ALL, 90); // Set all channels to 90 seconds
|
relay_chn_set_run_limit_all_with(90); // Set all channels to 90 seconds
|
||||||
|
|
||||||
|
// Assuming the CONFIG_RELAY_CHN_COUNT is 4
|
||||||
|
uint16_t limits_sec[CONFIG_RELAY_CHN_COUNT] = { 30, 35, 40, 45 };
|
||||||
|
relay_chn_set_run_limit_all(limits_sec); // Set all channels according to the array
|
||||||
```
|
```
|
||||||
> [!NOTE]
|
> [!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.
|
> 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.
|
||||||
@@ -286,7 +312,7 @@ relay_chn_tilt_reverse();
|
|||||||
relay_chn_tilt_stop();
|
relay_chn_tilt_stop();
|
||||||
|
|
||||||
// Set tilting sensitivity (sensitivity as percentage)
|
// Set tilting sensitivity (sensitivity as percentage)
|
||||||
relay_chn_tilt_sensitivity_set(90);
|
relay_chn_tilt_set_sensitivity(90);
|
||||||
|
|
||||||
// Get tilting sensitivity (sensitivty as percentage)
|
// Get tilting sensitivity (sensitivty as percentage)
|
||||||
uint8_t sensitivity = relay_chn_tilt_get_sensitivity();
|
uint8_t sensitivity = relay_chn_tilt_get_sensitivity();
|
||||||
@@ -299,27 +325,34 @@ For multi mode:
|
|||||||
|
|
||||||
// Start tilting automatically on channel #0
|
// Start tilting automatically on channel #0
|
||||||
relay_chn_tilt_auto(0);
|
relay_chn_tilt_auto(0);
|
||||||
relay_chn_tilt_auto(RELAY_CHN_ID_ALL); // on all channels
|
relay_chn_tilt_auto_all(); // on all channels
|
||||||
|
|
||||||
// Tilt forward on channel #1
|
// Tilt forward on channel #1
|
||||||
relay_chn_tilt_forward(1);
|
relay_chn_tilt_forward(1);
|
||||||
relay_chn_tilt_forward(RELAY_CHN_ID_ALL);
|
relay_chn_tilt_forward_all();
|
||||||
|
|
||||||
// Tilt reverse on channel #2
|
// Tilt reverse on channel #2
|
||||||
relay_chn_tilt_reverse(2);
|
relay_chn_tilt_reverse(2);
|
||||||
relay_chn_tilt_reverse(RELAY_CHN_ID_ALL);
|
relay_chn_tilt_reverse_all();
|
||||||
|
|
||||||
// Stop tilting on channel #0
|
// Stop tilting on channel #0
|
||||||
relay_chn_tilt_stop(0);
|
relay_chn_tilt_stop(0);
|
||||||
relay_chn_tilt_stop(RELAY_CHN_ID_ALL);
|
relay_chn_tilt_stop_all();
|
||||||
|
|
||||||
// Set tilting sensitivity (sensitivity as percentage) for channel #0
|
// Set tilting sensitivity (sensitivity as percentage) for channel #0
|
||||||
relay_chn_tilt_sensitivity_set(0, 90);
|
relay_chn_tilt_set_sensitivity(0, 90);
|
||||||
relay_chn_tilt_sensitivity_set(RELAY_CHN_ID_ALL, 90);
|
relay_chn_tilt_set_sensitivity_all_with(90);
|
||||||
|
|
||||||
|
// Assuming the CONFIG_RELAY_CHN_COUNT is 4
|
||||||
|
uint8_t sensitivities[CONFIG_RELAY_CHN_COUNT] = { 90, 85, 80, 75 };
|
||||||
|
relay_chn_tilt_set_sensitivity_all(sensitivity); // Set all channels according to the array
|
||||||
|
|
||||||
|
// Get tilt sensitivity for channel #0
|
||||||
|
uint8_t sensitivity = relay_chn_tilt_get_sensitivity(0);
|
||||||
|
|
||||||
// Get tilting sensitivity (sensitivty as percentage)
|
// Get tilting sensitivity (sensitivty as percentage)
|
||||||
uint8_t sensitivity;
|
uint8_t sensitivities[CONFIG_RELAY_CHN_COUNT];
|
||||||
relay_chn_tilt_get_sensitivity(0, &sensitivity, sizeof(sensitivity));
|
relay_chn_tilt_get_sensitivity_all(sensitivities);
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "relay_chn_defs.h"
|
|
||||||
#include "relay_chn_types.h"
|
#include "relay_chn_types.h"
|
||||||
#include "relay_chn_adapter.h"
|
#include "relay_chn_adapter.h"
|
||||||
|
|
||||||
@@ -64,7 +63,19 @@ esp_err_t relay_chn_register_listener(relay_chn_state_listener_t listener);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_unregister_listener(relay_chn_state_listener_t listener);
|
void relay_chn_unregister_listener(relay_chn_state_listener_t listener);
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
/**
|
||||||
|
* @brief Get the default tilting sensitivity for the relay channel.
|
||||||
|
*
|
||||||
|
* This function retrieves the default sensitivity for the relay channel's automatic
|
||||||
|
* tilting mechanism.
|
||||||
|
*
|
||||||
|
* @return Sensitivity value in percentage: 0 - 100%.
|
||||||
|
*/
|
||||||
|
uint8_t relay_chn_tilt_get_default_sensitivity(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
/**
|
/**
|
||||||
* @brief Get the state of the specified relay channel.
|
* @brief Get the state of the specified relay channel.
|
||||||
*
|
*
|
||||||
@@ -75,6 +86,18 @@ void relay_chn_unregister_listener(relay_chn_state_listener_t listener);
|
|||||||
*/
|
*/
|
||||||
relay_chn_state_t relay_chn_get_state(uint8_t chn_id);
|
relay_chn_state_t relay_chn_get_state(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current state of all relay channels.
|
||||||
|
*
|
||||||
|
* This function populates an array with the current states of all configured
|
||||||
|
* relay channels. The caller must ensure the `states` array is large enough
|
||||||
|
* to hold `CONFIG_RELAY_CHN_COUNT` elements.
|
||||||
|
*
|
||||||
|
* @param states Pointer to an array where the states will be stored.
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `states` is NULL.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_get_state_all(relay_chn_state_t *states);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the state string of the specified relay channel.
|
* @brief Get the state string of the specified relay channel.
|
||||||
*
|
*
|
||||||
@@ -100,6 +123,14 @@ char *relay_chn_get_state_str(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_run_forward(uint8_t chn_id);
|
void relay_chn_run_forward(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Commands all configured relay channels to run in the forward direction.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and issues a command
|
||||||
|
* to each to move in the forward direction.
|
||||||
|
*/
|
||||||
|
void relay_chn_ctl_run_forward_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Runs the relay channel in reverse.
|
* @brief Runs the relay channel in reverse.
|
||||||
*
|
*
|
||||||
@@ -109,6 +140,14 @@ void relay_chn_run_forward(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_run_reverse(uint8_t chn_id);
|
void relay_chn_run_reverse(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Commands all configured relay channels to run in the reverse direction.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and issues a command
|
||||||
|
* to each to move in the reverse direction.
|
||||||
|
*/
|
||||||
|
void relay_chn_ctl_run_reverse_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stops the relay channel specified by the channel ID.
|
* @brief Stops the relay channel specified by the channel ID.
|
||||||
*
|
*
|
||||||
@@ -120,6 +159,14 @@ void relay_chn_run_reverse(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_stop(uint8_t chn_id);
|
void relay_chn_stop(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Commands all configured relay channels to stop.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and issues a command
|
||||||
|
* to each to stop any ongoing movement.
|
||||||
|
*/
|
||||||
|
void relay_chn_ctl_stop_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Flips the direction of the specified relay channel.
|
* @brief Flips the direction of the specified relay channel.
|
||||||
*
|
*
|
||||||
@@ -131,6 +178,14 @@ void relay_chn_stop(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_flip_direction(uint8_t chn_id);
|
void relay_chn_flip_direction(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flips the logical direction of all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and swaps the
|
||||||
|
* physical GPIO pins assigned to the forward and reverse directions for each.
|
||||||
|
*/
|
||||||
|
void relay_chn_ctl_flip_direction_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the direction of the specified relay channel.
|
* @brief Get the direction of the specified relay channel.
|
||||||
*
|
*
|
||||||
@@ -143,7 +198,19 @@ void relay_chn_flip_direction(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
relay_chn_direction_t relay_chn_get_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 Gets the current logical direction of all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function populates an array with the current logical directions of all
|
||||||
|
* configured relay channels. The caller must ensure the `directions` array is
|
||||||
|
* large enough to hold `CONFIG_RELAY_CHN_COUNT` elements.
|
||||||
|
*
|
||||||
|
* @param directions Pointer to an array where the directions will be stored.
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `directions` is NULL.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_get_direction_all(relay_chn_direction_t *directions);
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
/**
|
/**
|
||||||
* @brief Get the run limit for the specified channel
|
* @brief Get the run limit for the specified channel
|
||||||
*
|
*
|
||||||
@@ -154,24 +221,61 @@ relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
uint16_t relay_chn_get_run_limit(uint8_t chn_id);
|
uint16_t relay_chn_get_run_limit(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the configured run limits for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function populates an array with the run limits (in seconds) of all
|
||||||
|
* configured relay channels. The caller must ensure the `limits_sec` array is
|
||||||
|
* large enough to hold `CONFIG_RELAY_CHN_COUNT` elements.
|
||||||
|
*
|
||||||
|
* @param limits_sec Pointer to an array where the run limits will be stored.
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `limits_sec` is NULL.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_get_run_limit_all(uint16_t *limits_sec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the run limit for the specified channel
|
* @brief Set the run limit for the specified channel
|
||||||
*
|
*
|
||||||
* Sets the time limit in seconds for the specified channel. It will not proceed
|
* Sets the time limit in seconds for the specified channel. It will not proceed
|
||||||
* if the channel ID is invalid.
|
* if the channel ID is invalid.
|
||||||
* If the time_sec value is lesser than the CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC,
|
* If the limit_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.
|
* 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,
|
* If the limit_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.
|
* 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 chn_id The ID of the relay channel to query.
|
||||||
* @param time_sec The run limit time in seconds.
|
* @param limit_sec The run limit time in seconds.
|
||||||
*/
|
*/
|
||||||
void relay_chn_set_run_limit(uint8_t chn_id, uint16_t time_sec);
|
void relay_chn_set_run_limit(uint8_t chn_id, uint16_t limit_sec);
|
||||||
#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the run limits for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and sets their
|
||||||
|
* run limits based on the values provided in the `limits_sec` array. Each value
|
||||||
|
* will be clamped within the configured `RELAY_CHN_RUN_LIMIT_MIN_SEC` and
|
||||||
|
* `RELAY_CHN_RUN_LIMIT_MAX_SEC` boundaries. The new run limits are persisted
|
||||||
|
* in NVS if enabled.
|
||||||
|
*
|
||||||
|
* @param limits_sec Pointer to an array containing the desired run limits in seconds.
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `limits_sec` is NULL.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_set_run_limit_all(uint16_t *limits_sec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a single run limit value for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function sets the same `limit_sec` value for all configured relay channels.
|
||||||
|
* The value will be clamped within the configured `RELAY_CHN_RUN_LIMIT_MIN_SEC`
|
||||||
|
* and `RELAY_CHN_RUN_LIMIT_MAX_SEC` boundaries.
|
||||||
|
* @param limit_sec The desired run limit in seconds to apply to all channels.
|
||||||
|
* @return ESP_OK on success.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_set_run_limit_all_with(uint16_t limit_sec);
|
||||||
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables automatic tilting for the specified relay channel.
|
* @brief Enables automatic tilting for the specified relay channel.
|
||||||
@@ -184,6 +288,14 @@ void relay_chn_set_run_limit(uint8_t chn_id, uint16_t time_sec);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_tilt_auto(uint8_t chn_id);
|
void relay_chn_tilt_auto(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initiates an automatic tilt operation for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and initiates an
|
||||||
|
* automatic tilt operation for each, based on their individual last run commands.
|
||||||
|
*/
|
||||||
|
void relay_chn_tilt_auto_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tilts the specified relay channel forward.
|
* @brief Tilts the specified relay channel forward.
|
||||||
*
|
*
|
||||||
@@ -193,6 +305,11 @@ void relay_chn_tilt_auto(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_tilt_forward(uint8_t chn_id);
|
void relay_chn_tilt_forward(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initiates a forward tilt operation for all configured relay channels.
|
||||||
|
*/
|
||||||
|
void relay_chn_tilt_forward_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tilts the specified relay channel reverse.
|
* @brief Tilts the specified relay channel reverse.
|
||||||
*
|
*
|
||||||
@@ -202,6 +319,11 @@ void relay_chn_tilt_forward(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_tilt_reverse(uint8_t chn_id);
|
void relay_chn_tilt_reverse(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initiates a reverse tilt operation for all configured relay channels.
|
||||||
|
*/
|
||||||
|
void relay_chn_tilt_reverse_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stops the tilting action on the specified relay channel.
|
* @brief Stops the tilting action on the specified relay channel.
|
||||||
*
|
*
|
||||||
@@ -211,6 +333,11 @@ void relay_chn_tilt_reverse(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_tilt_stop(uint8_t chn_id);
|
void relay_chn_tilt_stop(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops any ongoing tilt operation for all configured relay channels.
|
||||||
|
*/
|
||||||
|
void relay_chn_tilt_stop_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the tilting sensitivity for the specified relay channel.
|
* @brief Sets the tilting sensitivity for the specified relay channel.
|
||||||
*
|
*
|
||||||
@@ -222,6 +349,33 @@ void relay_chn_tilt_stop(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_tilt_set_sensitivity(uint8_t chn_id, uint8_t sensitivity);
|
void relay_chn_tilt_set_sensitivity(uint8_t chn_id, uint8_t sensitivity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the tilt sensitivity for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function sets the tilt sensitivity for each channel based on the values
|
||||||
|
* provided in the `sensitivities` array. Each sensitivity value (0-100%)
|
||||||
|
* determines the `move_time_ms` and `pause_time_ms` for tilt operations.
|
||||||
|
* The new sensitivities are persisted in NVS if enabled.
|
||||||
|
*
|
||||||
|
* @param sensitivities Pointer to an array containing the desired tilt sensitivities.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: Success
|
||||||
|
* - ESP_ERR_INVALID_ARG: When sensitivities parameter is NULL
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_tilt_set_sensitivity_all(uint8_t *sensitivities);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a single tilt sensitivity value for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function sets the same `sensitivity` value for all configured relay channels.
|
||||||
|
* The sensitivity value (0-100%) determines the `move_time_ms` and `pause_time_ms`
|
||||||
|
* for tilt operations. The new sensitivities are persisted in NVS if enabled.
|
||||||
|
*
|
||||||
|
* @param sensitivity The desired tilt sensitivity in percentage (0-100) to apply to all channels.
|
||||||
|
*/
|
||||||
|
void relay_chn_tilt_set_sensitivity_all_with(uint8_t sensitivity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the tilting sensitivity for the specified relay channel.
|
* @brief Gets the tilting sensitivity for the specified relay channel.
|
||||||
*
|
*
|
||||||
@@ -235,11 +389,23 @@ void relay_chn_tilt_set_sensitivity(uint8_t chn_id, uint8_t sensitivity);
|
|||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_tilt_get_sensitivity(uint8_t chn_id, uint8_t *sensitivity, size_t length);
|
uint8_t relay_chn_tilt_get_sensitivity(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current tilt sensitivities for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function populates an array with the current tilt sensitivities (0-100%)
|
||||||
|
* of all configured relay channels. The caller must ensure the `sensitivity` array
|
||||||
|
* is large enough to hold `CONFIG_RELAY_CHN_COUNT` elements.
|
||||||
|
*
|
||||||
|
* @param sensitivity Pointer to an array where the sensitivities will be stored.
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `sensitivity` is NULL.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_tilt_get_sensitivity_all(uint8_t *sensitivities);
|
||||||
|
|
||||||
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
|
||||||
#else // RELAY_CHN_COUNT > 1
|
#else // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the state of the relay channel.
|
* @brief Get the state of the relay channel.
|
||||||
@@ -299,7 +465,7 @@ void relay_chn_flip_direction(void);
|
|||||||
*/
|
*/
|
||||||
relay_chn_direction_t relay_chn_get_direction(void);
|
relay_chn_direction_t relay_chn_get_direction(void);
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
/**
|
/**
|
||||||
* @brief Get the run limit for the channel
|
* @brief Get the run limit for the channel
|
||||||
*
|
*
|
||||||
@@ -312,18 +478,18 @@ uint16_t relay_chn_get_run_limit(void);
|
|||||||
*
|
*
|
||||||
* Sets the time limit in seconds for the channel. It will not proceed
|
* Sets the time limit in seconds for the channel. It will not proceed
|
||||||
* if the channel ID is invalid.
|
* if the channel ID is invalid.
|
||||||
* If the time_sec value is lesser than the CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC,
|
* If the limit_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.
|
* 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,
|
* If the limit_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.
|
* the value will be set to CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC.
|
||||||
*
|
*
|
||||||
* @param time_sec The run limit time in seconds.
|
* @param limit_sec The run limit time in seconds.
|
||||||
*/
|
*/
|
||||||
void relay_chn_set_run_limit(uint16_t time_sec);
|
void relay_chn_set_run_limit(uint16_t limit_sec);
|
||||||
#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables automatic tilting for the relay channel.
|
* @brief Enables automatic tilting for the relay channel.
|
||||||
@@ -377,7 +543,7 @@ uint8_t relay_chn_tilt_get_sensitivity(void);
|
|||||||
|
|
||||||
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
* An adapter header to expose the appropriate API functions to the public API
|
* An adapter header to expose the appropriate API functions to the public API
|
||||||
* depending on the RELAY_CHN_COUNT value which determines single or multi mode.
|
* depending on the CONFIG_RELAY_CHN_COUNT value which determines single or multi mode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -13,7 +13,37 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
/**
|
||||||
|
* @brief Register a channel state change listener.
|
||||||
|
*
|
||||||
|
* @param listener A function that implements relay_chn_state_listener_t interface.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: Success
|
||||||
|
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||||
|
* - ESP_ERR_NO_MEM: No enough memory
|
||||||
|
* - ESP_FAIL: General failure
|
||||||
|
*/
|
||||||
|
extern esp_err_t relay_chn_notify_add_listener(relay_chn_state_listener_t listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister a channel state change listener.
|
||||||
|
*
|
||||||
|
* @param listener A function that implements relay_chn_state_listener_t interface.
|
||||||
|
*/
|
||||||
|
extern void relay_chn_notify_remove_listener(relay_chn_state_listener_t listener);
|
||||||
|
|
||||||
|
static inline esp_err_t relay_chn_register_listener(relay_chn_state_listener_t listener)
|
||||||
|
{
|
||||||
|
return relay_chn_notify_add_listener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void relay_chn_unregister_listener(relay_chn_state_listener_t listener)
|
||||||
|
{
|
||||||
|
relay_chn_notify_remove_listener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
/**
|
/**
|
||||||
* @brief Get the current state of a relay channel.
|
* @brief Get the current state of a relay channel.
|
||||||
*
|
*
|
||||||
@@ -22,6 +52,19 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
extern relay_chn_state_t relay_chn_ctl_get_state(uint8_t chn_id);
|
extern relay_chn_state_t relay_chn_ctl_get_state(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current state of all relay channels.
|
||||||
|
*
|
||||||
|
* This function populates an array with the current states of all configured
|
||||||
|
* relay channels. The caller must ensure the `states` array is large enough
|
||||||
|
* to hold `CONFIG_RELAY_CHN_COUNT` elements.
|
||||||
|
*
|
||||||
|
* @param states Pointer to an array where the states will be stored.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `states` is NULL.
|
||||||
|
*/
|
||||||
|
extern esp_err_t relay_chn_ctl_get_state_all(relay_chn_state_t *states);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get string representation of a relay channel's state.
|
* @brief Get string representation of a relay channel's state.
|
||||||
*
|
*
|
||||||
@@ -33,31 +76,62 @@ extern char *relay_chn_ctl_get_state_str(uint8_t chn_id);
|
|||||||
/**
|
/**
|
||||||
* @brief Run a relay channel in forward direction.
|
* @brief Run a relay channel in forward direction.
|
||||||
*
|
*
|
||||||
* @param[in] chn_id Channel ID to run forward, or RELAY_CHN_ID_ALL for all channels.
|
* @param[in] chn_id Channel ID to run forward.
|
||||||
*/
|
*/
|
||||||
extern void relay_chn_ctl_run_forward(uint8_t chn_id);
|
extern void relay_chn_ctl_run_forward(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Commands all configured relay channels to run in the forward direction.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and issues a command
|
||||||
|
* to each to move in the forward direction.
|
||||||
|
*/
|
||||||
|
extern void relay_chn_ctl_run_forward_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Run a relay channel in reverse direction.
|
* @brief Run a relay channel in reverse direction.
|
||||||
*
|
*
|
||||||
* @param[in] chn_id Channel ID to run reverse, or RELAY_CHN_ID_ALL for all channels.
|
* @param[in] chn_id Channel ID to run reverse.
|
||||||
*/
|
*/
|
||||||
extern void relay_chn_ctl_run_reverse(uint8_t chn_id);
|
extern void relay_chn_ctl_run_reverse(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Commands all configured relay channels to run in the reverse direction.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and issues a command
|
||||||
|
* to each to move in the reverse direction.
|
||||||
|
*/
|
||||||
|
extern void relay_chn_ctl_run_reverse_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stop a relay channel.
|
* @brief Stop a relay channel.
|
||||||
*
|
*
|
||||||
* @param[in] chn_id Channel ID to stop, or RELAY_CHN_ID_ALL for all channels.
|
* @param[in] chn_id Channel ID to stop.
|
||||||
*/
|
*/
|
||||||
extern void relay_chn_ctl_stop(uint8_t chn_id);
|
extern void relay_chn_ctl_stop(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Commands all configured relay channels to stop.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and issues a command to each to stop any ongoing movement.
|
||||||
|
*/
|
||||||
|
extern void relay_chn_ctl_stop_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Flip the running direction of a relay channel.
|
* @brief Flip the running direction of a relay channel.
|
||||||
*
|
*
|
||||||
* @param[in] chn_id Channel ID to flip direction for, or RELAY_CHN_ID_ALL for all channels.
|
* @param[in] chn_id Channel ID to flip direction for.
|
||||||
*/
|
*/
|
||||||
extern void relay_chn_ctl_flip_direction(uint8_t chn_id);
|
extern void relay_chn_ctl_flip_direction(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flips the logical direction of all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and swaps the
|
||||||
|
* physical GPIO pins assigned to the forward and reverse directions for each.
|
||||||
|
*/
|
||||||
|
extern void relay_chn_ctl_flip_direction_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the current direction of a relay channel.
|
* @brief Get the current direction of a relay channel.
|
||||||
*
|
*
|
||||||
@@ -66,11 +140,28 @@ extern void relay_chn_ctl_flip_direction(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
extern relay_chn_direction_t relay_chn_ctl_get_direction(uint8_t chn_id);
|
extern relay_chn_direction_t relay_chn_ctl_get_direction(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current logical direction of all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function populates an array with the current logical directions of all
|
||||||
|
* configured relay channels. The caller must ensure the `directions` array is
|
||||||
|
* large enough to hold `CONFIG_RELAY_CHN_COUNT` elements.
|
||||||
|
*
|
||||||
|
* @param directions Pointer to an array where the directions will be stored.
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `directions` is NULL.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_get_direction_all(relay_chn_direction_t *directions);
|
||||||
|
|
||||||
static inline relay_chn_state_t relay_chn_get_state(uint8_t chn_id)
|
static inline relay_chn_state_t relay_chn_get_state(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
return relay_chn_ctl_get_state(chn_id);
|
return relay_chn_ctl_get_state(chn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline esp_err_t relay_chn_get_state_all(relay_chn_state_t *states)
|
||||||
|
{
|
||||||
|
return relay_chn_ctl_get_state_all(states);
|
||||||
|
}
|
||||||
|
|
||||||
static inline char *relay_chn_get_state_str(uint8_t chn_id)
|
static inline char *relay_chn_get_state_str(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
return relay_chn_ctl_get_state_str(chn_id);
|
return relay_chn_ctl_get_state_str(chn_id);
|
||||||
@@ -81,27 +172,52 @@ static inline void relay_chn_run_forward(uint8_t chn_id)
|
|||||||
relay_chn_ctl_run_forward(chn_id);
|
relay_chn_ctl_run_forward(chn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void relay_chn_run_forward_all(void)
|
||||||
|
{
|
||||||
|
relay_chn_ctl_run_forward_all();
|
||||||
|
}
|
||||||
|
|
||||||
static inline void relay_chn_run_reverse(uint8_t chn_id)
|
static inline void relay_chn_run_reverse(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
relay_chn_ctl_run_reverse(chn_id);
|
relay_chn_ctl_run_reverse(chn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void relay_chn_run_reverse_all(void)
|
||||||
|
{
|
||||||
|
relay_chn_ctl_run_reverse_all();
|
||||||
|
}
|
||||||
|
|
||||||
static inline void relay_chn_stop(uint8_t chn_id)
|
static inline void relay_chn_stop(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
relay_chn_ctl_stop(chn_id);
|
relay_chn_ctl_stop(chn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void relay_chn_stop_all(void)
|
||||||
|
{
|
||||||
|
relay_chn_ctl_stop_all();
|
||||||
|
}
|
||||||
|
|
||||||
static inline void relay_chn_flip_direction(uint8_t chn_id)
|
static inline void relay_chn_flip_direction(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
relay_chn_ctl_flip_direction(chn_id);
|
relay_chn_ctl_flip_direction(chn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void relay_chn_flip_direction_all(void)
|
||||||
|
{
|
||||||
|
relay_chn_ctl_flip_direction_all();
|
||||||
|
}
|
||||||
|
|
||||||
static inline relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id)
|
static inline relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
return relay_chn_ctl_get_direction(chn_id);
|
return relay_chn_ctl_get_direction(chn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
static inline esp_err_t relay_chn_get_direction_all(relay_chn_direction_t *directions)
|
||||||
|
{
|
||||||
|
return relay_chn_ctl_get_direction_all(directions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
/**
|
/**
|
||||||
* @brief Get the run limit for the specified channel
|
* @brief Get the run limit for the specified channel
|
||||||
*
|
*
|
||||||
@@ -112,24 +228,76 @@ static inline relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id)
|
|||||||
*/
|
*/
|
||||||
extern uint16_t relay_chn_ctl_get_run_limit(uint8_t chn_id);
|
extern uint16_t relay_chn_ctl_get_run_limit(uint8_t chn_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the configured run limits for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function populates an array with the run limits (in seconds) of all
|
||||||
|
* configured relay channels. The caller must ensure the `limits_sec` array is
|
||||||
|
* large enough to hold `CONFIG_RELAY_CHN_COUNT` elements.
|
||||||
|
*
|
||||||
|
* @param limits_sec Pointer to an array where the run limits will be stored.
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `limits_sec` is NULL.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_get_run_limit_all(uint16_t *limits_sec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the run limit for the specified channel
|
* @brief Set the run limit for the specified channel
|
||||||
*
|
*
|
||||||
* @param chn_id The ID of the relay channel to query.
|
* @param chn_id The ID of the relay channel to query.
|
||||||
* @param time_sec The run limit time in seconds.
|
* @param limit_sec The run limit time in seconds.
|
||||||
*/
|
*/
|
||||||
extern void relay_chn_ctl_set_run_limit(uint8_t chn_id, uint16_t time_sec);
|
extern void relay_chn_ctl_set_run_limit(uint8_t chn_id, uint16_t limit_sec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the run limits for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function iterates through all configured relay channels and sets their
|
||||||
|
* run limits based on the values provided in the `limits_sec` array. Each value
|
||||||
|
* will be clamped within the configured `RELAY_CHN_RUN_LIMIT_MIN_SEC` and
|
||||||
|
* `RELAY_CHN_RUN_LIMIT_MAX_SEC` boundaries. The new run limits are persisted
|
||||||
|
* in NVS if enabled.
|
||||||
|
*
|
||||||
|
* @param limits_sec Pointer to an array containing the desired run limits in seconds.
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if `limits_sec` is NULL.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_set_run_limit_all(uint16_t *limits_sec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a single run limit value for all configured relay channels.
|
||||||
|
*
|
||||||
|
* This function sets the same `limit_sec` value for all configured relay channels.
|
||||||
|
* The value will be clamped within the configured `RELAY_CHN_RUN_LIMIT_MIN_SEC`
|
||||||
|
* and `RELAY_CHN_RUN_LIMIT_MAX_SEC` boundaries.
|
||||||
|
* @param limit_sec The desired run limit in seconds to apply to all channels.
|
||||||
|
* @return ESP_OK on success.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_ctl_set_run_limit_all_with(uint16_t limit_sec);
|
||||||
|
|
||||||
static inline uint16_t relay_chn_get_run_limit(uint8_t chn_id)
|
static inline uint16_t relay_chn_get_run_limit(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
return relay_chn_ctl_get_run_limit(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)
|
static inline esp_err_t relay_chn_get_run_limit_all(uint16_t *limits_sec)
|
||||||
{
|
{
|
||||||
relay_chn_ctl_set_run_limit(chn_id, time_sec);
|
return relay_chn_ctl_get_run_limit_all(limits_sec);
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
|
||||||
|
static inline void relay_chn_set_run_limit(uint8_t chn_id, uint16_t limit_sec)
|
||||||
|
{
|
||||||
|
relay_chn_ctl_set_run_limit(chn_id, limit_sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline esp_err_t relay_chn_set_run_limit_all(uint16_t *limits_sec)
|
||||||
|
{
|
||||||
|
return relay_chn_ctl_set_run_limit_all(limits_sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline esp_err_t relay_chn_set_run_limit_all_with(uint16_t limit_sec)
|
||||||
|
{
|
||||||
|
return relay_chn_ctl_set_run_limit_all_with(limit_sec);
|
||||||
|
}
|
||||||
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -209,7 +377,7 @@ static inline relay_chn_direction_t relay_chn_get_direction(void)
|
|||||||
return relay_chn_ctl_get_direction();
|
return relay_chn_ctl_get_direction();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
/**
|
/**
|
||||||
* @brief Get the run limit for the channel
|
* @brief Get the run limit for the channel
|
||||||
*
|
*
|
||||||
@@ -220,22 +388,22 @@ extern uint16_t relay_chn_ctl_get_run_limit(void);
|
|||||||
/**
|
/**
|
||||||
* @brief Set the run limit for the channel
|
* @brief Set the run limit for the channel
|
||||||
*
|
*
|
||||||
* @param time_sec The run limit time in seconds.
|
* @param limit_sec The run limit time in seconds.
|
||||||
*/
|
*/
|
||||||
extern void relay_chn_ctl_set_run_limit(uint16_t time_sec);
|
extern void relay_chn_ctl_set_run_limit(uint16_t limit_sec);
|
||||||
|
|
||||||
static inline uint16_t relay_chn_get_run_limit(void)
|
static inline uint16_t relay_chn_get_run_limit(void)
|
||||||
{
|
{
|
||||||
return relay_chn_ctl_get_run_limit();
|
return relay_chn_ctl_get_run_limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void relay_chn_set_run_limit(uint16_t time_sec)
|
static inline void relay_chn_set_run_limit(uint16_t limit_sec)
|
||||||
{
|
{
|
||||||
relay_chn_ctl_set_run_limit(time_sec);
|
relay_chn_ctl_set_run_limit(limit_sec);
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
||||||
|
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Config defines for covenient writing */
|
|
||||||
#define RELAY_CHN_OPPOSITE_INERTIA_MS CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS
|
|
||||||
#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
|
|
||||||
#define RELAY_CHN_NVS_CUSTOM_PARTITION CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION
|
|
||||||
#if RELAY_CHN_NVS_CUSTOM_PARTITION == 1
|
|
||||||
#define RELAY_CHN_NVS_CUSTOM_PARTITION_NAME CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
|
||||||
#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
|
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "relay_chn_defs.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -33,7 +32,7 @@ typedef enum relay_chn_state_enum {
|
|||||||
RELAY_CHN_STATE_REVERSE, /*!< The relay channel is running in the reverse direction */
|
RELAY_CHN_STATE_REVERSE, /*!< The relay channel is running in the reverse direction */
|
||||||
RELAY_CHN_STATE_FORWARD_PENDING, /*!< The relay channel is pending to run in the forward direction */
|
RELAY_CHN_STATE_FORWARD_PENDING, /*!< The relay channel is pending to run in the forward direction */
|
||||||
RELAY_CHN_STATE_REVERSE_PENDING, /*!< The relay channel is pending to run in the reverse direction */
|
RELAY_CHN_STATE_REVERSE_PENDING, /*!< The relay channel is pending to run in the reverse direction */
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
RELAY_CHN_STATE_TILT_FORWARD, /*!< The relay channel is tilting for forward */
|
RELAY_CHN_STATE_TILT_FORWARD, /*!< The relay channel is tilting for forward */
|
||||||
RELAY_CHN_STATE_TILT_REVERSE, /*!< The relay channel is tilting for reverse */
|
RELAY_CHN_STATE_TILT_REVERSE, /*!< The relay channel is tilting for reverse */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_timer.h"
|
#include "esp_timer.h"
|
||||||
#include "relay_chn_defs.h"
|
|
||||||
#include "relay_chn_types.h"
|
#include "relay_chn_types.h"
|
||||||
#include "relay_chn_priv_types.h"
|
#include "relay_chn_priv_types.h"
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_init_timer(relay_chn_ctl_t *chn_ctl);
|
esp_err_t relay_chn_init_timer(relay_chn_ctl_t *chn_ctl);
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the relay channel run limit timer.
|
* @brief Initializes the relay channel run limit timer.
|
||||||
*
|
*
|
||||||
@@ -40,7 +39,7 @@ esp_err_t relay_chn_init_timer(relay_chn_ctl_t *chn_ctl);
|
|||||||
* @return esp_err_t ESP_OK on success, or an error code on failure.
|
* @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);
|
esp_err_t relay_chn_init_run_limit_timer(relay_chn_ctl_t *chn_ctl);
|
||||||
#endif // RELAY_CHN_ENABLE_RUN_LIMIT
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Issues a command to the relay channel.
|
* @brief Issues a command to the relay channel.
|
||||||
@@ -102,7 +101,7 @@ void relay_chn_update_state(relay_chn_ctl_t *chn_ctl, relay_chn_state_t new_stat
|
|||||||
*/
|
*/
|
||||||
char *relay_chn_state_str(relay_chn_state_t state);
|
char *relay_chn_state_str(relay_chn_state_t state);
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
/**
|
/**
|
||||||
* @brief Check if the provided channel ID is valid.
|
* @brief Check if the provided channel ID is valid.
|
||||||
*
|
*
|
||||||
@@ -111,7 +110,7 @@ char *relay_chn_state_str(relay_chn_state_t state);
|
|||||||
* @return false Channel ID is invalid.
|
* @return false Channel ID is invalid.
|
||||||
*/
|
*/
|
||||||
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 // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ esp_err_t relay_chn_ctl_init(relay_chn_output_t *output, relay_chn_run_info_t *r
|
|||||||
*/
|
*/
|
||||||
void relay_chn_ctl_deinit(void);
|
void relay_chn_ctl_deinit(void);
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
/**
|
/**
|
||||||
* @brief Get the control structure for a specific relay channel.
|
* @brief Get the control structure for a specific relay channel.
|
||||||
*
|
*
|
||||||
@@ -49,7 +49,7 @@ relay_chn_ctl_t *relay_chn_ctl_get(uint8_t chn_id);
|
|||||||
relay_chn_ctl_t *relay_chn_ctl_get_all(void);
|
relay_chn_ctl_t *relay_chn_ctl_get_all(void);
|
||||||
#else
|
#else
|
||||||
relay_chn_ctl_t *relay_chn_ctl_get(void);
|
relay_chn_ctl_t *relay_chn_ctl_get(void);
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
51
private_include/relay_chn_notify.h
Normal file
51
private_include/relay_chn_notify.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "relay_chn_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Init the notify module.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: Success
|
||||||
|
* - ESP_ERR_NO_MEM: Not enough memory to create notify queue
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_notify_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinit the notify module.
|
||||||
|
*
|
||||||
|
* This function cleans up resources used by the notify module.
|
||||||
|
*/
|
||||||
|
void relay_chn_notify_deinit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notify all registered listeners about a state change.
|
||||||
|
*
|
||||||
|
* This function sends a state change event to an internal queue, which will then
|
||||||
|
* be processed by a dedicated task to notify all registered listeners. This
|
||||||
|
* function is typically called internally by the relay channel core logic.
|
||||||
|
*
|
||||||
|
* @param chn_id The ID of the relay channel whose state has changed.
|
||||||
|
* @param old_state The previous state of the relay channel.
|
||||||
|
* @param new_state The new state of the relay channel.
|
||||||
|
*/
|
||||||
|
esp_err_t relay_chn_notify_state_change(uint8_t chn_id,
|
||||||
|
relay_chn_state_t old_state,
|
||||||
|
relay_chn_state_t new_state);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -32,6 +32,10 @@ esp_err_t relay_chn_nvs_init(void);
|
|||||||
*
|
*
|
||||||
* @param[in] ch Channel number.
|
* @param[in] ch Channel number.
|
||||||
* @param[in] direction Direction to store.
|
* @param[in] direction Direction to store.
|
||||||
|
*
|
||||||
|
* @note This operation is asynchronous. The value is queued to be written
|
||||||
|
* by a background task. A subsequent `get` call may not immediately
|
||||||
|
* reflect the new value.
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t direction);
|
esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t direction);
|
||||||
@@ -41,36 +45,46 @@ esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t directio
|
|||||||
*
|
*
|
||||||
* @param[in] ch Channel number.
|
* @param[in] ch Channel number.
|
||||||
* @param[out] direction Pointer to store retrieved direction.
|
* @param[out] direction Pointer to store retrieved direction.
|
||||||
|
* @param[in] default_val Default value to use if not found in NVS.
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
/**
|
/**
|
||||||
* @brief Store relay channel run limit in NVS.
|
* @brief Store relay channel run limit in NVS.
|
||||||
*
|
*
|
||||||
* @param[in] ch Channel number.
|
* @param[in] ch Channel number.
|
||||||
* @param[in] direction Run limit value to store.
|
* @param[in] limit_sec Run limit value to store.
|
||||||
|
*
|
||||||
|
* @note This operation is asynchronous. The value is queued to be written
|
||||||
|
* by a background task. A subsequent `get` call may not immediately
|
||||||
|
* reflect the new value.
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_nvs_set_run_limit(uint8_t ch, uint16_t time_sec);
|
esp_err_t relay_chn_nvs_set_run_limit(uint8_t ch, uint16_t limit_sec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve relay channel run limit from NVS.
|
* @brief Retrieve relay channel run limit from NVS.
|
||||||
*
|
*
|
||||||
* @param[in] ch Channel number.
|
* @param[in] ch Channel number.
|
||||||
* @param[out] direction Pointer to store retrieved run limit value.
|
* @param[out] limit_sec Pointer to store retrieved run limit value.
|
||||||
|
* @param[in] default_val Default value to use if not found in NVS.
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_nvs_get_run_limit(uint8_t ch, uint16_t *time_sec);
|
esp_err_t relay_chn_nvs_get_run_limit(uint8_t ch, uint16_t *limit_sec, uint16_t default_val);
|
||||||
#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
||||||
|
|
||||||
#ifdef RELAY_CHN_ENABLE_TILTING
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
/**
|
/**
|
||||||
* @brief Store tilt sensitivity in NVS.
|
* @brief Store tilt sensitivity in NVS.
|
||||||
*
|
*
|
||||||
* @param[in] ch Channel number.
|
* @param[in] ch Channel number.
|
||||||
* @param[in] sensitivity Sensitivity value to store.
|
* @param[in] sensitivity Sensitivity value to store.
|
||||||
|
*
|
||||||
|
* @note This operation is asynchronous. The value is queued to be written
|
||||||
|
* by a background task. A subsequent `get` call may not immediately
|
||||||
|
* reflect the new value.
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity);
|
esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity);
|
||||||
@@ -80,15 +94,20 @@ esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity);
|
|||||||
*
|
*
|
||||||
* @param[in] ch Channel number.
|
* @param[in] ch Channel number.
|
||||||
* @param[out] sensitivity Pointer to store retrieved sensitivity.
|
* @param[out] sensitivity Pointer to store retrieved sensitivity.
|
||||||
|
* @param[in] default_val Default value to use if not found in NVS.
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Store tilt counters in NVS.
|
* @brief Store tilt counters in NVS.
|
||||||
*
|
*
|
||||||
* @param[in] ch Channel number.
|
* @param[in] ch Channel number.
|
||||||
* @param[in] tilt_count Tilt count value.
|
* @param[in] tilt_count Tilt count value.
|
||||||
|
*
|
||||||
|
* @note This operation is asynchronous. The value is queued to be written
|
||||||
|
* by a background task. A subsequent `get` call may not immediately
|
||||||
|
* reflect the new value.
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_nvs_set_tilt_count(uint8_t ch, uint16_t tilt_count);
|
esp_err_t relay_chn_nvs_set_tilt_count(uint8_t ch, uint16_t tilt_count);
|
||||||
@@ -98,15 +117,17 @@ esp_err_t relay_chn_nvs_set_tilt_count(uint8_t ch, uint16_t tilt_count);
|
|||||||
*
|
*
|
||||||
* @param[in] ch Channel number.
|
* @param[in] ch Channel number.
|
||||||
* @param[out] tilt_count Pointer to store tilt count.
|
* @param[out] tilt_count Pointer to store tilt count.
|
||||||
|
* @param[in] default_val Default value to use if not found in NVS.
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
#endif // RELAY_CHN_ENABLE_TILTING
|
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Erase all keys in the NVS namespace.
|
* @brief Erase all keys in the NVS namespace.
|
||||||
*
|
*
|
||||||
* This function will erase all key-value pairs in the NVS namespace used by relay channels.
|
* This function will erase all key-value pairs in the NVS namespace used by relay channels.
|
||||||
|
* It will also flush all pending operations in the queue.
|
||||||
*
|
*
|
||||||
* @return ESP_OK on success, error code otherwise.
|
* @return ESP_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
@@ -114,10 +135,8 @@ esp_err_t relay_chn_nvs_erase_all(void);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deinitialize NVS storage for relay channels.
|
* @brief Deinitialize NVS storage for relay channels.
|
||||||
*
|
|
||||||
* @return ESP_OK on success, error code otherwise.
|
|
||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_nvs_deinit(void);
|
void relay_chn_nvs_deinit(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count);
|
|||||||
*/
|
*/
|
||||||
void relay_chn_output_deinit(void);
|
void relay_chn_output_deinit(void);
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
/**
|
/**
|
||||||
* @brief Get the relay channel output object for a specific channel.
|
* @brief Get the relay channel output object for a specific channel.
|
||||||
*
|
*
|
||||||
@@ -59,7 +59,7 @@ relay_chn_output_t *relay_chn_output_get_all(void);
|
|||||||
* @return Pointer to relay channel output object.
|
* @return Pointer to relay channel output object.
|
||||||
*/
|
*/
|
||||||
relay_chn_output_t *relay_chn_output_get(void);
|
relay_chn_output_t *relay_chn_output_get(void);
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stop the relay channel output.
|
* @brief Stop the relay channel output.
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ typedef struct {
|
|||||||
uint32_t last_run_cmd_time_ms; /*!< The time in milliseconds when the last run command was issued */
|
uint32_t last_run_cmd_time_ms; /*!< The time in milliseconds when the last run command was issued */
|
||||||
} relay_chn_run_info_t;
|
} relay_chn_run_info_t;
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
/// @brief Tilt commands.
|
/// @brief Tilt commands.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RELAY_CHN_TILT_CMD_NONE, /*!< No command */
|
RELAY_CHN_TILT_CMD_NONE, /*!< No command */
|
||||||
@@ -68,11 +68,11 @@ typedef struct {
|
|||||||
relay_chn_output_t *output; /*!< Output configuration of the relay channel */
|
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 */
|
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 */
|
esp_timer_handle_t inertia_timer; /*!< Timer to handle the opposite direction inertia time */
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
esp_timer_handle_t run_limit_timer; /*!< Timer to handle the run limit */
|
esp_timer_handle_t run_limit_timer; /*!< Timer to handle the run limit */
|
||||||
uint16_t run_limit_sec; /*!< Run limit in seconds */
|
uint16_t run_limit_sec; /*!< Run limit in seconds */
|
||||||
#endif
|
#endif
|
||||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
relay_chn_tilt_ctl_t *tilt_ctl; /*!< Pointer to the tilt control structure if tilting is enabled */
|
relay_chn_tilt_ctl_t *tilt_ctl; /*!< Pointer to the tilt control structure if tilting is enabled */
|
||||||
#endif
|
#endif
|
||||||
} relay_chn_ctl_t;
|
} relay_chn_ctl_t;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
void relay_chn_run_info_init(void);
|
void relay_chn_run_info_init(void);
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
/**
|
/**
|
||||||
* @brief Get run information object for a specific relay channel.
|
* @brief Get run information object for a specific relay channel.
|
||||||
*
|
*
|
||||||
@@ -43,7 +43,7 @@ relay_chn_run_info_t *relay_chn_run_info_get_all(void);
|
|||||||
* @return Pointer to run information structure.
|
* @return Pointer to run information structure.
|
||||||
*/
|
*/
|
||||||
relay_chn_run_info_t *relay_chn_run_info_get(void);
|
relay_chn_run_info_t *relay_chn_run_info_get(void);
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the last run command for a relay channel.
|
* @brief Get the last run command for a relay channel.
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ if [[ -z "$IDF_PATH" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ==== 2. Valid Modes and Defaults ====
|
# ==== 2. Valid Modes and Defaults ====
|
||||||
valid_test_tags=("core" "tilt" "listener" "all" "relay_chn" "nvs" "run_limit")
|
valid_test_tags=("core" "tilt" "notify" "all" "relay_chn" "nvs" "run_limit" "batch" "inertia" "direction" "auto" "sensitivity" "counter" "interrupt")
|
||||||
|
valid_test_profiles=("run_limit" "tilt" "nvs" "nvs_custom" "multi" "full_single" "full_multi")
|
||||||
arg_tag="all" # Default to 'all' if no tag specified
|
arg_tag="all" # Default to 'all' if no tag specified
|
||||||
|
arg_profile="full_multi" # Default to 'full_multi' if no profile specified
|
||||||
arg_clean=false
|
arg_clean=false
|
||||||
arg_log=false
|
arg_log=false
|
||||||
arg_dry_run=false
|
arg_dry_run=false
|
||||||
arg_sdkconfig_file=""
|
|
||||||
flag_file=false
|
|
||||||
|
|
||||||
print_help() {
|
print_help() {
|
||||||
echo "Usage: $0 -t <tags> [OPTIONS]"
|
echo "Usage: $0 -t <tags> [OPTIONS]"
|
||||||
@@ -24,10 +24,14 @@ print_help() {
|
|||||||
echo "This script builds and runs tests for the relay_chn component using QEMU."
|
echo "This script builds and runs tests for the relay_chn component using QEMU."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Arguments:"
|
echo "Arguments:"
|
||||||
echo " -t, --tag [relay_chn|core|tilt|listener|nvs|run_limit|all] Specify which test tag to run."
|
echo " -t, --tag [relay_chn|core|tilt|notify|nvs|run_limit|batch|inertia|direction|auto|sensitivity|counter|interrupt|all] Specify which test tag to run."
|
||||||
echo ""
|
echo ""
|
||||||
echo " If no tag is specified, it defaults to 'all'."
|
echo " If no tag is specified, it defaults to 'all'."
|
||||||
echo ""
|
echo ""
|
||||||
|
echo " -p, --profile [run_limit|tilt|nvs|nvs_custom|multi|full_single|full_multi] Specify which test tag to run."
|
||||||
|
echo ""
|
||||||
|
echo " If no profile is specified, it defaults to 'full_multi'."
|
||||||
|
echo ""
|
||||||
echo "Options:"
|
echo "Options:"
|
||||||
echo " -f, --file <path> Specify a custom sdkconfig file to use for the build."
|
echo " -f, --file <path> Specify a custom sdkconfig file to use for the build."
|
||||||
echo " Defaults to 'sdkconfig.defaults' if not provided."
|
echo " Defaults to 'sdkconfig.defaults' if not provided."
|
||||||
@@ -54,9 +58,8 @@ while [[ $# -gt 0 ]]; do
|
|||||||
arg_tag="$2"
|
arg_tag="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
--file|-f)
|
--profile|-p)
|
||||||
arg_sdkconfig_file="$2"
|
arg_profile="$2"
|
||||||
flag_file=true
|
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
--clean|-c)
|
--clean|-c)
|
||||||
@@ -86,6 +89,11 @@ if [[ ! " ${valid_test_tags[*]} " =~ " $arg_tag " ]]; then
|
|||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ ! " ${valid_test_profiles[*]} " =~ " $arg_profile " ]]; then
|
||||||
|
echo "❌ Invalid profile: '$arg_profile'"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
# ==== 5. Resolve Paths and Switch to Working Directory ====
|
# ==== 5. Resolve Paths and Switch to Working Directory ====
|
||||||
script_dir=$(dirname "$(readlink -f "$0")")
|
script_dir=$(dirname "$(readlink -f "$0")")
|
||||||
project_root=$(dirname "$script_dir")
|
project_root=$(dirname "$script_dir")
|
||||||
@@ -98,21 +106,9 @@ if [[ -z "$test_apps_dir" || ! -d "$test_apps_dir" ]]; then
|
|||||||
echo " Please ensure the script is in a 'scripts' directory and 'test_apps' is a sibling."
|
echo " Please ensure the script is in a 'scripts' directory and 'test_apps' is a sibling."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✅ Found 'test_apps' at: $test_apps_dir"
|
echo "✅ Found 'test_apps' at: $test_apps_dir"
|
||||||
|
echo "🧪 Test mode: $arg_tag | Profile: $arg_profile"
|
||||||
if $flag_file; then
|
|
||||||
if [[ -z "$arg_sdkconfig_file" || ! -f "$arg_sdkconfig_file" ]]; then
|
|
||||||
echo "❌ Invalid or missing file: '$arg_sdkconfig_file'"
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
# Resolve to an absolute path to work correctly after changing directory
|
|
||||||
arg_sdkconfig_file=$(readlink -f "$arg_sdkconfig_file")
|
|
||||||
else
|
|
||||||
echo "⚠️ No SDK configuration file provided. Using default sdkconfig."
|
|
||||||
arg_sdkconfig_file="$test_apps_dir/sdkconfig.defaults"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "🧪 Test mode: $arg_tag"
|
|
||||||
echo "🧹 Clean: $arg_clean | 📄 Log: $arg_log"
|
echo "🧹 Clean: $arg_clean | 📄 Log: $arg_log"
|
||||||
|
|
||||||
echo "📂 Changing to working directory: $test_apps_dir"
|
echo "📂 Changing to working directory: $test_apps_dir"
|
||||||
@@ -129,15 +125,14 @@ fi
|
|||||||
# In some locales, we can get errors like: "Error: unknown opcode or format name 'wsr.IBREAKA1'"
|
# In some locales, we can get errors like: "Error: unknown opcode or format name 'wsr.IBREAKA1'"
|
||||||
# The 'LC_ALL=C' env variable is set to ensure consistent locale settings.
|
# The 'LC_ALL=C' env variable is set to ensure consistent locale settings.
|
||||||
LC_ALL=C \
|
LC_ALL=C \
|
||||||
SDKCONFIG_DEFAULTS="$arg_sdkconfig_file" \
|
|
||||||
RELAY_CHN_UNITY_TEST_GROUP_TAG="$arg_tag" \
|
RELAY_CHN_UNITY_TEST_GROUP_TAG="$arg_tag" \
|
||||||
idf.py reconfigure build
|
idf.py @profiles/"${arg_profile}" reconfigure build
|
||||||
|
|
||||||
echo "🚀 Running test with QEMU..."
|
echo "🚀 Running test with QEMU..."
|
||||||
|
|
||||||
if $arg_log; then
|
if $arg_log; then
|
||||||
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
||||||
LOGFILE="test_log_${arg_tag}_$TIMESTAMP.txt"
|
LOGFILE="test_log_${arg_profile}_${arg_tag}_$TIMESTAMP.txt"
|
||||||
if $arg_dry_run; then
|
if $arg_dry_run; then
|
||||||
echo "🔍 Dry run mode: Logging to $LOGFILE but not executing." | tee "$LOGFILE"
|
echo "🔍 Dry run mode: Logging to $LOGFILE but not executing." | tee "$LOGFILE"
|
||||||
echo "Command: idf.py qemu" | tee "$LOGFILE"
|
echo "Command: idf.py qemu" | tee "$LOGFILE"
|
||||||
|
|||||||
@@ -18,13 +18,16 @@ echo "🔍 Searching for 'test_apps' directory in '$project_root'..."
|
|||||||
test_apps_dir=$(find "$project_root" -type d -name "test_apps" | head -n 1)
|
test_apps_dir=$(find "$project_root" -type d -name "test_apps" | head -n 1)
|
||||||
echo "test_apps dir: ${test_apps_dir}"
|
echo "test_apps dir: ${test_apps_dir}"
|
||||||
|
|
||||||
# Execute tests for all configs
|
# Execute tests for all profiles
|
||||||
mapfile -t sdkcfg_files < <(find "$test_apps_dir" -maxdepth 1 -type f -name "sdkconfig.defaults*")
|
mapfile -t profiles < <(find "${test_apps_dir}/profiles" -maxdepth 1 -type f)
|
||||||
|
|
||||||
for sdkcfg_file in "${sdkcfg_files[@]}"; do
|
for profile in "${profiles[@]}"; do
|
||||||
echo "🔧 Running tests with config: $sdkcfg_file"
|
# Get only the name of the profile file
|
||||||
"${script_dir}"/run_tests.sh -c -f "$sdkcfg_file" -t "$arg_tag" || {
|
profile=$(basename "${profile}")
|
||||||
echo "❌ Tests failed with config: $sdkcfg_file"
|
|
||||||
|
echo "🔧 Running tests with profile: $profile"
|
||||||
|
"${script_dir}"/run_tests.sh -c -p "$profile" -t "$arg_tag" || {
|
||||||
|
echo "❌ Tests failed with profile: $profile"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
done
|
done
|
||||||
@@ -11,12 +11,13 @@
|
|||||||
#include "relay_chn_output.h"
|
#include "relay_chn_output.h"
|
||||||
#include "relay_chn_run_info.h"
|
#include "relay_chn_run_info.h"
|
||||||
#include "relay_chn_ctl.h"
|
#include "relay_chn_ctl.h"
|
||||||
|
#include "relay_chn_notify.h"
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
#include "relay_chn_tilt.h"
|
#include "relay_chn_tilt.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -26,16 +27,7 @@
|
|||||||
static const char *TAG = "RELAY_CHN_CORE";
|
static const char *TAG = "RELAY_CHN_CORE";
|
||||||
|
|
||||||
|
|
||||||
// Structure to hold a listener entry in the linked list.
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
typedef struct relay_chn_listener_entry_type {
|
|
||||||
relay_chn_state_listener_t listener; /*!< The listener function pointer */
|
|
||||||
ListItem_t list_item; /*!< FreeRTOS list item */
|
|
||||||
} relay_chn_listener_entry_t;
|
|
||||||
|
|
||||||
// The list that holds references to the registered listeners.
|
|
||||||
static List_t relay_chn_listener_list;
|
|
||||||
|
|
||||||
#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
|
||||||
* relevant channel as soon as the run limit time times out
|
* relevant channel as soon as the run limit time times out
|
||||||
@@ -90,7 +82,7 @@ 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");
|
||||||
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
ret = relay_chn_nvs_init();
|
ret = relay_chn_nvs_init();
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize NVS for relay channel");
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize NVS for relay channel");
|
||||||
#endif
|
#endif
|
||||||
@@ -102,7 +94,7 @@ esp_err_t relay_chn_create(const uint8_t* gpio_map, uint8_t gpio_count)
|
|||||||
// Initialize the run info
|
// Initialize the run info
|
||||||
relay_chn_run_info_init();
|
relay_chn_run_info_init();
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
relay_chn_output_t *outputs = relay_chn_output_get_all();
|
relay_chn_output_t *outputs = relay_chn_output_get_all();
|
||||||
relay_chn_run_info_t *run_infos = relay_chn_run_info_get_all();
|
relay_chn_run_info_t *run_infos = relay_chn_run_info_get_all();
|
||||||
#else
|
#else
|
||||||
@@ -114,117 +106,36 @@ 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");
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
// Initialize the tilt feature
|
// Initialize the tilt feature
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
relay_chn_ctl_t *chn_ctls = relay_chn_ctl_get_all();
|
relay_chn_ctl_t *chn_ctls = relay_chn_ctl_get_all();
|
||||||
#else
|
#else
|
||||||
relay_chn_ctl_t *chn_ctls = relay_chn_ctl_get();
|
relay_chn_ctl_t *chn_ctls = relay_chn_ctl_get();
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
ret = relay_chn_tilt_init(chn_ctls); // Initialize tilt feature
|
ret = relay_chn_tilt_init(chn_ctls); // Initialize tilt feature
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize tilt feature");
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize tilt feature");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Init the state listener list
|
// Initialize the notify feature
|
||||||
vListInitialise(&relay_chn_listener_list);
|
ret = relay_chn_notify_init();
|
||||||
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize notify feature");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_destroy(void)
|
void relay_chn_destroy(void)
|
||||||
{
|
{
|
||||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
relay_chn_tilt_deinit();
|
relay_chn_tilt_deinit();
|
||||||
#endif
|
#endif
|
||||||
|
relay_chn_notify_deinit();
|
||||||
relay_chn_ctl_deinit();
|
relay_chn_ctl_deinit();
|
||||||
relay_chn_output_deinit();
|
relay_chn_output_deinit();
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
relay_chn_nvs_deinit();
|
relay_chn_nvs_deinit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Free the listeners
|
|
||||||
while (listCURRENT_LIST_LENGTH(&relay_chn_listener_list) > 0) {
|
|
||||||
ListItem_t *pxItem = listGET_HEAD_ENTRY(&relay_chn_listener_list);
|
|
||||||
relay_chn_listener_entry_t *entry = listGET_LIST_ITEM_OWNER(pxItem);
|
|
||||||
uxListRemove(pxItem);
|
|
||||||
free(entry);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Find a listener entry in the list by its function pointer.
|
|
||||||
*
|
|
||||||
* This function replaces the old index-based search and is used to check
|
|
||||||
* for the existence of a listener before registration or for finding it
|
|
||||||
* during unregistration.
|
|
||||||
*
|
|
||||||
* @param listener The listener function pointer to find.
|
|
||||||
* @return Pointer to the listener entry if found, otherwise NULL.
|
|
||||||
*/
|
|
||||||
static relay_chn_listener_entry_t* find_listener_entry(relay_chn_state_listener_t listener)
|
|
||||||
{
|
|
||||||
// Iterate through the linked list of listeners
|
|
||||||
for (ListItem_t *pxListItem = listGET_HEAD_ENTRY(&relay_chn_listener_list);
|
|
||||||
pxListItem != listGET_END_MARKER(&relay_chn_listener_list);
|
|
||||||
pxListItem = listGET_NEXT(pxListItem)) {
|
|
||||||
|
|
||||||
relay_chn_listener_entry_t *entry = (relay_chn_listener_entry_t *) listGET_LIST_ITEM_OWNER(pxListItem);
|
|
||||||
if (entry->listener == listener) {
|
|
||||||
// Found the listener, return the entry
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listener was not found in the list
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t relay_chn_register_listener(relay_chn_state_listener_t listener)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(listener, ESP_ERR_INVALID_ARG, TAG, "Listener cannot be NULL");
|
|
||||||
|
|
||||||
// Check for duplicates
|
|
||||||
if (find_listener_entry(listener) != NULL) {
|
|
||||||
ESP_LOGD(TAG, "Listener %p already registered", listener);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate memory for the new listener entry
|
|
||||||
relay_chn_listener_entry_t *entry = malloc(sizeof(relay_chn_listener_entry_t));
|
|
||||||
ESP_RETURN_ON_FALSE(entry, ESP_ERR_NO_MEM, TAG, "Failed to allocate memory for listener");
|
|
||||||
|
|
||||||
// Initialize and insert the new listener
|
|
||||||
entry->listener = listener;
|
|
||||||
vListInitialiseItem(&(entry->list_item));
|
|
||||||
listSET_LIST_ITEM_OWNER(&(entry->list_item), (void *)entry);
|
|
||||||
vListInsertEnd(&relay_chn_listener_list, &(entry->list_item));
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Registered listener %p", listener);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void relay_chn_unregister_listener(relay_chn_state_listener_t listener)
|
|
||||||
{
|
|
||||||
if (listener == NULL)
|
|
||||||
{
|
|
||||||
ESP_LOGD(TAG, "Cannot unregister a NULL listener.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the listener entry in the list
|
|
||||||
relay_chn_listener_entry_t *entry = find_listener_entry(listener);
|
|
||||||
|
|
||||||
if (entry != NULL) {
|
|
||||||
// Remove the item from the list and free the allocated memory
|
|
||||||
uxListRemove(&(entry->list_item));
|
|
||||||
free(entry);
|
|
||||||
ESP_LOGD(TAG, "Unregistered listener %p", listener);
|
|
||||||
} else {
|
|
||||||
ESP_LOGD(TAG, "Listener %p not found for unregistration.", listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -251,15 +162,34 @@ void relay_chn_update_state(relay_chn_ctl_t *chn_ctl, relay_chn_state_t new_stat
|
|||||||
|
|
||||||
chn_ctl->state = new_state;
|
chn_ctl->state = new_state;
|
||||||
|
|
||||||
// Iterate through the linked list of listeners and notify them.
|
relay_chn_notify_state_change(chn_ctl->id, old_state, new_state);
|
||||||
for (ListItem_t *pxListItem = listGET_HEAD_ENTRY(&relay_chn_listener_list);
|
|
||||||
pxListItem != listGET_END_MARKER(&relay_chn_listener_list);
|
|
||||||
pxListItem = listGET_NEXT(pxListItem)) {
|
|
||||||
relay_chn_listener_entry_t *entry = (relay_chn_listener_entry_t *) listGET_LIST_ITEM_OWNER(pxListItem);
|
|
||||||
if (entry && entry->listener) {
|
|
||||||
// Emit the state change to the listeners
|
|
||||||
entry->listener(chn_ctl->id, old_state, new_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void relay_chn_execute_idle(relay_chn_ctl_t *chn_ctl);
|
||||||
|
|
||||||
|
static void relay_chn_start_timer_or_idle(relay_chn_ctl_t *chn_ctl, esp_timer_handle_t timer, uint32_t time_ms, const char* timer_name)
|
||||||
|
{
|
||||||
|
if (relay_chn_start_esp_timer_once(timer, time_ms) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to start %s timer for ch %d", timer_name, chn_ctl->id);
|
||||||
|
// Attempt to go to a safe state.
|
||||||
|
// relay_chn_execute_idle is safe to call, it stops timers and sets state.
|
||||||
|
relay_chn_execute_idle(chn_ctl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void relay_chn_stop_prv(relay_chn_ctl_t *chn_ctl)
|
||||||
|
{
|
||||||
|
if (relay_chn_output_stop(chn_ctl->output) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "relay_chn_execute_stop: Failed to output stop for relay channel #%d!", chn_ctl->id);
|
||||||
|
}
|
||||||
|
relay_chn_state_t previous_state = chn_ctl->state;
|
||||||
|
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_STOPPED);
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
// Record the command's last run time
|
||||||
|
relay_chn_run_info_set_last_run_cmd_time_ms(chn_ctl->run_info, (uint32_t)(esp_timer_get_time() / 1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,28 +257,36 @@ void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd)
|
|||||||
// If the last run command is different from the current command, calculate the time passed
|
// If the last run command is different from the current command, calculate the time passed
|
||||||
// since the last run command stopped and decide whether to run the command immediately or wait
|
// since the last run command stopped and decide whether to run the command immediately or wait
|
||||||
uint32_t last_run_cmd_time_ms = relay_chn_run_info_get_last_run_cmd_time_ms(chn_ctl->run_info);
|
uint32_t last_run_cmd_time_ms = relay_chn_run_info_get_last_run_cmd_time_ms(chn_ctl->run_info);
|
||||||
uint32_t inertia_time_passed_ms = (uint32_t) (esp_timer_get_time() / 1000) - last_run_cmd_time_ms;
|
uint32_t current_time_ms = (uint32_t)(esp_timer_get_time() / 1000);
|
||||||
uint32_t inertia_time_ms = RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
if (current_time_ms < last_run_cmd_time_ms) { // Timer overflow
|
||||||
if (inertia_time_ms > 0) {
|
// If timer overflowed, it's been a long time. Run immediately.
|
||||||
|
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||||
|
} else {
|
||||||
|
uint32_t inertia_time_passed_ms = current_time_ms - last_run_cmd_time_ms;
|
||||||
|
if (inertia_time_passed_ms < CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS) {
|
||||||
|
uint32_t inertia_time_ms = CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
||||||
chn_ctl->pending_cmd = cmd;
|
chn_ctl->pending_cmd = cmd;
|
||||||
relay_chn_state_t new_state = cmd == RELAY_CHN_CMD_FORWARD
|
relay_chn_state_t new_state = cmd == RELAY_CHN_CMD_FORWARD
|
||||||
? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
||||||
relay_chn_update_state(chn_ctl, new_state);
|
relay_chn_update_state(chn_ctl, new_state);
|
||||||
// If the time passed is less than the opposite inertia time, wait for the remaining time
|
// If the time passed is less than the opposite inertia time, wait for the remaining time
|
||||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, inertia_time_ms);
|
if (relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, inertia_time_ms) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to start inertia timer for ch %d", chn_ctl->id);
|
||||||
|
relay_chn_execute_idle(chn_ctl);
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
// If the time passed is more than the opposite inertia time, run the command immediately
|
// If the time passed is more than the opposite inertia time, run the command immediately
|
||||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RELAY_CHN_STATE_FORWARD:
|
case RELAY_CHN_STATE_FORWARD:
|
||||||
case RELAY_CHN_STATE_REVERSE:
|
case RELAY_CHN_STATE_REVERSE:
|
||||||
if (cmd == RELAY_CHN_CMD_FLIP) {
|
if (cmd == RELAY_CHN_CMD_FLIP) {
|
||||||
// If the command is FLIP, stop the running channel first, then issue the FLIP command
|
// If the command is FLIP, stop the running channel first, then issue the FLIP command
|
||||||
relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_stop_prv(chn_ctl);
|
||||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -359,17 +297,17 @@ void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop the channel first before the schedule
|
// Stop the channel first before the schedule
|
||||||
relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_stop_prv(chn_ctl);
|
||||||
|
|
||||||
// If the last run command is different from the current command, wait for the opposite inertia time
|
// If the last run command is different from the current command, wait for the opposite inertia time
|
||||||
chn_ctl->pending_cmd = cmd;
|
chn_ctl->pending_cmd = cmd;
|
||||||
relay_chn_state_t new_state = cmd == RELAY_CHN_CMD_FORWARD
|
relay_chn_state_t new_state = cmd == RELAY_CHN_CMD_FORWARD
|
||||||
? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
||||||
relay_chn_update_state(chn_ctl, new_state);
|
relay_chn_update_state(chn_ctl, new_state);
|
||||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
relay_chn_start_timer_or_idle(chn_ctl, chn_ctl->inertia_timer, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS, "inertia");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
case RELAY_CHN_STATE_TILT_FORWARD:
|
case RELAY_CHN_STATE_TILT_FORWARD:
|
||||||
// Terminate tilting first
|
// Terminate tilting first
|
||||||
relay_chn_tilt_dispatch_cmd(chn_ctl->tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
relay_chn_tilt_dispatch_cmd(chn_ctl->tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||||
@@ -377,7 +315,7 @@ void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd)
|
|||||||
// Schedule for running forward
|
// Schedule for running forward
|
||||||
chn_ctl->pending_cmd = cmd;
|
chn_ctl->pending_cmd = cmd;
|
||||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_FORWARD_PENDING);
|
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_FORWARD_PENDING);
|
||||||
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, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||||
} else if (cmd == RELAY_CHN_CMD_REVERSE) {
|
} else if (cmd == RELAY_CHN_CMD_REVERSE) {
|
||||||
// Run directly since it is the same direction
|
// Run directly since it is the same direction
|
||||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||||
@@ -395,7 +333,7 @@ void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd)
|
|||||||
// Schedule for running reverse
|
// Schedule for running reverse
|
||||||
chn_ctl->pending_cmd = cmd;
|
chn_ctl->pending_cmd = cmd;
|
||||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_REVERSE_PENDING);
|
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_REVERSE_PENDING);
|
||||||
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, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@@ -404,16 +342,16 @@ void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
bool relay_chn_is_channel_id_valid(uint8_t chn_id)
|
bool relay_chn_is_channel_id_valid(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
bool valid = (chn_id < RELAY_CHN_COUNT) || chn_id == RELAY_CHN_ID_ALL;
|
bool valid = chn_id < CONFIG_RELAY_CHN_COUNT;
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
ESP_LOGE(TAG, "Invalid channel ID: %d", chn_id);
|
ESP_LOGE(TAG, "Invalid channel ID: %d", chn_id);
|
||||||
}
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
|
|
||||||
static void relay_chn_execute_idle(relay_chn_ctl_t *chn_ctl)
|
static void relay_chn_execute_idle(relay_chn_ctl_t *chn_ctl)
|
||||||
@@ -426,36 +364,27 @@ static void relay_chn_execute_idle(relay_chn_ctl_t *chn_ctl)
|
|||||||
|
|
||||||
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) {
|
relay_chn_stop_prv(chn_ctl);
|
||||||
ESP_LOGE(TAG, "relay_chn_execute_stop: Failed to output stop for relay channel #%d!", chn_ctl->id);
|
|
||||||
}
|
|
||||||
relay_chn_state_t previous_state = chn_ctl->state;
|
|
||||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_STOPPED);
|
|
||||||
|
|
||||||
// If there is any pending command, cancel it since the STOP command is issued right after it
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_NONE;
|
|
||||||
// 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);
|
esp_timer_stop(chn_ctl->run_limit_timer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Save the last run time only if the previous state was either STATE FORWARD
|
// Invalidate the channel's timer if it is active
|
||||||
// or STATE_REVERSE. Then schedule a free command.
|
esp_timer_stop(chn_ctl->inertia_timer);
|
||||||
if (previous_state == RELAY_CHN_STATE_FORWARD || previous_state == RELAY_CHN_STATE_REVERSE) {
|
|
||||||
// Record the command's last run time
|
relay_chn_cmd_t last_run_cmd = relay_chn_run_info_get_last_run_cmd(chn_ctl->run_info);
|
||||||
relay_chn_run_info_set_last_run_cmd_time_ms(chn_ctl->run_info, (uint32_t)(esp_timer_get_time() / 1000));
|
if (last_run_cmd == RELAY_CHN_CMD_FORWARD || last_run_cmd == RELAY_CHN_CMD_REVERSE ) {
|
||||||
// Schedule a free command for the channel
|
// Schedule IDLE
|
||||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_IDLE;
|
chn_ctl->pending_cmd = RELAY_CHN_CMD_IDLE;
|
||||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
relay_chn_start_timer_or_idle(chn_ctl, chn_ctl->inertia_timer, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS, "idle");
|
||||||
} 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 forward or reverse, issue a free command immediately
|
||||||
// relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_IDLE);
|
|
||||||
relay_chn_execute_idle(chn_ctl);
|
relay_chn_execute_idle(chn_ctl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void relay_chn_execute_forward(relay_chn_ctl_t *chn_ctl)
|
static void relay_chn_execute_forward(relay_chn_ctl_t *chn_ctl)
|
||||||
{
|
{
|
||||||
if (relay_chn_output_forward(chn_ctl->output) != ESP_OK) {
|
if (relay_chn_output_forward(chn_ctl->output) != ESP_OK) {
|
||||||
@@ -465,8 +394,8 @@ 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_run_info_set_last_run_cmd(chn_ctl->run_info, RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_FORWARD);
|
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_FORWARD);
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
relay_chn_start_esp_timer_once(chn_ctl->run_limit_timer, chn_ctl->run_limit_sec * 1000);
|
relay_chn_start_timer_or_idle(chn_ctl, chn_ctl->run_limit_timer, chn_ctl->run_limit_sec * 1000, "run limit");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,8 +408,8 @@ 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_run_info_set_last_run_cmd(chn_ctl->run_info, RELAY_CHN_CMD_REVERSE);
|
||||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_REVERSE);
|
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_REVERSE);
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
relay_chn_start_esp_timer_once(chn_ctl->run_limit_timer, chn_ctl->run_limit_sec * 1000);
|
relay_chn_start_timer_or_idle(chn_ctl, chn_ctl->run_limit_timer, chn_ctl->run_limit_sec * 1000, "run limit");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +418,7 @@ static void relay_chn_execute_flip(relay_chn_ctl_t *chn_ctl)
|
|||||||
relay_chn_output_flip(chn_ctl->output);
|
relay_chn_output_flip(chn_ctl->output);
|
||||||
// Set an inertia on the channel to prevent any immediate movement
|
// Set an inertia on the channel to prevent any immediate movement
|
||||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_IDLE;
|
chn_ctl->pending_cmd = RELAY_CHN_CMD_IDLE;
|
||||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
relay_chn_start_timer_or_idle(chn_ctl, chn_ctl->inertia_timer, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS, "flip inertia");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch relay channel command
|
// Dispatch relay channel command
|
||||||
@@ -516,7 +445,7 @@ void relay_chn_dispatch_cmd(relay_chn_ctl_t *chn_ctl, relay_chn_cmd_t cmd) {
|
|||||||
ESP_LOGD(TAG, "Unknown relay channel command!");
|
ESP_LOGD(TAG, "Unknown relay channel command!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
// Reset the tilt counter when the command is either FORWARD or REVERSE
|
// Reset the tilt counter when the command is either FORWARD or REVERSE
|
||||||
if (cmd == RELAY_CHN_CMD_FORWARD || cmd == RELAY_CHN_CMD_REVERSE) {
|
if (cmd == RELAY_CHN_CMD_FORWARD || cmd == RELAY_CHN_CMD_REVERSE) {
|
||||||
relay_chn_tilt_reset_count(chn_ctl->tilt_ctl);
|
relay_chn_tilt_reset_count(chn_ctl->tilt_ctl);
|
||||||
@@ -557,7 +486,7 @@ char *relay_chn_state_str(relay_chn_state_t state)
|
|||||||
return "FORWARD_PENDING";
|
return "FORWARD_PENDING";
|
||||||
case RELAY_CHN_STATE_REVERSE_PENDING:
|
case RELAY_CHN_STATE_REVERSE_PENDING:
|
||||||
return "REVERSE_PENDING";
|
return "REVERSE_PENDING";
|
||||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
case RELAY_CHN_STATE_TILT_FORWARD:
|
case RELAY_CHN_STATE_TILT_FORWARD:
|
||||||
return "TILT_FORWARD";
|
return "TILT_FORWARD";
|
||||||
case RELAY_CHN_STATE_TILT_REVERSE:
|
case RELAY_CHN_STATE_TILT_REVERSE:
|
||||||
|
|||||||
@@ -10,21 +10,21 @@
|
|||||||
#include "relay_chn_ctl.h"
|
#include "relay_chn_ctl.h"
|
||||||
#include "relay_chn_output.h"
|
#include "relay_chn_output.h"
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char *TAG = "RELAY_CHN_CTL";
|
static const char *TAG = "RELAY_CHN_CTL";
|
||||||
|
|
||||||
static relay_chn_ctl_t chn_ctls[RELAY_CHN_COUNT];
|
static relay_chn_ctl_t s_chn_ctls[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
|
||||||
|
|
||||||
esp_err_t relay_chn_ctl_init(relay_chn_output_t *outputs, relay_chn_run_info_t *run_infos)
|
esp_err_t relay_chn_ctl_init(relay_chn_output_t *outputs, relay_chn_run_info_t *run_infos)
|
||||||
{
|
{
|
||||||
// Initialize all relay channels
|
// Initialize all relay channels
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
relay_chn_ctl_t* chn_ctl = &chn_ctls[i];
|
relay_chn_ctl_t* chn_ctl = &s_chn_ctls[i];
|
||||||
relay_chn_output_t* output = &outputs[i];
|
relay_chn_output_t* output = &outputs[i];
|
||||||
relay_chn_run_info_t* run_info = &run_infos[i];
|
relay_chn_run_info_t* run_info = &run_infos[i];
|
||||||
|
|
||||||
@@ -34,14 +34,12 @@ esp_err_t relay_chn_ctl_init(relay_chn_output_t *outputs, relay_chn_run_info_t *
|
|||||||
|
|
||||||
chn_ctl->output = output;
|
chn_ctl->output = output;
|
||||||
chn_ctl->run_info = run_info;
|
chn_ctl->run_info = run_info;
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
uint16_t run_limit_sec = RELAY_CHN_RUN_LIMIT_DEFAULT_SEC;
|
uint16_t run_limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC;
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
// Load run limit value from NVS
|
// Load run limit value from NVS
|
||||||
ret = relay_chn_nvs_get_run_limit(chn_ctl->id, &run_limit_sec);
|
ret = relay_chn_nvs_get_run_limit(chn_ctl->id, &run_limit_sec, CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC);
|
||||||
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load run limit from NVS for #%d with error: %s", i, esp_err_to_name(ret));
|
||||||
ESP_LOGE(TAG, "Failed to load run limit from NVS for channel %d with error: %s", i, esp_err_to_name(ret));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
chn_ctl->run_limit_sec = run_limit_sec;
|
chn_ctl->run_limit_sec = run_limit_sec;
|
||||||
ret = relay_chn_init_run_limit_timer(chn_ctl);
|
ret = relay_chn_init_run_limit_timer(chn_ctl);
|
||||||
@@ -55,13 +53,13 @@ esp_err_t relay_chn_ctl_init(relay_chn_output_t *outputs, relay_chn_run_info_t *
|
|||||||
|
|
||||||
void relay_chn_ctl_deinit()
|
void relay_chn_ctl_deinit()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
relay_chn_ctl_t* chn_ctl = &chn_ctls[i];
|
relay_chn_ctl_t* chn_ctl = &s_chn_ctls[i];
|
||||||
if (chn_ctl->inertia_timer != NULL) {
|
if (chn_ctl->inertia_timer != NULL) {
|
||||||
esp_timer_delete(chn_ctl->inertia_timer);
|
esp_timer_delete(chn_ctl->inertia_timer);
|
||||||
chn_ctl->inertia_timer = NULL;
|
chn_ctl->inertia_timer = NULL;
|
||||||
}
|
}
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
if (chn_ctl->run_limit_timer != NULL) {
|
if (chn_ctl->run_limit_timer != NULL) {
|
||||||
esp_timer_delete(chn_ctl->run_limit_timer);
|
esp_timer_delete(chn_ctl->run_limit_timer);
|
||||||
chn_ctl->run_limit_timer = NULL;
|
chn_ctl->run_limit_timer = NULL;
|
||||||
@@ -72,120 +70,181 @@ void relay_chn_ctl_deinit()
|
|||||||
|
|
||||||
relay_chn_state_t relay_chn_ctl_get_state(uint8_t chn_id)
|
relay_chn_state_t relay_chn_ctl_get_state(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) {
|
return relay_chn_is_channel_id_valid(chn_id) ?
|
||||||
return RELAY_CHN_STATE_UNDEFINED;
|
s_chn_ctls[chn_id].state : RELAY_CHN_STATE_UNDEFINED;
|
||||||
}
|
}
|
||||||
return chn_ctls[chn_id].state;
|
|
||||||
|
esp_err_t relay_chn_ctl_get_state_all(relay_chn_state_t *states)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(states != NULL, ESP_ERR_INVALID_ARG, TAG, "states cannot be NULL");
|
||||||
|
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
relay_chn_state_t *dest_state = &states[i];
|
||||||
|
if (dest_state == NULL) {
|
||||||
|
ESP_LOGW(TAG, "get_state_all: States have been copied until channel %d since states[%d] is NULL", i, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*dest_state = s_chn_ctls[i].state;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *relay_chn_ctl_get_state_str(uint8_t chn_id)
|
char *relay_chn_ctl_get_state_str(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) {
|
return relay_chn_is_channel_id_valid(chn_id)
|
||||||
return relay_chn_state_str(RELAY_CHN_STATE_UNDEFINED);
|
? relay_chn_state_str(s_chn_ctls[chn_id].state)
|
||||||
}
|
: relay_chn_state_str(RELAY_CHN_STATE_UNDEFINED);
|
||||||
return relay_chn_state_str(chn_ctls[chn_id].state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void relay_chn_ctl_issue_cmd_on_all_channels(relay_chn_cmd_t cmd)
|
static void relay_chn_ctl_issue_cmd_on_all_channels(relay_chn_cmd_t cmd)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
relay_chn_issue_cmd(&chn_ctls[i], cmd);
|
relay_chn_issue_cmd(&s_chn_ctls[i], cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_run_forward(uint8_t chn_id)
|
void relay_chn_ctl_run_forward(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
if (relay_chn_is_channel_id_valid(chn_id))
|
||||||
|
relay_chn_issue_cmd(&s_chn_ctls[chn_id], RELAY_CHN_CMD_FORWARD);
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_FORWARD);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_FORWARD);
|
|
||||||
|
void relay_chn_ctl_run_forward_all()
|
||||||
|
{
|
||||||
|
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_FORWARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_run_reverse(uint8_t chn_id)
|
void relay_chn_ctl_run_reverse(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
if (relay_chn_is_channel_id_valid(chn_id))
|
||||||
|
relay_chn_issue_cmd(&s_chn_ctls[chn_id], RELAY_CHN_CMD_REVERSE);
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_REVERSE);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_REVERSE);
|
|
||||||
|
void relay_chn_ctl_run_reverse_all()
|
||||||
|
{
|
||||||
|
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_stop(uint8_t chn_id)
|
void relay_chn_ctl_stop(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
if (relay_chn_is_channel_id_valid(chn_id))
|
||||||
|
relay_chn_issue_cmd(&s_chn_ctls[chn_id], RELAY_CHN_CMD_STOP);
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_STOP);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_STOP);
|
|
||||||
|
void relay_chn_ctl_stop_all()
|
||||||
|
{
|
||||||
|
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_flip_direction(uint8_t chn_id)
|
void relay_chn_ctl_flip_direction(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
if (relay_chn_is_channel_id_valid(chn_id))
|
||||||
|
relay_chn_issue_cmd(&s_chn_ctls[chn_id], RELAY_CHN_CMD_FLIP);
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_FLIP);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_FLIP);
|
|
||||||
|
void relay_chn_ctl_flip_direction_all()
|
||||||
|
{
|
||||||
|
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_FLIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
relay_chn_direction_t relay_chn_ctl_get_direction(uint8_t chn_id)
|
relay_chn_direction_t relay_chn_ctl_get_direction(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
return relay_chn_is_channel_id_valid(chn_id)
|
||||||
return RELAY_CHN_DIRECTION_DEFAULT;
|
? relay_chn_output_get_direction(s_chn_ctls[chn_id].output)
|
||||||
}
|
: RELAY_CHN_DIRECTION_DEFAULT;
|
||||||
relay_chn_ctl_t *chn_ctl = &chn_ctls[chn_id];
|
|
||||||
return relay_chn_output_get_direction(chn_ctl->output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
esp_err_t relay_chn_ctl_get_direction_all(relay_chn_direction_t *directions)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(directions != NULL, ESP_ERR_INVALID_ARG, TAG, "directions cannot be NULL");
|
||||||
|
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
relay_chn_direction_t *dest_direction = &directions[i];
|
||||||
|
if (dest_direction == NULL) {
|
||||||
|
ESP_LOGW(TAG, "get_direction_all: Directions have been copied until channel %d since directions[%d] is NULL", i, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*dest_direction = relay_chn_output_get_direction(s_chn_ctls[i].output);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
uint16_t relay_chn_ctl_get_run_limit(uint8_t chn_id)
|
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) {
|
return relay_chn_is_channel_id_valid(chn_id) ? s_chn_ctls[chn_id].run_limit_sec : 0;
|
||||||
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)
|
esp_err_t relay_chn_ctl_get_run_limit_all(uint16_t *limits_sec)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) {
|
ESP_RETURN_ON_FALSE(limits_sec != NULL, ESP_ERR_INVALID_ARG, TAG, "limits_sec cannot be NULL");
|
||||||
|
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
uint16_t *dest_limit_sec = &limits_sec[i];
|
||||||
|
if (dest_limit_sec == NULL) {
|
||||||
|
ESP_LOGW(TAG, "get_run_limit_all: Run limits have been copied until channel %d since limits_sec[%d] is NULL", i, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*dest_limit_sec = s_chn_ctls[i].run_limit_sec;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void relay_chn_ctl_set_run_limit_common(uint8_t chn_id, uint16_t limit_sec)
|
||||||
|
{
|
||||||
|
// Check for boundaries
|
||||||
|
if (limit_sec > CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC)
|
||||||
|
limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC;
|
||||||
|
else if (limit_sec < CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC)
|
||||||
|
limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC;
|
||||||
|
|
||||||
|
s_chn_ctls[chn_id].run_limit_sec = limit_sec;
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
|
relay_chn_nvs_set_run_limit(chn_id, limit_sec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void relay_chn_ctl_set_run_limit(uint8_t chn_id, uint16_t limit_sec)
|
||||||
|
{
|
||||||
|
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
ESP_LOGE(TAG, "set_run_limit: Invalid channel ID: %d", chn_id);
|
ESP_LOGE(TAG, "set_run_limit: Invalid channel ID: %d", chn_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
relay_chn_ctl_set_run_limit_common(chn_id, limit_sec);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for boundaries
|
esp_err_t relay_chn_ctl_set_run_limit_all(uint16_t *limits_sec)
|
||||||
if (time_sec > RELAY_CHN_RUN_LIMIT_MAX_SEC)
|
{
|
||||||
time_sec = RELAY_CHN_RUN_LIMIT_MAX_SEC;
|
ESP_RETURN_ON_FALSE(limits_sec != NULL, ESP_ERR_INVALID_ARG, TAG, "limits_sec cannot be NULL");
|
||||||
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;
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
uint16_t *src_limit_sec = &limits_sec[i];
|
||||||
|
if (src_limit_sec == NULL) {
|
||||||
|
ESP_LOGW(TAG, "set_run_limit_all: Run limits have been set until channel %d since limits_sec[%d] is NULL", i, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
relay_chn_ctl_set_run_limit_common(i, *src_limit_sec);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
esp_err_t relay_chn_ctl_set_run_limit_all_with(uint16_t limit_sec)
|
||||||
relay_chn_nvs_set_run_limit(chn_id, time_sec);
|
{
|
||||||
#endif
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
relay_chn_ctl_set_run_limit_common(i, limit_sec);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
relay_chn_ctl_t *relay_chn_ctl_get(uint8_t chn_id)
|
relay_chn_ctl_t *relay_chn_ctl_get(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
return relay_chn_is_channel_id_valid(chn_id) ? &s_chn_ctls[chn_id] : NULL;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return &chn_ctls[chn_id];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
relay_chn_ctl_t *relay_chn_ctl_get_all(void)
|
relay_chn_ctl_t *relay_chn_ctl_get_all(void)
|
||||||
{
|
{
|
||||||
return chn_ctls;
|
return s_chn_ctls;
|
||||||
}
|
}
|
||||||
@@ -10,51 +10,49 @@
|
|||||||
#include "relay_chn_ctl.h"
|
#include "relay_chn_ctl.h"
|
||||||
#include "relay_chn_output.h"
|
#include "relay_chn_output.h"
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char *TAG = "RELAY_CHN_CTL";
|
static const char *TAG = "RELAY_CHN_CTL";
|
||||||
|
|
||||||
static relay_chn_ctl_t chn_ctl;
|
static relay_chn_ctl_t s_chn_ctl;
|
||||||
|
|
||||||
|
|
||||||
esp_err_t relay_chn_ctl_init(relay_chn_output_t *output, relay_chn_run_info_t *run_info)
|
esp_err_t relay_chn_ctl_init(relay_chn_output_t *output, relay_chn_run_info_t *run_info)
|
||||||
{
|
{
|
||||||
// Initialize the relay channel
|
// Initialize the relay channel
|
||||||
chn_ctl.id = 0; // Single channel, so ID is 0
|
s_chn_ctl.id = 0; // Single channel, so ID is 0
|
||||||
chn_ctl.state = RELAY_CHN_STATE_IDLE;
|
s_chn_ctl.state = RELAY_CHN_STATE_IDLE;
|
||||||
chn_ctl.pending_cmd = RELAY_CHN_CMD_NONE;
|
s_chn_ctl.pending_cmd = RELAY_CHN_CMD_NONE;
|
||||||
chn_ctl.output = output;
|
s_chn_ctl.output = output;
|
||||||
chn_ctl.run_info = run_info;
|
s_chn_ctl.run_info = run_info;
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
uint16_t run_limit_sec = RELAY_CHN_RUN_LIMIT_DEFAULT_SEC;
|
uint16_t run_limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC;
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
// Load run limit value from NVS
|
// Load run limit value from NVS
|
||||||
ret = relay_chn_nvs_get_run_limit(chn_ctl.id, &run_limit_sec);
|
ret = relay_chn_nvs_get_run_limit(s_chn_ctl.id, &run_limit_sec, CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC);
|
||||||
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load run limit from NVS with error: %s", esp_err_to_name(ret));
|
||||||
ESP_LOGE(TAG, "Failed to load run limit from NVS with error: %s", esp_err_to_name(ret));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
chn_ctl.run_limit_sec = run_limit_sec;
|
s_chn_ctl.run_limit_sec = run_limit_sec;
|
||||||
ret = relay_chn_init_run_limit_timer(&chn_ctl);
|
ret = relay_chn_init_run_limit_timer(&s_chn_ctl);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize run limit timer");
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize run limit timer");
|
||||||
#endif
|
#endif
|
||||||
return relay_chn_init_timer(&chn_ctl); // Create direction change inertia timer
|
return relay_chn_init_timer(&s_chn_ctl); // Create direction change inertia timer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void relay_chn_ctl_deinit()
|
void relay_chn_ctl_deinit()
|
||||||
{
|
{
|
||||||
if (chn_ctl.inertia_timer != NULL) {
|
if (s_chn_ctl.inertia_timer != NULL) {
|
||||||
esp_timer_delete(chn_ctl.inertia_timer);
|
esp_timer_delete(s_chn_ctl.inertia_timer);
|
||||||
chn_ctl.inertia_timer = NULL;
|
s_chn_ctl.inertia_timer = NULL;
|
||||||
}
|
}
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
if (chn_ctl.run_limit_timer != NULL) {
|
if (s_chn_ctl.run_limit_timer != NULL) {
|
||||||
esp_timer_delete(chn_ctl.run_limit_timer);
|
esp_timer_delete(s_chn_ctl.run_limit_timer);
|
||||||
chn_ctl.run_limit_timer = NULL;
|
s_chn_ctl.run_limit_timer = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -62,57 +60,57 @@ void relay_chn_ctl_deinit()
|
|||||||
/* relay_chn APIs */
|
/* relay_chn APIs */
|
||||||
relay_chn_state_t relay_chn_ctl_get_state()
|
relay_chn_state_t relay_chn_ctl_get_state()
|
||||||
{
|
{
|
||||||
return chn_ctl.state;
|
return s_chn_ctl.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *relay_chn_ctl_get_state_str()
|
char *relay_chn_ctl_get_state_str()
|
||||||
{
|
{
|
||||||
return relay_chn_state_str(chn_ctl.state);
|
return relay_chn_state_str(s_chn_ctl.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_run_forward()
|
void relay_chn_ctl_run_forward()
|
||||||
{
|
{
|
||||||
relay_chn_issue_cmd(&chn_ctl, RELAY_CHN_CMD_FORWARD);
|
relay_chn_issue_cmd(&s_chn_ctl, RELAY_CHN_CMD_FORWARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_run_reverse()
|
void relay_chn_ctl_run_reverse()
|
||||||
{
|
{
|
||||||
relay_chn_issue_cmd(&chn_ctl, RELAY_CHN_CMD_REVERSE);
|
relay_chn_issue_cmd(&s_chn_ctl, RELAY_CHN_CMD_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_stop()
|
void relay_chn_ctl_stop()
|
||||||
{
|
{
|
||||||
relay_chn_issue_cmd(&chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_issue_cmd(&s_chn_ctl, RELAY_CHN_CMD_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_flip_direction()
|
void relay_chn_ctl_flip_direction()
|
||||||
{
|
{
|
||||||
relay_chn_issue_cmd(&chn_ctl, RELAY_CHN_CMD_FLIP);
|
relay_chn_issue_cmd(&s_chn_ctl, RELAY_CHN_CMD_FLIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
relay_chn_direction_t relay_chn_ctl_get_direction()
|
relay_chn_direction_t relay_chn_ctl_get_direction()
|
||||||
{
|
{
|
||||||
return relay_chn_output_get_direction(chn_ctl.output);
|
return relay_chn_output_get_direction(s_chn_ctl.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
uint16_t relay_chn_ctl_get_run_limit()
|
uint16_t relay_chn_ctl_get_run_limit()
|
||||||
{
|
{
|
||||||
return chn_ctl.run_limit_sec;
|
return s_chn_ctl.run_limit_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_ctl_set_run_limit(uint16_t time_sec)
|
void relay_chn_ctl_set_run_limit(uint16_t limit_sec)
|
||||||
{
|
{
|
||||||
// Check for boundaries
|
// Check for boundaries
|
||||||
if (time_sec > RELAY_CHN_RUN_LIMIT_MAX_SEC)
|
if (limit_sec > CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC)
|
||||||
time_sec = RELAY_CHN_RUN_LIMIT_MAX_SEC;
|
limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC;
|
||||||
else if (time_sec < RELAY_CHN_RUN_LIMIT_MIN_SEC)
|
else if (limit_sec < CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC)
|
||||||
time_sec = RELAY_CHN_RUN_LIMIT_MIN_SEC;
|
limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC;
|
||||||
|
|
||||||
chn_ctl.run_limit_sec = time_sec;
|
s_chn_ctl.run_limit_sec = limit_sec;
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
relay_chn_nvs_set_run_limit(chn_ctl.id, time_sec);
|
relay_chn_nvs_set_run_limit(s_chn_ctl.id, limit_sec);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -120,5 +118,5 @@ void relay_chn_ctl_set_run_limit(uint16_t time_sec)
|
|||||||
|
|
||||||
relay_chn_ctl_t *relay_chn_ctl_get()
|
relay_chn_ctl_t *relay_chn_ctl_get()
|
||||||
{
|
{
|
||||||
return &chn_ctl;
|
return &s_chn_ctl;
|
||||||
}
|
}
|
||||||
268
src/relay_chn_notify.c
Normal file
268
src/relay_chn_notify.c
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "relay_chn_notify.h"
|
||||||
|
|
||||||
|
static const char *TAG = "RELAY_CHN_NOTIFY";
|
||||||
|
|
||||||
|
// --- Config ---
|
||||||
|
#define RELAY_CHN_NOTIFY_QUEUE_LEN (16 + CONFIG_RELAY_CHN_COUNT * 4)
|
||||||
|
#define RELAY_CHN_NOTIFY_TASK_STACK 2048
|
||||||
|
#define RELAY_CHN_NOTIFY_TASK_PRIO (tskIDLE_PRIORITY + 5)
|
||||||
|
|
||||||
|
/// @brief Structure to hold a listener entry in the linked list.
|
||||||
|
typedef struct relay_chn_listener_entry_type {
|
||||||
|
relay_chn_state_listener_t listener; /*!< The listener function pointer */
|
||||||
|
ListItem_t list_item; /*!< FreeRTOS list item */
|
||||||
|
} relay_chn_listener_entry_t;
|
||||||
|
|
||||||
|
/// @brief Command types for the notification queue.
|
||||||
|
typedef enum {
|
||||||
|
RELAY_CHN_NOTIFY_CMD_BROADCAST, /*!< A relay channel state has changed. */
|
||||||
|
RELAY_CHN_NOTIFY_CMD_ADD_LISTENER, /*!< Request to add a new listener. */
|
||||||
|
RELAY_CHN_NOTIFY_CMD_REMOVE_LISTENER, /*!< Request to remove a listener. */
|
||||||
|
} relay_chn_notify_cmd_t;
|
||||||
|
|
||||||
|
/// @brief Payload for a state change event.
|
||||||
|
typedef struct {
|
||||||
|
uint8_t chn_id;
|
||||||
|
relay_chn_state_t old_state;
|
||||||
|
relay_chn_state_t new_state;
|
||||||
|
} relay_chn_notify_event_data_t;
|
||||||
|
|
||||||
|
/// @brief The command structure sent to the notification queue.
|
||||||
|
typedef struct {
|
||||||
|
relay_chn_notify_cmd_t cmd;
|
||||||
|
union {
|
||||||
|
relay_chn_notify_event_data_t event_data; /*!< Used for RELAY_CHN_NOTIFY_CMD_BROADCAST */
|
||||||
|
relay_chn_state_listener_t listener; /*!< Used for ADD/REMOVE listener commands */
|
||||||
|
} payload;
|
||||||
|
} relay_chn_notify_msg_t;
|
||||||
|
|
||||||
|
// The list that holds references to the registered listeners.
|
||||||
|
static List_t s_listeners;
|
||||||
|
|
||||||
|
static QueueHandle_t s_notify_queue = NULL;
|
||||||
|
static TaskHandle_t s_notify_task = NULL;
|
||||||
|
|
||||||
|
static void relay_chn_notify_task(void *arg);
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t relay_chn_notify_init(void)
|
||||||
|
{
|
||||||
|
if (s_notify_queue != NULL) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_notify_queue = xQueueCreate(RELAY_CHN_NOTIFY_QUEUE_LEN, sizeof(relay_chn_notify_msg_t));
|
||||||
|
if (!s_notify_queue) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create notify queue");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the notify dispatcher task
|
||||||
|
BaseType_t ret = xTaskCreate(relay_chn_notify_task, "task_rlch_ntfy",
|
||||||
|
RELAY_CHN_NOTIFY_TASK_STACK, NULL,
|
||||||
|
RELAY_CHN_NOTIFY_TASK_PRIO, &s_notify_task);
|
||||||
|
if (ret != pdPASS) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create notify task");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init the state listener list
|
||||||
|
vListInitialise(&s_listeners);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void relay_chn_notify_deinit(void)
|
||||||
|
{
|
||||||
|
if (s_notify_task != NULL) {
|
||||||
|
vTaskDelete(s_notify_task);
|
||||||
|
s_notify_task = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_notify_queue != NULL) {
|
||||||
|
vQueueDelete(s_notify_queue);
|
||||||
|
s_notify_queue = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!listLIST_IS_EMPTY(&s_listeners)) {
|
||||||
|
// Free the listeners
|
||||||
|
while (listCURRENT_LIST_LENGTH(&s_listeners) > 0) {
|
||||||
|
ListItem_t *pxItem = listGET_HEAD_ENTRY(&s_listeners);
|
||||||
|
relay_chn_listener_entry_t *entry = listGET_LIST_ITEM_OWNER(pxItem);
|
||||||
|
uxListRemove(pxItem);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find a listener entry in the list by its function pointer.
|
||||||
|
*
|
||||||
|
* This function replaces the old index-based search and is used to check
|
||||||
|
* for the existence of a listener before registration or for finding it
|
||||||
|
* during unregistration.
|
||||||
|
*
|
||||||
|
* @param listener The listener function pointer to find.
|
||||||
|
* @return Pointer to the listener entry if found, otherwise NULL.
|
||||||
|
*/
|
||||||
|
static relay_chn_listener_entry_t* find_listener_entry(relay_chn_state_listener_t listener)
|
||||||
|
{
|
||||||
|
if (listLIST_IS_EMPTY(&s_listeners)) {
|
||||||
|
ESP_LOGD(TAG, "No listeners registered");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through the linked list of listeners
|
||||||
|
for (ListItem_t *pxListItem = listGET_HEAD_ENTRY(&s_listeners);
|
||||||
|
pxListItem != listGET_END_MARKER(&s_listeners);
|
||||||
|
pxListItem = listGET_NEXT(pxListItem)) {
|
||||||
|
|
||||||
|
relay_chn_listener_entry_t *entry = (relay_chn_listener_entry_t *) listGET_LIST_ITEM_OWNER(pxListItem);
|
||||||
|
if (entry->listener == listener) {
|
||||||
|
// Found the listener, return the entry
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listener was not found in the list
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_add_listener(relay_chn_state_listener_t listener)
|
||||||
|
{
|
||||||
|
// This is now only called from the dispatcher task, so no mutex needed.
|
||||||
|
if (find_listener_entry(listener) != NULL) {
|
||||||
|
ESP_LOGD(TAG, "Listener %p already registered", listener);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
relay_chn_listener_entry_t *entry = malloc(sizeof(relay_chn_listener_entry_t));
|
||||||
|
if (!entry) {
|
||||||
|
ESP_LOGE(TAG, "Failed to allocate memory for listener");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entry->listener = listener;
|
||||||
|
vListInitialiseItem(&(entry->list_item));
|
||||||
|
listSET_LIST_ITEM_OWNER(&(entry->list_item), (void *)entry);
|
||||||
|
vListInsertEnd(&s_listeners, &(entry->list_item));
|
||||||
|
ESP_LOGD(TAG, "Registered listener %p", listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_remove_listener(relay_chn_state_listener_t listener)
|
||||||
|
{
|
||||||
|
// This is now only called from the dispatcher task, so no mutex needed.
|
||||||
|
relay_chn_listener_entry_t *entry = find_listener_entry(listener);
|
||||||
|
if (entry != NULL) {
|
||||||
|
uxListRemove(&(entry->list_item));
|
||||||
|
free(entry);
|
||||||
|
ESP_LOGD(TAG, "Unregistered listener %p", listener);
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "Listener %p not found for unregistration.", listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listLIST_IS_EMPTY(&s_listeners)) {
|
||||||
|
// Flush all pending notifications in the queue
|
||||||
|
xQueueReset(s_notify_queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t relay_chn_notify_add_listener(relay_chn_state_listener_t listener)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(listener, ESP_ERR_INVALID_ARG, TAG, "Listener cannot be NULL");
|
||||||
|
ESP_RETURN_ON_FALSE(s_notify_queue, ESP_ERR_INVALID_STATE, TAG, "Notify module not initialized");
|
||||||
|
|
||||||
|
relay_chn_notify_msg_t msg = { .cmd = RELAY_CHN_NOTIFY_CMD_ADD_LISTENER, .payload.listener = listener };
|
||||||
|
if (xQueueSend(s_notify_queue, &msg, 0) != pdTRUE) {
|
||||||
|
ESP_LOGE(TAG, "Notify queue is full, failed to queue add_listener");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void relay_chn_notify_remove_listener(relay_chn_state_listener_t listener)
|
||||||
|
{
|
||||||
|
if (listener == NULL) {
|
||||||
|
ESP_LOGD(TAG, "Cannot unregister a NULL listener.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!s_notify_queue) {
|
||||||
|
ESP_LOGE(TAG, "Notify module not initialized, cannot remove listener");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relay_chn_notify_msg_t msg = { .cmd = RELAY_CHN_NOTIFY_CMD_REMOVE_LISTENER, .payload.listener = listener };
|
||||||
|
if (xQueueSendToFront(s_notify_queue, &msg, 0) != pdTRUE) {
|
||||||
|
ESP_LOGW(TAG, "Notify queue is full, failed to queue remove_listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t relay_chn_notify_state_change(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state)
|
||||||
|
{
|
||||||
|
if (!s_notify_queue) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
relay_chn_notify_msg_t msg = {
|
||||||
|
.cmd = RELAY_CHN_NOTIFY_CMD_BROADCAST,
|
||||||
|
.payload.event_data.chn_id = chn_id,
|
||||||
|
.payload.event_data.old_state = old_state,
|
||||||
|
.payload.event_data.new_state = new_state,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try to send, do not wait if the queue is full
|
||||||
|
if (xQueueSend(s_notify_queue, &msg, 0) != pdTRUE) {
|
||||||
|
ESP_LOGW(TAG, "Notify queue is full, dropping event: %d -> %d for #%d", old_state, new_state, chn_id);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_notify(relay_chn_notify_event_data_t *event_data)
|
||||||
|
{
|
||||||
|
// Iterate through the linked list of listeners and notify them.
|
||||||
|
// No mutex is needed as this is the only task accessing the list.
|
||||||
|
for (ListItem_t *pxListItem = listGET_HEAD_ENTRY(&s_listeners);
|
||||||
|
pxListItem != listGET_END_MARKER(&s_listeners);
|
||||||
|
pxListItem = listGET_NEXT(pxListItem)) {
|
||||||
|
relay_chn_listener_entry_t *entry = (relay_chn_listener_entry_t *) listGET_LIST_ITEM_OWNER(pxListItem);
|
||||||
|
if (entry && entry->listener) {
|
||||||
|
// Emit the state change to the listeners
|
||||||
|
entry->listener(event_data->chn_id, event_data->old_state, event_data->new_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Notify Task ----
|
||||||
|
static void relay_chn_notify_task(void *arg)
|
||||||
|
{
|
||||||
|
relay_chn_notify_msg_t msg;
|
||||||
|
for (;;) {
|
||||||
|
if (xQueueReceive(s_notify_queue, &msg, portMAX_DELAY) == pdTRUE) {
|
||||||
|
switch (msg.cmd) {
|
||||||
|
case RELAY_CHN_NOTIFY_CMD_BROADCAST: {
|
||||||
|
do_notify(&msg.payload.event_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RELAY_CHN_NOTIFY_CMD_ADD_LISTENER:
|
||||||
|
do_add_listener(msg.payload.listener);
|
||||||
|
break;
|
||||||
|
case RELAY_CHN_NOTIFY_CMD_REMOVE_LISTENER:
|
||||||
|
do_remove_listener(msg.payload.listener);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGE(TAG, "Unknown command type in notify queue: %d", msg.cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,133 +4,449 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* 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_check.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "nvs.h"
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
|
|
||||||
#define RELAY_CHN_KEY_DIR "dir" /*!< Direction key */
|
#define RELAY_CHN_KEY_DIR "dir" /*!< Direction key */
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
#define RELAY_CHN_KEY_RLIM(ch) "rlim_%d" /*!< Run limit key */
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
#define RELAY_CHN_KEY_RLIM_FMT "rlim_%d" /*!< Run limit key format for multi-channel */
|
||||||
|
#else
|
||||||
|
#define RELAY_CHN_KEY_RLIM "rlim_0" /*!< Run limit key for single-channel */
|
||||||
#endif
|
#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 */
|
|
||||||
#endif
|
#endif
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
#define RELAY_CHN_KEY_TSENS_FMT "tsens_%d" /*!< Tilt sensitivity key format for multi-channel */
|
||||||
|
#define RELAY_CHN_KEY_TCNT_FMT "tcnt_%d" /*!< Tilt count key format for multi-channel */
|
||||||
|
#else
|
||||||
|
#define RELAY_CHN_KEY_TSENS "tsens_0" /*!< Tilt sensitivity key for single-channel */
|
||||||
|
#define RELAY_CHN_KEY_TCNT "tcnt_0" /*!< Tilt count key for single-channel */
|
||||||
|
#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 const char *TAG = "RELAY_CHN_NVS";
|
||||||
|
|
||||||
static nvs_handle_t relay_chn_nvs;
|
static nvs_handle_t s_relay_chn_nvs;
|
||||||
|
static QueueHandle_t s_nvs_ops_queue = NULL;
|
||||||
|
static TaskHandle_t s_nvs_ops_task = NULL;
|
||||||
|
static SemaphoreHandle_t s_nvs_deinit_sem = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static void relay_chn_nvs_task(void *arg);
|
||||||
|
|
||||||
esp_err_t relay_chn_nvs_init()
|
esp_err_t relay_chn_nvs_init()
|
||||||
{
|
{
|
||||||
|
// Already initialized?
|
||||||
|
if (s_nvs_ops_queue != NULL) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_nvs_deinit_sem = xSemaphoreCreateBinary();
|
||||||
|
if (!s_nvs_deinit_sem) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create deinit semaphore");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_nvs_ops_queue = xQueueCreate(RELAY_CHN_NVS_QUEUE_LEN, sizeof(relay_chn_nvs_msg_t));
|
||||||
|
if (!s_nvs_ops_queue) {
|
||||||
|
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, &s_nvs_ops_task);
|
||||||
|
if (res != pdPASS) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create NVS task");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
#if RELAY_CHN_NVS_CUSTOM_PARTITION == 1
|
#if CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION
|
||||||
ret = nvs_open_from_partition(RELAY_CHN_NVS_CUSTOM_PARTITION_NAME,
|
ret = nvs_open_from_partition(CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME,
|
||||||
RELAY_CHN_NVS_NAMESPACE,
|
CONFIG_RELAY_CHN_NVS_NAMESPACE,
|
||||||
NVS_READWRITE,
|
NVS_READWRITE,
|
||||||
&relay_chn_nvs);
|
&s_relay_chn_nvs);
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(ret,
|
ESP_RETURN_ON_ERROR(ret,
|
||||||
TAG,
|
TAG,
|
||||||
"Failed to open NVS namespace '%s' from partition '%s' with error %s",
|
"Failed to open NVS namespace '%s' from partition '%s' with error %s",
|
||||||
RELAY_CHN_NVS_NAMESPACE,
|
CONFIG_RELAY_CHN_NVS_NAMESPACE,
|
||||||
RELAY_CHN_NVS_CUSTOM_PARTITION_NAME,
|
CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME,
|
||||||
esp_err_to_name(ret));
|
esp_err_to_name(ret));
|
||||||
#else
|
#else
|
||||||
ret = nvs_open(RELAY_CHN_NVS_NAMESPACE, NVS_READWRITE, &relay_chn_nvs);
|
ret = nvs_open(CONFIG_RELAY_CHN_NVS_NAMESPACE, NVS_READWRITE, &s_relay_chn_nvs);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to open NVS namespace '%s'", RELAY_CHN_NVS_NAMESPACE);
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to open NVS namespace '%s'", CONFIG_RELAY_CHN_NVS_NAMESPACE);
|
||||||
#endif // RELAY_CHN_NVS_CUSTOM_PARTITION
|
#endif // CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t relay_chn_nvs_enqueue(relay_chn_nvs_msg_t *msg, const char *op_name)
|
||||||
|
{
|
||||||
|
if (!s_nvs_ops_queue) {
|
||||||
|
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(s_nvs_ops_queue, 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(s_nvs_ops_queue, msg, 0) != pdTRUE) {
|
||||||
|
ESP_LOGW(TAG, "NVS queue is full, dropping %s for #%d", op_name, msg->ch);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t direction)
|
esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t direction)
|
||||||
{
|
{
|
||||||
uint8_t direction_val;
|
relay_chn_nvs_msg_t msg = {
|
||||||
esp_err_t ret = nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, &direction_val);
|
.op = RELAY_CHN_NVS_OP_SET_DIRECTION,
|
||||||
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
.ch = ch,
|
||||||
// The key does not exist yet, set it to zero which is the default direction
|
.data.data_u8 = (uint8_t) direction,
|
||||||
direction_val = RELAY_CHN_DIRECTION_DEFAULT;
|
};
|
||||||
} else if (ret != ESP_OK) {
|
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(s_relay_chn_nvs, RELAY_CHN_KEY_DIR, &direction_val);
|
||||||
|
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to get direction from NVS with error: %s", esp_err_to_name(ret));
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to get direction from NVS with error: %s", esp_err_to_name(ret));
|
||||||
}
|
}
|
||||||
direction_val &= ~(1 << ch); // Clear the bit for the channel
|
direction_val &= ~(1 << ch); // Clear the bit for the channel
|
||||||
direction_val |= (((uint8_t) direction) << ch); // Set the new direction bit
|
direction_val |= (((uint8_t) direction) << ch); // Set the new direction bit
|
||||||
ret = nvs_set_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, direction_val);
|
ret = nvs_set_u8(s_relay_chn_nvs, RELAY_CHN_KEY_DIR, direction_val);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set direction for channel %d", ch);
|
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");
|
ESP_RETURN_ON_FALSE(direction != NULL, ESP_ERR_INVALID_ARG, TAG, "Direction pointer is NULL");
|
||||||
|
|
||||||
uint8_t direction_val;
|
uint8_t direction_val;
|
||||||
esp_err_t ret = nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, &direction_val);
|
esp_err_t ret = nvs_get_u8(s_relay_chn_nvs, RELAY_CHN_KEY_DIR, &direction_val);
|
||||||
if (ret != ESP_OK) {
|
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
||||||
return ret; // Return error if the key does not exist
|
*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);
|
*direction = (relay_chn_direction_t)((direction_val >> ch) & 0x01);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
esp_err_t relay_chn_nvs_set_run_limit(uint8_t ch, uint16_t time_sec)
|
esp_err_t relay_chn_nvs_set_run_limit(uint8_t ch, uint16_t limit_sec)
|
||||||
{
|
{
|
||||||
esp_err_t ret = nvs_set_u16(relay_chn_nvs, RELAY_CHN_KEY_RLIM(ch), time_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
|
||||||
|
char key[NVS_KEY_NAME_MAX_SIZE];
|
||||||
|
snprintf(key, sizeof(key), RELAY_CHN_KEY_RLIM_FMT, ch);
|
||||||
|
ret = nvs_set_u16(s_relay_chn_nvs, key, limit_sec);
|
||||||
|
#else
|
||||||
|
ret = nvs_set_u16(s_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);
|
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 *time_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(time_sec != NULL, ESP_ERR_INVALID_ARG, TAG, "Run limit value pointer is NULL");
|
ESP_RETURN_ON_FALSE(limit_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);
|
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);
|
||||||
|
ret = nvs_get_u16(s_relay_chn_nvs, key, limit_sec);
|
||||||
|
#else
|
||||||
|
ret = nvs_get_u16(s_relay_chn_nvs, RELAY_CHN_KEY_RLIM, limit_sec);
|
||||||
|
#endif
|
||||||
|
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
||||||
|
*limit_sec = default_val;
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
return ret;
|
||||||
|
}
|
||||||
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
||||||
|
|
||||||
#ifdef RELAY_CHN_ENABLE_TILTING
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity)
|
esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity)
|
||||||
{
|
{
|
||||||
esp_err_t ret = nvs_set_u8(relay_chn_nvs, RELAY_CHN_KEY_TSENS(ch), sensitivity);
|
relay_chn_nvs_msg_t msg = {
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set tilt sensitivity for channel %d", ch);
|
.op = RELAY_CHN_NVS_OP_SET_TILT_SENSITIVITY,
|
||||||
return nvs_commit(relay_chn_nvs);
|
.ch = ch,
|
||||||
|
.data.data_u8 = sensitivity,
|
||||||
|
};
|
||||||
|
return relay_chn_nvs_enqueue(&msg, "SET_TILT_SENSITIVITY");
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t relay_chn_nvs_get_tilt_sensitivity(uint8_t ch, uint8_t *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
|
||||||
|
char key[NVS_KEY_NAME_MAX_SIZE];
|
||||||
|
snprintf(key, sizeof(key), RELAY_CHN_KEY_TSENS_FMT, ch);
|
||||||
|
ret = nvs_set_u8(s_relay_chn_nvs, key, sensitivity);
|
||||||
|
#else
|
||||||
|
ret = nvs_set_u8(s_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 ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_RETURN_ON_FALSE(sensitivity != NULL, ESP_ERR_INVALID_ARG, TAG, "Sensitivity pointer is NULL");
|
||||||
|
|
||||||
return nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_TSENS(ch), sensitivity);
|
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);
|
||||||
|
ret = nvs_get_u8(s_relay_chn_nvs, key, sensitivity);
|
||||||
|
#else
|
||||||
|
ret = nvs_get_u8(s_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)
|
esp_err_t relay_chn_nvs_set_tilt_count(uint8_t ch, uint16_t tilt_count)
|
||||||
{
|
{
|
||||||
esp_err_t ret;
|
relay_chn_nvs_msg_t msg = {
|
||||||
ret = nvs_set_u16(relay_chn_nvs, RELAY_CHN_KEY_TCNT(ch), tilt_count);
|
.op = RELAY_CHN_NVS_OP_SET_TILT_COUNT,
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to save tilt_count tilt counter");
|
.ch = ch,
|
||||||
return nvs_commit(relay_chn_nvs);
|
.data.data_u16 = tilt_count,
|
||||||
|
};
|
||||||
|
return relay_chn_nvs_enqueue(&msg, "SET_TILT_COUNT");
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t relay_chn_nvs_get_tilt_count(uint8_t ch, uint16_t *tilt_count)
|
static esp_err_t relay_chn_nvs_task_set_tilt_count(uint8_t ch, uint16_t tilt_count)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(tilt_count != NULL,
|
esp_err_t ret;
|
||||||
ESP_ERR_INVALID_ARG, TAG, "Counter pointers are NULL");
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
return nvs_get_u16(relay_chn_nvs, RELAY_CHN_KEY_TCNT(ch), tilt_count);
|
char key[NVS_KEY_NAME_MAX_SIZE];
|
||||||
|
snprintf(key, sizeof(key), RELAY_CHN_KEY_TCNT_FMT, ch);
|
||||||
|
ret = nvs_set_u16(s_relay_chn_nvs, key, tilt_count);
|
||||||
|
#else
|
||||||
|
ret = nvs_set_u16(s_relay_chn_nvs, RELAY_CHN_KEY_TCNT, tilt_count);
|
||||||
|
#endif
|
||||||
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to save tilt_count tilt counter");
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_ENABLE_TILTING
|
|
||||||
|
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);
|
||||||
|
ret = nvs_get_u16(s_relay_chn_nvs, key, tilt_count);
|
||||||
|
#else
|
||||||
|
ret = nvs_get_u16(s_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()
|
esp_err_t relay_chn_nvs_erase_all()
|
||||||
{
|
{
|
||||||
// Erase all key-value pairs in the relay_chn NVS namespace
|
relay_chn_nvs_msg_t msg = {
|
||||||
esp_err_t ret = nvs_erase_all(relay_chn_nvs);
|
.op = RELAY_CHN_NVS_OP_ERASE_ALL,
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to erase all keys in NVS namespace '%s'", RELAY_CHN_NVS_NAMESPACE);
|
};
|
||||||
|
return relay_chn_nvs_enqueue(&msg, "ERASE_ALL");
|
||||||
// Commit the changes
|
|
||||||
return nvs_commit(relay_chn_nvs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t relay_chn_nvs_deinit()
|
static esp_err_t do_nvs_deinit()
|
||||||
{
|
{
|
||||||
nvs_close(relay_chn_nvs);
|
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(s_nvs_ops_queue);
|
||||||
|
// Erase all key-value pairs in the relay_chn NVS namespace
|
||||||
|
esp_err_t ret = nvs_erase_all(s_relay_chn_nvs);
|
||||||
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to erase all keys in NVS namespace '%s'", CONFIG_RELAY_CHN_NVS_NAMESPACE);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void relay_chn_nvs_deinit()
|
||||||
|
{
|
||||||
|
if (s_nvs_ops_task) {
|
||||||
|
if (do_nvs_deinit() == ESP_OK) {
|
||||||
|
if (s_nvs_deinit_sem && xSemaphoreTake(s_nvs_deinit_sem, pdMS_TO_TICKS(2000)) != pdTRUE) {
|
||||||
|
ESP_LOGE(TAG, "Failed to get deinit confirmation from NVS task. Forcing deletion.");
|
||||||
|
vTaskDelete(s_nvs_ops_task); // Last resort
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Failed to send deinit message to NVS task. Forcing deletion.");
|
||||||
|
vTaskDelete(s_nvs_ops_task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s_nvs_ops_queue) {
|
||||||
|
vQueueDelete(s_nvs_ops_queue);
|
||||||
|
s_nvs_ops_queue = NULL;
|
||||||
|
}
|
||||||
|
if (s_nvs_deinit_sem) {
|
||||||
|
vSemaphoreDelete(s_nvs_deinit_sem);
|
||||||
|
s_nvs_deinit_sem = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close NVS handle here, after task has stopped and queue is deleted.
|
||||||
|
nvs_close(s_relay_chn_nvs);
|
||||||
|
s_nvs_ops_task = 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(s_nvs_ops_queue, &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(s_nvs_ops_queue, &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(s_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(s_relay_chn_nvs) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Final NVS commit failed on deinit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xSemaphoreGive(s_nvs_deinit_sem);
|
||||||
|
s_nvs_ops_task = NULL;
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
@@ -6,37 +6,36 @@
|
|||||||
|
|
||||||
#include "esp_check.h"
|
#include "esp_check.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "relay_chn_defs.h"
|
|
||||||
#include "relay_chn_output.h"
|
#include "relay_chn_output.h"
|
||||||
#include "relay_chn_core.h"
|
#include "relay_chn_core.h"
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static const char *TAG = "RELAY_CHN_OUTPUT";
|
static const char *TAG = "RELAY_CHN_OUTPUT";
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
static relay_chn_output_t outputs[RELAY_CHN_COUNT];
|
static relay_chn_output_t s_outputs[CONFIG_RELAY_CHN_COUNT];
|
||||||
#else
|
#else
|
||||||
static relay_chn_output_t output;
|
static relay_chn_output_t s_output;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static esp_err_t relay_chn_output_check_gpio_capabilities(uint8_t gpio_count)
|
static esp_err_t relay_chn_output_check_gpio_capabilities(uint8_t gpio_count)
|
||||||
{
|
{
|
||||||
// Check if the device's GPIOs are enough for the number of channels
|
// Check if the device's GPIOs are enough for the number of channels
|
||||||
if (RELAY_CHN_COUNT > (GPIO_PIN_COUNT / 2)) {
|
if (CONFIG_RELAY_CHN_COUNT > (GPIO_PIN_COUNT / 2)) {
|
||||||
ESP_LOGE(TAG, "Not enough GPIOs for the number of channels!");
|
ESP_LOGE(TAG, "Not enough GPIOs for the number of channels!");
|
||||||
ESP_LOGE(TAG, "Max available num of channels: %d, requested channels: %d", GPIO_PIN_COUNT / 2, RELAY_CHN_COUNT);
|
ESP_LOGE(TAG, "Max available num of channels: %d, requested channels: %d", GPIO_PIN_COUNT / 2, CONFIG_RELAY_CHN_COUNT);
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the provided GPIOs correspond to the number of channels
|
// Check if the provided GPIOs correspond to the number of channels
|
||||||
if (gpio_count != RELAY_CHN_COUNT * 2) {
|
if (gpio_count != CONFIG_RELAY_CHN_COUNT * 2) {
|
||||||
ESP_LOGE(TAG, "Invalid number of GPIOs provided: %d", gpio_count);
|
ESP_LOGE(TAG, "Invalid number of GPIOs provided: %d", gpio_count);
|
||||||
ESP_LOGE(TAG, "Expected number of GPIOs: %d", RELAY_CHN_COUNT * 2);
|
ESP_LOGE(TAG, "Expected number of GPIOs: %d", CONFIG_RELAY_CHN_COUNT * 2);
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@@ -73,16 +72,12 @@ static esp_err_t relay_chn_output_ctl_init(relay_chn_output_t *output,
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
static esp_err_t relay_chn_output_load_direction(uint8_t ch, relay_chn_direction_t *direction)
|
static esp_err_t relay_chn_output_load_direction(uint8_t ch, relay_chn_direction_t *direction)
|
||||||
{
|
{
|
||||||
esp_err_t ret = relay_chn_nvs_get_direction(ch, direction);
|
// relay_chn_nvs_get_direction handles the NOT_FOUND case and returns the provided default value.
|
||||||
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
esp_err_t ret = relay_chn_nvs_get_direction(ch, direction, RELAY_CHN_DIRECTION_DEFAULT);
|
||||||
// If the key does not exist, use the default direction
|
|
||||||
*direction = RELAY_CHN_DIRECTION_DEFAULT;
|
|
||||||
} else if (ret != ESP_OK) {
|
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to get direction from storage for channel %d: %s", ch, esp_err_to_name(ret));
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to get direction from storage for channel %d: %s", ch, esp_err_to_name(ret));
|
||||||
}
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -93,15 +88,15 @@ esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count)
|
|||||||
ret = relay_chn_output_check_gpio_capabilities(gpio_count);
|
ret = relay_chn_output_check_gpio_capabilities(gpio_count);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Device does not support the provided GPIOs");
|
ESP_RETURN_ON_ERROR(ret, TAG, "Device does not support the provided GPIOs");
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
relay_chn_output_t* output = &outputs[i];
|
relay_chn_output_t* output = &s_outputs[i];
|
||||||
int gpio_index = i << 1; // gpio_index = i * 2
|
int gpio_index = i << 1; // gpio_index = i * 2
|
||||||
gpio_num_t forward_pin = (gpio_num_t) gpio_map[gpio_index];
|
gpio_num_t forward_pin = (gpio_num_t) gpio_map[gpio_index];
|
||||||
gpio_num_t reverse_pin = (gpio_num_t) gpio_map[gpio_index + 1];
|
gpio_num_t reverse_pin = (gpio_num_t) gpio_map[gpio_index + 1];
|
||||||
|
|
||||||
relay_chn_direction_t direction = RELAY_CHN_DIRECTION_DEFAULT;
|
relay_chn_direction_t direction = RELAY_CHN_DIRECTION_DEFAULT;
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
// If NVS storage is enabled, retrieve the direction from storage
|
// If NVS storage is enabled, retrieve the direction from storage
|
||||||
ret = relay_chn_output_load_direction(i, &direction);
|
ret = relay_chn_output_load_direction(i, &direction);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load direction from storage for channel %d", i);
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load direction from storage for channel %d", i);
|
||||||
@@ -111,12 +106,12 @@ esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
relay_chn_direction_t direction = RELAY_CHN_DIRECTION_DEFAULT;
|
relay_chn_direction_t direction = RELAY_CHN_DIRECTION_DEFAULT;
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
// If NVS storage is enabled, retrieve the direction from storage
|
// If NVS storage is enabled, retrieve the direction from storage
|
||||||
ret = relay_chn_output_load_direction(0, &direction);
|
ret = relay_chn_output_load_direction(0, &direction);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load direction from storage for channel %d", 0);
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load direction from storage for channel %d", 0);
|
||||||
#endif
|
#endif
|
||||||
ret = relay_chn_output_ctl_init(&output, gpio_map[0], gpio_map[1], direction);
|
ret = relay_chn_output_ctl_init(&s_output, gpio_map[0], gpio_map[1], direction);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel");
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel");
|
||||||
#endif
|
#endif
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@@ -130,34 +125,34 @@ static void relay_chn_output_ctl_deinit(relay_chn_output_t *output)
|
|||||||
|
|
||||||
void relay_chn_output_deinit()
|
void relay_chn_output_deinit()
|
||||||
{
|
{
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
relay_chn_output_ctl_deinit(&outputs[i]);
|
relay_chn_output_ctl_deinit(&s_outputs[i]);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
relay_chn_output_ctl_deinit(&output);
|
relay_chn_output_ctl_deinit(&s_output);
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
relay_chn_output_t *relay_chn_output_get(uint8_t chn_id)
|
relay_chn_output_t *relay_chn_output_get(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &outputs[chn_id];
|
return &s_outputs[chn_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
relay_chn_output_t *relay_chn_output_get_all(void)
|
relay_chn_output_t *relay_chn_output_get_all(void)
|
||||||
{
|
{
|
||||||
return outputs;
|
return s_outputs;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
relay_chn_output_t *relay_chn_output_get(void)
|
relay_chn_output_t *relay_chn_output_get(void)
|
||||||
{
|
{
|
||||||
return &output;
|
return &s_output;
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
esp_err_t relay_chn_output_stop(relay_chn_output_t *output)
|
esp_err_t relay_chn_output_stop(relay_chn_output_t *output)
|
||||||
{
|
{
|
||||||
@@ -194,11 +189,11 @@ void relay_chn_output_flip(relay_chn_output_t *output)
|
|||||||
? RELAY_CHN_DIRECTION_FLIPPED
|
? RELAY_CHN_DIRECTION_FLIPPED
|
||||||
: RELAY_CHN_DIRECTION_DEFAULT;
|
: RELAY_CHN_DIRECTION_DEFAULT;
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
uint8_t ch = 0;
|
uint8_t ch = 0;
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
for (uint8_t i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
if (output == &outputs[i]) {
|
if (output == &s_outputs[i]) {
|
||||||
ch = i;
|
ch = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,44 +8,44 @@
|
|||||||
#include "relay_chn_run_info.h"
|
#include "relay_chn_run_info.h"
|
||||||
|
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
static relay_chn_run_info_t run_infos[RELAY_CHN_COUNT];
|
static relay_chn_run_info_t s_run_infos[CONFIG_RELAY_CHN_COUNT];
|
||||||
#else
|
#else
|
||||||
static relay_chn_run_info_t run_info;
|
static relay_chn_run_info_t s_run_info;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void relay_chn_run_info_init()
|
void relay_chn_run_info_init()
|
||||||
{
|
{
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
run_infos[i].last_run_cmd = RELAY_CHN_CMD_NONE;
|
s_run_infos[i].last_run_cmd = RELAY_CHN_CMD_NONE;
|
||||||
run_infos[i].last_run_cmd_time_ms = 0;
|
s_run_infos[i].last_run_cmd_time_ms = 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
run_info.last_run_cmd = RELAY_CHN_CMD_NONE;
|
s_run_info.last_run_cmd = RELAY_CHN_CMD_NONE;
|
||||||
run_info.last_run_cmd_time_ms = 0;
|
s_run_info.last_run_cmd_time_ms = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
relay_chn_run_info_t *relay_chn_run_info_get(uint8_t chn_id)
|
relay_chn_run_info_t *relay_chn_run_info_get(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &run_infos[chn_id];
|
return &s_run_infos[chn_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
relay_chn_run_info_t *relay_chn_run_info_get_all()
|
relay_chn_run_info_t *relay_chn_run_info_get_all()
|
||||||
{
|
{
|
||||||
return run_infos;
|
return s_run_infos;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
relay_chn_run_info_t *relay_chn_run_info_get()
|
relay_chn_run_info_t *relay_chn_run_info_get()
|
||||||
{
|
{
|
||||||
return &run_info;
|
return &s_run_info;
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
relay_chn_cmd_t relay_chn_run_info_get_last_run_cmd(relay_chn_run_info_t *run_info)
|
relay_chn_cmd_t relay_chn_run_info_get_last_run_cmd(relay_chn_run_info_t *run_info)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "relay_chn_run_info.h"
|
#include "relay_chn_run_info.h"
|
||||||
#include "relay_chn_tilt.h"
|
#include "relay_chn_tilt.h"
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
|
|
||||||
#define RELAY_CHN_TILT_FLUSH_DEBOUNCE_MS 3000
|
#define RELAY_CHN_TILT_FLUSH_DEBOUNCE_MS 3000
|
||||||
@@ -39,6 +39,7 @@ 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) )
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
#define ADJUST_TILT_SENS_BOUNDARIES(sens) if (sens > 100) sens = 100
|
||||||
|
|
||||||
/// @brief Tilt steps.
|
/// @brief Tilt steps.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -63,16 +64,16 @@ typedef struct relay_chn_tilt_ctl {
|
|||||||
relay_chn_tilt_timing_t tilt_timing; /*!< Tilt timing structure */
|
relay_chn_tilt_timing_t tilt_timing; /*!< Tilt timing structure */
|
||||||
uint16_t tilt_count; /*!< Tilt count to manage forward and reverse tilts */
|
uint16_t tilt_count; /*!< Tilt count to manage forward and reverse tilts */
|
||||||
esp_timer_handle_t tilt_timer; /*!< Tilt timer handle */
|
esp_timer_handle_t tilt_timer; /*!< Tilt timer handle */
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
esp_timer_handle_t flush_timer; /*!< Flush timer to avoid frequent write of tilt counters */
|
esp_timer_handle_t flush_timer; /*!< Flush timer to avoid frequent write of tilt counters */
|
||||||
#endif
|
#endif
|
||||||
} relay_chn_tilt_ctl_t;
|
} relay_chn_tilt_ctl_t;
|
||||||
|
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
static relay_chn_tilt_ctl_t tilt_ctls[RELAY_CHN_COUNT];
|
static relay_chn_tilt_ctl_t s_tilt_ctls[CONFIG_RELAY_CHN_COUNT];
|
||||||
#else
|
#else
|
||||||
static relay_chn_tilt_ctl_t tilt_ctl;
|
static relay_chn_tilt_ctl_t s_tilt_ctl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -87,12 +88,34 @@ static uint32_t relay_chn_tilt_get_required_timing_before_tilting(relay_chn_tilt
|
|||||||
|
|
||||||
uint32_t last_run_cmd_time_ms = relay_chn_run_info_get_last_run_cmd_time_ms(tilt_ctl->chn_ctl->run_info);
|
uint32_t last_run_cmd_time_ms = relay_chn_run_info_get_last_run_cmd_time_ms(tilt_ctl->chn_ctl->run_info);
|
||||||
uint32_t inertia_time_passed_ms = (uint32_t) (esp_timer_get_time() / 1000) - last_run_cmd_time_ms;
|
uint32_t inertia_time_passed_ms = (uint32_t) (esp_timer_get_time() / 1000) - last_run_cmd_time_ms;
|
||||||
return RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
return CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void relay_chn_tilt_execute_stop(relay_chn_tilt_ctl_t *tilt_ctl);
|
||||||
|
|
||||||
|
static void relay_chn_tilt_start_timer_or_stop(relay_chn_tilt_ctl_t *tilt_ctl, esp_timer_handle_t timer, uint32_t time_ms, const char* timer_name)
|
||||||
|
{
|
||||||
|
if (relay_chn_start_esp_timer_once(timer, time_ms) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to start %s timer for ch %d", timer_name, tilt_ctl->chn_ctl->id);
|
||||||
|
// Attempt to go to a safe state for tilt.
|
||||||
|
// relay_chn_tilt_execute_stop is safe to call, it stops timers and sets state.
|
||||||
|
relay_chn_tilt_execute_stop(tilt_ctl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue a tilt command to a specific relay channel.
|
// Issue a tilt command to a specific relay channel.
|
||||||
static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd)
|
static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd)
|
||||||
{
|
{
|
||||||
|
// TILT_STOP is safe and high priority
|
||||||
|
if (cmd == RELAY_CHN_TILT_CMD_STOP) {
|
||||||
|
if (tilt_ctl->chn_ctl->state == RELAY_CHN_STATE_STOPPED) {
|
||||||
|
return; // Do nothing if already stopped
|
||||||
|
}
|
||||||
|
// If the command is TILT_STOP, issue it immediately
|
||||||
|
relay_chn_tilt_dispatch_cmd(tilt_ctl, cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (relay_chn_run_info_get_last_run_cmd(tilt_ctl->chn_ctl->run_info) == RELAY_CHN_CMD_NONE) {
|
if (relay_chn_run_info_get_last_run_cmd(tilt_ctl->chn_ctl->run_info) == RELAY_CHN_CMD_NONE) {
|
||||||
// Do not tilt if the channel hasn't been run before
|
// Do not tilt if the channel hasn't been run before
|
||||||
ESP_LOGD(TAG, "relay_chn_tilt_issue_cmd: Tilt will not be executed since the channel hasn't been run yet");
|
ESP_LOGD(TAG, "relay_chn_tilt_issue_cmd: Tilt will not be executed since the channel hasn't been run yet");
|
||||||
@@ -116,7 +139,7 @@ static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_t
|
|||||||
case RELAY_CHN_STATE_REVERSE_PENDING:
|
case RELAY_CHN_STATE_REVERSE_PENDING:
|
||||||
// Issue a stop command first so that the timer and pending cmd get cleared
|
// Issue a stop command first so that the timer and pending cmd get cleared
|
||||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||||
// break not put intentionally
|
// FALLTHRU
|
||||||
case RELAY_CHN_STATE_STOPPED: {
|
case RELAY_CHN_STATE_STOPPED: {
|
||||||
// Check if channel needs timing before tilting
|
// Check if channel needs timing before tilting
|
||||||
uint32_t req_timing_ms = relay_chn_tilt_get_required_timing_before_tilting(tilt_ctl, cmd);
|
uint32_t req_timing_ms = relay_chn_tilt_get_required_timing_before_tilting(tilt_ctl, cmd);
|
||||||
@@ -125,7 +148,7 @@ static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_t
|
|||||||
} else {
|
} else {
|
||||||
// Channel needs timing before running tilting action, schedule it
|
// Channel needs timing before running tilting action, schedule it
|
||||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
||||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, req_timing_ms);
|
relay_chn_tilt_start_timer_or_stop(tilt_ctl, tilt_ctl->tilt_timer, req_timing_ms, "pending tilt");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -136,7 +159,7 @@ static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_t
|
|||||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||||
// Schedule for tilting
|
// Schedule for tilting
|
||||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
||||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
relay_chn_tilt_start_timer_or_stop(tilt_ctl, tilt_ctl->tilt_timer, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS, "tilt inertia");
|
||||||
} else if (cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
} else if (cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||||
// Stop the running channel first
|
// Stop the running channel first
|
||||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||||
@@ -151,7 +174,7 @@ static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_t
|
|||||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||||
// Schedule for tilting
|
// Schedule for tilting
|
||||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
||||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
relay_chn_tilt_start_timer_or_stop(tilt_ctl, tilt_ctl->tilt_timer, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS, "tilt inertia");
|
||||||
} else if (cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
} else if (cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||||
// Stop the running channel first
|
// Stop the running channel first
|
||||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||||
@@ -176,100 +199,93 @@ static void relay_chn_tilt_issue_auto(relay_chn_tilt_ctl_t *tilt_ctl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
uint8_t relay_chn_tilt_get_default_sensitivity()
|
||||||
void relay_chn_tilt_auto(uint8_t chn_id)
|
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
return RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute for all channels
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
|
||||||
relay_chn_tilt_issue_auto(&tilt_ctls[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Execute for a single channel
|
|
||||||
else {
|
|
||||||
relay_chn_tilt_ctl_t* tilt_ctl = &tilt_ctls[chn_id];
|
|
||||||
relay_chn_tilt_issue_auto(tilt_ctl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
static void relay_chn_tilt_issue_cmd_on_all_channels(relay_chn_tilt_cmd_t cmd)
|
static void relay_chn_tilt_issue_cmd_on_all_channels(relay_chn_tilt_cmd_t cmd)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
relay_chn_tilt_ctl_t* tilt_ctl = &tilt_ctls[i];
|
relay_chn_tilt_ctl_t* tilt_ctl = &s_tilt_ctls[i];
|
||||||
relay_chn_tilt_issue_cmd(tilt_ctl, cmd);
|
relay_chn_tilt_issue_cmd(tilt_ctl, cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void relay_chn_tilt_auto(uint8_t chn_id)
|
||||||
|
{
|
||||||
|
if (relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
|
relay_chn_tilt_issue_auto(&s_tilt_ctls[chn_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void relay_chn_tilt_auto_all()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
relay_chn_tilt_issue_auto(&s_tilt_ctls[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void relay_chn_tilt_forward(uint8_t chn_id)
|
void relay_chn_tilt_forward(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
if (relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
return;
|
relay_chn_tilt_issue_cmd(&s_tilt_ctls[chn_id], RELAY_CHN_TILT_CMD_FORWARD);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL)
|
void relay_chn_tilt_forward_all()
|
||||||
|
{
|
||||||
relay_chn_tilt_issue_cmd_on_all_channels(RELAY_CHN_TILT_CMD_FORWARD);
|
relay_chn_tilt_issue_cmd_on_all_channels(RELAY_CHN_TILT_CMD_FORWARD);
|
||||||
else {
|
|
||||||
relay_chn_tilt_ctl_t* tilt_ctl = &tilt_ctls[chn_id];
|
|
||||||
relay_chn_tilt_issue_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_FORWARD);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_tilt_reverse(uint8_t chn_id)
|
void relay_chn_tilt_reverse(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
if (relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
return;
|
relay_chn_tilt_issue_cmd(&s_tilt_ctls[chn_id], RELAY_CHN_TILT_CMD_REVERSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL)
|
void relay_chn_tilt_reverse_all()
|
||||||
|
{
|
||||||
relay_chn_tilt_issue_cmd_on_all_channels(RELAY_CHN_TILT_CMD_REVERSE);
|
relay_chn_tilt_issue_cmd_on_all_channels(RELAY_CHN_TILT_CMD_REVERSE);
|
||||||
else {
|
|
||||||
relay_chn_tilt_ctl_t* tilt_ctl = &tilt_ctls[chn_id];
|
|
||||||
relay_chn_tilt_issue_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_REVERSE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_tilt_stop(uint8_t chn_id)
|
void relay_chn_tilt_stop(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
return;
|
relay_chn_tilt_dispatch_cmd(&s_tilt_ctls[chn_id], RELAY_CHN_TILT_CMD_STOP);
|
||||||
}
|
|
||||||
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
|
||||||
relay_chn_tilt_dispatch_cmd(&tilt_ctls[i], RELAY_CHN_TILT_CMD_STOP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
relay_chn_tilt_dispatch_cmd(&tilt_ctls[chn_id], RELAY_CHN_TILT_CMD_STOP);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // RELAY_CHN_COUNT > 1
|
void relay_chn_tilt_stop_all()
|
||||||
|
{
|
||||||
|
relay_chn_tilt_issue_cmd_on_all_channels(RELAY_CHN_TILT_CMD_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
void relay_chn_tilt_auto()
|
void relay_chn_tilt_auto()
|
||||||
{
|
{
|
||||||
relay_chn_tilt_issue_auto(&tilt_ctl);
|
relay_chn_tilt_issue_auto(&s_tilt_ctl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_tilt_forward()
|
void relay_chn_tilt_forward()
|
||||||
{
|
{
|
||||||
relay_chn_tilt_issue_cmd(&tilt_ctl, RELAY_CHN_TILT_CMD_FORWARD);
|
relay_chn_tilt_issue_cmd(&s_tilt_ctl, RELAY_CHN_TILT_CMD_FORWARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_tilt_reverse()
|
void relay_chn_tilt_reverse()
|
||||||
{
|
{
|
||||||
relay_chn_tilt_issue_cmd(&tilt_ctl, RELAY_CHN_TILT_CMD_REVERSE);
|
relay_chn_tilt_issue_cmd(&s_tilt_ctl, RELAY_CHN_TILT_CMD_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_tilt_stop()
|
void relay_chn_tilt_stop()
|
||||||
{
|
{
|
||||||
relay_chn_tilt_dispatch_cmd(&tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
relay_chn_tilt_dispatch_cmd(&s_tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
static void relay_chn_tilt_set_timing_values(relay_chn_tilt_timing_t *tilt_timing,
|
static void relay_chn_tilt_set_timing_values(relay_chn_tilt_timing_t *tilt_timing,
|
||||||
uint8_t sensitivity,
|
uint8_t sensitivity,
|
||||||
@@ -314,48 +330,67 @@ static void relay_chn_tilt_compute_set_sensitivity(relay_chn_tilt_ctl_t *tilt_ct
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
void relay_chn_tilt_set_sensitivity(uint8_t chn_id, uint8_t sensitivity)
|
void relay_chn_tilt_set_sensitivity(uint8_t chn_id, uint8_t sensitivity)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
if (relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
return;
|
ADJUST_TILT_SENS_BOUNDARIES(sensitivity);
|
||||||
}
|
relay_chn_tilt_compute_set_sensitivity(&s_tilt_ctls[chn_id], sensitivity);
|
||||||
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
|
||||||
relay_chn_tilt_compute_set_sensitivity(&tilt_ctls[i], sensitivity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
relay_chn_tilt_compute_set_sensitivity(&tilt_ctls[chn_id], sensitivity);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
|
||||||
relay_chn_nvs_set_tilt_sensitivity(chn_id, sensitivity);
|
relay_chn_nvs_set_tilt_sensitivity(chn_id, sensitivity);
|
||||||
#endif // RELAY_CHN_ENABLE_NVS
|
#endif // CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t relay_chn_tilt_get_sensitivity(uint8_t chn_id, uint8_t *sensitivity, size_t length)
|
esp_err_t relay_chn_tilt_set_sensitivity_all(uint8_t *sensitivities)
|
||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
ESP_RETURN_ON_FALSE(sensitivities != NULL, ESP_ERR_INVALID_ARG, TAG, "set_sensitivity_all: sensitivities is NULL");
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if (sensitivity == NULL) {
|
|
||||||
ESP_LOGD(TAG, "relay_chn_tilt_get_sensitivity: sensitivity is NULL");
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
if (length < RELAY_CHN_COUNT) {
|
|
||||||
ESP_LOGD(TAG, "relay_chn_tilt_get_sensitivity: length is too short to store all sensitivity values");
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
sensitivity[i] = tilt_ctls[i].tilt_timing.sensitivity;
|
uint8_t *src_sensitivity = &sensitivities[i];
|
||||||
|
if (src_sensitivity == NULL) {
|
||||||
|
ESP_LOGW(TAG, "set_sensitivity_all: Run limits have been set until channel %d since sensitivities[%d] is NULL", i, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ADJUST_TILT_SENS_BOUNDARIES(*src_sensitivity);
|
||||||
|
relay_chn_tilt_compute_set_sensitivity(&s_tilt_ctls[i], *src_sensitivity);
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
|
relay_chn_nvs_set_tilt_sensitivity(i, *src_sensitivity);
|
||||||
|
#endif // CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
*sensitivity = tilt_ctls[chn_id].tilt_timing.sensitivity;
|
|
||||||
|
void relay_chn_tilt_set_sensitivity_all_with(uint8_t sensitivity)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
ADJUST_TILT_SENS_BOUNDARIES(sensitivity);
|
||||||
|
relay_chn_tilt_compute_set_sensitivity(&s_tilt_ctls[i], sensitivity);
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
|
relay_chn_nvs_set_tilt_sensitivity(i, sensitivity);
|
||||||
|
#endif // CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t relay_chn_tilt_get_sensitivity(uint8_t chn_id)
|
||||||
|
{
|
||||||
|
return relay_chn_is_channel_id_valid(chn_id) ?
|
||||||
|
s_tilt_ctls[chn_id].tilt_timing.sensitivity : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t relay_chn_tilt_get_sensitivity_all(uint8_t *sensitivities)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(sensitivities != NULL, ESP_ERR_INVALID_ARG, TAG, "get_sensitivity_all: sensitivities is NULL");
|
||||||
|
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
uint8_t *dest_sensitivity = &sensitivities[i];
|
||||||
|
if (dest_sensitivity == NULL) {
|
||||||
|
ESP_LOGW(TAG, "get_sensitivity_all: Sensitivites have been copied until channel %d since sensitivities[%d] is NULL", i, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*dest_sensitivity = s_tilt_ctls[i].tilt_timing.sensitivity;
|
||||||
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,24 +398,25 @@ esp_err_t relay_chn_tilt_get_sensitivity(uint8_t chn_id, uint8_t *sensitivity, s
|
|||||||
|
|
||||||
void relay_chn_tilt_set_sensitivity(uint8_t sensitivity)
|
void relay_chn_tilt_set_sensitivity(uint8_t sensitivity)
|
||||||
{
|
{
|
||||||
relay_chn_tilt_compute_set_sensitivity(&tilt_ctl, sensitivity);
|
ADJUST_TILT_SENS_BOUNDARIES(sensitivity);
|
||||||
|
relay_chn_tilt_compute_set_sensitivity(&s_tilt_ctl, sensitivity);
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
relay_chn_nvs_set_tilt_sensitivity(0, sensitivity);
|
relay_chn_nvs_set_tilt_sensitivity(0, sensitivity);
|
||||||
#endif // RELAY_CHN_ENABLE_NVS
|
#endif // CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t relay_chn_tilt_get_sensitivity()
|
uint8_t relay_chn_tilt_get_sensitivity()
|
||||||
{
|
{
|
||||||
return tilt_ctl.tilt_timing.sensitivity;
|
return s_tilt_ctl.tilt_timing.sensitivity;
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
|
||||||
void relay_chn_tilt_reset_count(relay_chn_tilt_ctl_t *tilt_ctl)
|
void relay_chn_tilt_reset_count(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||||
{
|
{
|
||||||
tilt_ctl->tilt_count = 0;
|
tilt_ctl->tilt_count = 0;
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
esp_timer_stop(tilt_ctl->flush_timer);
|
esp_timer_stop(tilt_ctl->flush_timer);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -450,7 +486,7 @@ static uint16_t relay_chn_tilt_count_update(relay_chn_tilt_ctl_t *tilt_ctl)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
static esp_err_t relay_chn_tilt_save_tilt_count(relay_chn_tilt_ctl_t *tilt_ctl)
|
static esp_err_t relay_chn_tilt_save_tilt_count(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||||
{
|
{
|
||||||
// Save the tilt count to NVS storage
|
// Save the tilt count to NVS storage
|
||||||
@@ -484,11 +520,14 @@ static void relay_chn_tilt_execute_stop(relay_chn_tilt_ctl_t *tilt_ctl)
|
|||||||
if (relay_chn_output_stop(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
if (relay_chn_output_stop(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_stop: Failed to output stop for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
ESP_LOGE(TAG, "relay_chn_tilt_execute_stop: Failed to output stop for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
||||||
}
|
}
|
||||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_IDLE);
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
// Start the flush debounce timer
|
// Start the flush debounce timer
|
||||||
relay_chn_start_esp_timer_once(tilt_ctl->flush_timer, RELAY_CHN_TILT_FLUSH_DEBOUNCE_MS);
|
if (relay_chn_start_esp_timer_once(tilt_ctl->flush_timer, RELAY_CHN_TILT_FLUSH_DEBOUNCE_MS) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to start tilt flush timer for ch %d", tilt_ctl->chn_ctl->id);
|
||||||
|
// This is not a critical failure, just log it. The count will be saved on next stop.
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,11 +536,11 @@ static void relay_chn_tilt_execute_forward(relay_chn_tilt_ctl_t *tilt_ctl)
|
|||||||
if (relay_chn_output_reverse(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
if (relay_chn_output_reverse(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_forward: Failed to output reverse for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
ESP_LOGE(TAG, "relay_chn_tilt_execute_forward: Failed to output reverse for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
||||||
// Stop tilting because of the error
|
// Stop tilting because of the error
|
||||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
relay_chn_tilt_execute_stop(tilt_ctl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Set the move time timer
|
// Set the move time timer
|
||||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.move_time_ms);
|
relay_chn_tilt_start_timer_or_stop(tilt_ctl, tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.move_time_ms, "tilt move");
|
||||||
// Set to pause step
|
// Set to pause step
|
||||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PAUSE;
|
tilt_ctl->step = RELAY_CHN_TILT_STEP_PAUSE;
|
||||||
}
|
}
|
||||||
@@ -511,11 +550,11 @@ static void relay_chn_tilt_execute_reverse(relay_chn_tilt_ctl_t *tilt_ctl)
|
|||||||
if (relay_chn_output_forward(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
if (relay_chn_output_forward(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_reverse: Failed to output forward for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
ESP_LOGE(TAG, "relay_chn_tilt_execute_reverse: Failed to output forward for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
||||||
// Stop tilting because of the error
|
// Stop tilting because of the error
|
||||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
relay_chn_tilt_execute_stop(tilt_ctl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Set the move time timer
|
// Set the move time timer
|
||||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.move_time_ms);
|
relay_chn_tilt_start_timer_or_stop(tilt_ctl, tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.move_time_ms, "tilt move");
|
||||||
// Set to pause step
|
// Set to pause step
|
||||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PAUSE;
|
tilt_ctl->step = RELAY_CHN_TILT_STEP_PAUSE;
|
||||||
}
|
}
|
||||||
@@ -526,7 +565,7 @@ static void relay_chn_tilt_execute_pause(relay_chn_tilt_ctl_t *tilt_ctl)
|
|||||||
if (relay_chn_output_stop(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
if (relay_chn_output_stop(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_pause: Failed to output stop for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
ESP_LOGE(TAG, "relay_chn_tilt_execute_pause: Failed to output stop for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
||||||
// Stop tilting because of the error
|
// Stop tilting because of the error
|
||||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
relay_chn_tilt_execute_stop(tilt_ctl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,12 +573,12 @@ static void relay_chn_tilt_execute_pause(relay_chn_tilt_ctl_t *tilt_ctl)
|
|||||||
if (relay_chn_tilt_count_update(tilt_ctl) == 0) {
|
if (relay_chn_tilt_count_update(tilt_ctl) == 0) {
|
||||||
ESP_LOGD(TAG, "relay_chn_tilt_execute_pause: Relay channel cannot tilt anymore");
|
ESP_LOGD(TAG, "relay_chn_tilt_execute_pause: Relay channel cannot tilt anymore");
|
||||||
// Stop tilting since the tilting limit has been reached
|
// Stop tilting since the tilting limit has been reached
|
||||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
relay_chn_tilt_execute_stop(tilt_ctl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the pause time timer
|
// Set the pause time timer
|
||||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.pause_time_ms);
|
relay_chn_tilt_start_timer_or_stop(tilt_ctl, tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.pause_time_ms, "tilt pause");
|
||||||
// Set to move step
|
// Set to move step
|
||||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_MOVE;
|
tilt_ctl->step = RELAY_CHN_TILT_STEP_MOVE;
|
||||||
}
|
}
|
||||||
@@ -599,30 +638,22 @@ static void relay_chn_tilt_timer_cb(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
static esp_err_t relay_chn_tilt_load_sensitivity(uint8_t ch, uint8_t *sensitivity)
|
static esp_err_t relay_chn_tilt_load_sensitivity(uint8_t ch, uint8_t *sensitivity)
|
||||||
{
|
{
|
||||||
esp_err_t ret = relay_chn_nvs_get_tilt_sensitivity(ch, sensitivity);
|
ESP_RETURN_ON_ERROR(relay_chn_nvs_get_tilt_sensitivity(ch, sensitivity, RELAY_CHN_TILT_DEFAULT_SENSITIVITY),
|
||||||
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
TAG, "Failed to load tilt sensitivity for channel %d", ch);
|
||||||
*sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt sensitivity for channel %d", ch);
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t relay_chn_tilt_load_tilt_count(uint8_t ch, uint16_t *tilt_count)
|
static esp_err_t relay_chn_tilt_load_tilt_count(uint8_t ch, uint16_t *tilt_count)
|
||||||
{
|
{
|
||||||
esp_err_t ret = relay_chn_nvs_get_tilt_count(ch, tilt_count);
|
ESP_RETURN_ON_ERROR(relay_chn_nvs_get_tilt_count(ch, tilt_count, 0),
|
||||||
if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
TAG, "Failed to load tilt counters for channel %d", ch);
|
||||||
ESP_LOGD(TAG, "relay_chn_tilt_load_tilt_count: No tilt count found in NVS for channel %d, initializing to zero", ch);
|
ESP_LOGD(TAG, "Loaded tilt count for channel %d: %d", ch, *tilt_count);
|
||||||
tilt_count = 0;
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt counters for channel %d", ch);
|
#endif // CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
#endif // RELAY_CHN_ENABLE_NVS
|
|
||||||
|
|
||||||
static esp_err_t relay_chn_tilt_ctl_init(relay_chn_tilt_ctl_t *tilt_ctl,
|
static esp_err_t relay_chn_tilt_ctl_init(relay_chn_tilt_ctl_t *tilt_ctl,
|
||||||
relay_chn_ctl_t *chn_ctl,
|
relay_chn_ctl_t *chn_ctl,
|
||||||
@@ -648,7 +679,7 @@ static esp_err_t relay_chn_tilt_ctl_init(relay_chn_tilt_ctl_t *tilt_ctl,
|
|||||||
esp_err_t ret = esp_timer_create(&timer_args, &tilt_ctl->tilt_timer);
|
esp_err_t ret = esp_timer_create(&timer_args, &tilt_ctl->tilt_timer);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create tilt timer for channel %d", chn_ctl->id);
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create tilt timer for channel %d", chn_ctl->id);
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
// Create flush timer for the tilt counters
|
// Create flush timer for the tilt counters
|
||||||
snprintf(timer_name, sizeof(timer_name), "relay_chn_%2d_tilt_flush_timer", chn_ctl->id);
|
snprintf(timer_name, sizeof(timer_name), "relay_chn_%2d_tilt_flush_timer", chn_ctl->id);
|
||||||
timer_args.callback = relay_chn_tilt_flush_timer_cb;
|
timer_args.callback = relay_chn_tilt_flush_timer_cb;
|
||||||
@@ -664,32 +695,33 @@ esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls)
|
|||||||
uint8_t sensitivity;
|
uint8_t sensitivity;
|
||||||
uint16_t tilt_count;
|
uint16_t tilt_count;
|
||||||
|
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
esp_err_t ret;
|
||||||
esp_err_t ret = relay_chn_tilt_load_sensitivity(i, &sensitivity);
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
|
ret = relay_chn_tilt_load_sensitivity(i, &sensitivity);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt sensitivity for channel %d", i);
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt sensitivity for channel %d", i);
|
||||||
ret = relay_chn_tilt_load_tilt_count(i, &tilt_count);
|
ret = relay_chn_tilt_load_tilt_count(i, &tilt_count);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt count for channel %d", i);
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt count for channel %d", i);
|
||||||
#else
|
#else
|
||||||
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 // CONFIG_RELAY_CHN_ENABLE_NVS == 1
|
||||||
ret = relay_chn_tilt_ctl_init(&tilt_ctls[i], &chn_ctls[i], tilt_count, sensitivity);
|
ret = relay_chn_tilt_ctl_init(&s_tilt_ctls[i], &chn_ctls[i], tilt_count, sensitivity);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to init tilt control for channel %d", i);
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to init tilt control for channel %d", i);
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
#else
|
#else
|
||||||
sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
|
sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
|
||||||
tilt_count = 0;
|
tilt_count = 0;
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
esp_err_t ret = relay_chn_tilt_load_sensitivity(0, &sensitivity);
|
esp_err_t ret = relay_chn_tilt_load_sensitivity(0, &sensitivity);
|
||||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt sensitivity for channel %d", 0);
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt sensitivity for channel %d", 0);
|
||||||
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 // CONFIG_RELAY_CHN_ENABLE_NVS == 1
|
||||||
return relay_chn_tilt_ctl_init(&tilt_ctl, chn_ctls, tilt_count, sensitivity);
|
return relay_chn_tilt_ctl_init(&s_tilt_ctl, chn_ctls, tilt_count, sensitivity);
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -698,21 +730,21 @@ void relay_chn_tilt_ctl_deinit(relay_chn_tilt_ctl_t *tilt_ctl)
|
|||||||
esp_timer_delete(tilt_ctl->tilt_timer);
|
esp_timer_delete(tilt_ctl->tilt_timer);
|
||||||
tilt_ctl->tilt_timer = NULL;
|
tilt_ctl->tilt_timer = NULL;
|
||||||
}
|
}
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
if (tilt_ctl->flush_timer != NULL) {
|
if (tilt_ctl->flush_timer != NULL) {
|
||||||
esp_timer_delete(tilt_ctl->flush_timer);
|
esp_timer_delete(tilt_ctl->flush_timer);
|
||||||
tilt_ctl->flush_timer = NULL;
|
tilt_ctl->flush_timer = NULL;
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_ENABLE_NVS == 1
|
#endif // CONFIG_RELAY_CHN_ENABLE_NVS == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_tilt_deinit()
|
void relay_chn_tilt_deinit()
|
||||||
{
|
{
|
||||||
#if RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
relay_chn_tilt_ctl_deinit(&tilt_ctls[i]);
|
relay_chn_tilt_ctl_deinit(&s_tilt_ctls[i]);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
relay_chn_tilt_ctl_deinit(&tilt_ctl);
|
relay_chn_tilt_ctl_deinit(&s_tilt_ctl);
|
||||||
#endif // RELAY_CHN_COUNT > 1
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||||
}
|
}
|
||||||
23
test_apps/.vscode/c_cpp_properties.json
vendored
Normal file
23
test_apps/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "ESP-IDF",
|
||||||
|
"compilerPath": "${config:idf.toolsPath}/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc",
|
||||||
|
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
|
||||||
|
"includePath": [
|
||||||
|
"${config:idf.espIdfPath}/components/**",
|
||||||
|
"${config:idf.espIdfPathWin}/components/**",
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"browse": {
|
||||||
|
"path": [
|
||||||
|
"${config:idf.espIdfPath}/components",
|
||||||
|
"${config:idf.espIdfPathWin}/components",
|
||||||
|
"${workspaceFolder}"
|
||||||
|
],
|
||||||
|
"limitSymbolsToIncludedHeaders": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
15
test_apps/.vscode/launch.json
vendored
Normal file
15
test_apps/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "gdbtarget",
|
||||||
|
"request": "attach",
|
||||||
|
"name": "Eclipse CDT GDB Adapter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "espidf",
|
||||||
|
"name": "Launch",
|
||||||
|
"request": "launch"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
# === These files must be included in any case ===
|
# === These files must be included in any case ===
|
||||||
set(srcs "test_common.c"
|
set(srcs "test_common.c"
|
||||||
|
"test_relay_chn_notify_common.c"
|
||||||
"test_app_main.c")
|
"test_app_main.c")
|
||||||
|
|
||||||
set(incdirs ".")
|
set(incdirs "."
|
||||||
|
"../../private_include")
|
||||||
|
|
||||||
# === Selective compilation based on channel count ===
|
# === Selective compilation based on channel count ===
|
||||||
if(CONFIG_RELAY_CHN_COUNT GREATER 1)
|
if(CONFIG_RELAY_CHN_COUNT GREATER 1)
|
||||||
list(APPEND srcs "test_relay_chn_core_multi.c"
|
list(APPEND srcs "test_relay_chn_core_multi.c"
|
||||||
"test_relay_chn_listener_multi.c")
|
"test_relay_chn_notify_multi.c")
|
||||||
else()
|
else()
|
||||||
list(APPEND srcs "test_relay_chn_core_single.c"
|
list(APPEND srcs "test_relay_chn_core_single.c"
|
||||||
"test_relay_chn_listener_single.c")
|
"test_relay_chn_notify_single.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CONFIG_RELAY_CHN_ENABLE_TILTING)
|
if(CONFIG_RELAY_CHN_ENABLE_TILTING)
|
||||||
@@ -22,7 +24,6 @@ if(CONFIG_RELAY_CHN_ENABLE_TILTING)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CONFIG_RELAY_CHN_ENABLE_NVS)
|
if(CONFIG_RELAY_CHN_ENABLE_NVS)
|
||||||
list(APPEND incdirs "../../private_include")
|
|
||||||
list(APPEND srcs "../../src/relay_chn_nvs.c")
|
list(APPEND srcs "../../src/relay_chn_nvs.c")
|
||||||
if(CONFIG_RELAY_CHN_COUNT GREATER 1)
|
if(CONFIG_RELAY_CHN_COUNT GREATER 1)
|
||||||
list(APPEND srcs "test_relay_chn_nvs_multi.c")
|
list(APPEND srcs "test_relay_chn_nvs_multi.c")
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
@@ -7,7 +12,7 @@
|
|||||||
#include "unity_test_runner.h"
|
#include "unity_test_runner.h"
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
#if RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -25,21 +30,21 @@ void setUp()
|
|||||||
|
|
||||||
void tearDown()
|
void tearDown()
|
||||||
{
|
{
|
||||||
reset_channels_to_idle_state();
|
reset_channels_to_defaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
static void test_nvs_flash_init(void)
|
static void test_nvs_flash_init(void)
|
||||||
{
|
{
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
#if RELAY_CHN_NVS_CUSTOM_PARTITION == 1
|
#if CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION
|
||||||
ret = nvs_flash_init_partition(RELAY_CHN_NVS_CUSTOM_PARTITION_NAME);
|
ret = nvs_flash_init_partition(CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME);
|
||||||
ESP_LOGI(TEST_TAG, "test_nvs_flash_init: NVS flash init partition return: %s", esp_err_to_name(ret));
|
ESP_LOGI(TEST_TAG, "test_nvs_flash_init: NVS flash init partition return: %s", esp_err_to_name(ret));
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
// NVS partition is truncated and needs to be erased
|
// NVS partition is truncated and needs to be erased
|
||||||
ret = nvs_flash_erase_partition(RELAY_CHN_NVS_CUSTOM_PARTITION_NAME);
|
ret = nvs_flash_erase_partition(CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME);
|
||||||
if (ret == ESP_OK) {
|
if (ret == ESP_OK) {
|
||||||
ret = nvs_flash_init_partition(RELAY_CHN_NVS_CUSTOM_PARTITION_NAME);
|
ret = nvs_flash_init_partition(CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -57,12 +62,12 @@ TEST_ESP_OK(ret);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
static void test_nvs_flash_deinit(void)
|
static void test_nvs_flash_deinit(void)
|
||||||
{
|
{
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
#if RELAY_CHN_NVS_CUSTOM_PARTITION == 1
|
#if CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION
|
||||||
ret = nvs_flash_deinit_partition(RELAY_CHN_NVS_CUSTOM_PARTITION_NAME);
|
ret = nvs_flash_deinit_partition(CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME);
|
||||||
#else
|
#else
|
||||||
ret = nvs_flash_deinit();
|
ret = nvs_flash_deinit();
|
||||||
#endif
|
#endif
|
||||||
@@ -72,7 +77,7 @@ static void test_nvs_flash_deinit(void)
|
|||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
// Init NVS once for all tests
|
// Init NVS once for all tests
|
||||||
test_nvs_flash_init();
|
test_nvs_flash_init();
|
||||||
#endif
|
#endif
|
||||||
@@ -98,7 +103,7 @@ void app_main(void)
|
|||||||
// Destroy relay_chn
|
// Destroy relay_chn
|
||||||
relay_chn_destroy();
|
relay_chn_destroy();
|
||||||
|
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_NVS == 1
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
// Deinit NVS
|
// Deinit NVS
|
||||||
test_nvs_flash_deinit();
|
test_nvs_flash_deinit();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
#include "relay_chn_ctl.h" // For resetting the channels
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
#include "relay_chn_tilt.h" // For resetting tilt count
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *TEST_TAG = "RELAY_CHN_TEST";
|
const char *TEST_TAG = "RELAY_CHN_TEST";
|
||||||
|
|
||||||
const uint8_t relay_chn_count = CONFIG_RELAY_CHN_COUNT;
|
|
||||||
const uint32_t opposite_inertia_ms = CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS;
|
|
||||||
const uint32_t test_delay_margin_ms = 50; // ms tolerance
|
|
||||||
|
|
||||||
// Test-wide GPIO map
|
// Test-wide GPIO map
|
||||||
#if CONFIG_RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
const uint8_t gpio_map[] = {
|
const uint8_t gpio_map[] = {
|
||||||
@@ -36,17 +43,49 @@ const uint8_t gpio_map[] = {4, 5};
|
|||||||
|
|
||||||
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||||
|
|
||||||
void reset_channels_to_idle_state()
|
static void reset_channel(relay_chn_ctl_t *ctl)
|
||||||
{
|
{
|
||||||
|
ctl->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||||
|
ctl->state = RELAY_CHN_STATE_IDLE;
|
||||||
|
ctl->output->direction = RELAY_CHN_DIRECTION_DEFAULT;
|
||||||
|
ctl->run_info->last_run_cmd = RELAY_CHN_CMD_NONE;
|
||||||
|
ctl->run_info->last_run_cmd_time_ms = 0;
|
||||||
|
esp_timer_stop(ctl->inertia_timer);
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
|
esp_timer_stop(ctl->run_limit_timer);
|
||||||
|
ctl->run_limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC;
|
||||||
|
#endif
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
relay_chn_tilt_reset_count(ctl->tilt_ctl);
|
||||||
|
#endif
|
||||||
#if CONFIG_RELAY_CHN_COUNT > 1
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
relay_chn_stop(RELAY_CHN_ID_ALL);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
relay_chn_stop();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset_channels_to_defaults()
|
||||||
|
{
|
||||||
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||||
|
relay_chn_ctl_t *ctls = relay_chn_ctl_get_all();
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(ctls, "reset_channels_to_defaults: relay_chn_ctl_get_all() returned NULL");
|
||||||
|
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
relay_chn_ctl_t *ctl = &ctls[i];
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(ctl, "ctl is NULL");
|
||||||
|
reset_channel(ctl);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(i));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
relay_chn_ctl_t *ctl = relay_chn_ctl_get();
|
||||||
|
TEST_ASSERT_NOT_NULL_MESSAGE(ctl, "reset_channels_to_defaults: relay_chn_ctl_get() returned NULL");
|
||||||
|
reset_channel(ctl);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_state_listener(uint8_t id, relay_chn_state_t old_state, relay_chn_state_t new_state)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TEST_TAG, "test_state_listener: id: %d, old_state: %d, new_state: %d", id, old_state, new_state);
|
||||||
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string.h> // For memset
|
#include <string.h> // For memset
|
||||||
@@ -13,14 +19,12 @@ extern const char *TEST_TAG;
|
|||||||
// GPIO configurations
|
// GPIO configurations
|
||||||
extern const uint8_t gpio_map[];
|
extern const uint8_t gpio_map[];
|
||||||
extern const uint8_t gpio_count;
|
extern const uint8_t gpio_count;
|
||||||
extern const uint8_t relay_chn_count;
|
|
||||||
|
|
||||||
// Config variables for tests
|
// Config variables for tests
|
||||||
extern const uint32_t opposite_inertia_ms;
|
#define TEST_DELAY_MARGIN_MS 50
|
||||||
extern const uint32_t test_delay_margin_ms;
|
|
||||||
|
|
||||||
// Init state
|
|
||||||
extern bool g_is_component_initialized;
|
|
||||||
|
|
||||||
// Reset channels to Idle state
|
// Reset channels to Idle state
|
||||||
void reset_channels_to_idle_state(void);
|
void reset_channels_to_defaults(void);
|
||||||
|
|
||||||
|
// Relay channel state listener for tests
|
||||||
|
void test_state_listener(uint8_t id, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||||
@@ -1,5 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
|
static relay_chn_state_t s_states[CONFIG_RELAY_CHN_COUNT], s_expect_states[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
static relay_chn_direction_t s_directions[CONFIG_RELAY_CHN_COUNT], s_expect_directions[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
|
||||||
|
static void test_set_expected_state_all(relay_chn_state_t state)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
s_expect_states[i] = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_set_expected_direction_all(relay_chn_direction_t direction)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
s_expect_directions[i] = direction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Initialization Tests ---
|
// --- Initialization Tests ---
|
||||||
|
|
||||||
@@ -8,7 +31,7 @@ TEST_CASE("relay_chn_create handles invalid arguments", "[relay_chn][core]")
|
|||||||
// 1. Test with NULL gpio_map
|
// 1. Test with NULL gpio_map
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(NULL, gpio_count));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(NULL, gpio_count));
|
||||||
|
|
||||||
// 2. Test with incorrect gpio_count (must be RELAY_CHN_COUNT * 2)
|
// 2. Test with incorrect gpio_count (must be CONFIG_RELAY_CHN_COUNT * 2)
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, gpio_count - 1));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, gpio_count - 1));
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 1));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 1));
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 0));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 0));
|
||||||
@@ -21,89 +44,93 @@ TEST_CASE("relay_chn_create handles invalid arguments", "[relay_chn][core]")
|
|||||||
// --- Basic Functionality Tests ---
|
// --- Basic Functionality Tests ---
|
||||||
|
|
||||||
// TEST_CASE: Test that relay channels initialize correctly to RELAY_CHN_STATE_IDLE
|
// TEST_CASE: Test that relay channels initialize correctly to RELAY_CHN_STATE_IDLE
|
||||||
TEST_CASE("Relay channels initialize correctly to FREE state", "[relay_chn][core]") {
|
TEST_CASE("Relay channels initialize correctly to FREE state", "[relay_chn][core]")
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
{
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test that relays do nothing when an invlid channel id given
|
// TEST_CASE: Test that relays do nothing when an invlid channel id given
|
||||||
TEST_CASE("Run forward does nothing if channel id is invalid", "[relay_chn][core]") {
|
TEST_CASE("Run forward does nothing if channel id is invalid", "[relay_chn][core]")
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
{
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
relay_chn_run_forward(invalid_id); // relay_chn_run_forward returns void
|
int invalid_id = CONFIG_RELAY_CHN_COUNT * 2 + i;
|
||||||
|
relay_chn_run_forward(invalid_id);
|
||||||
// Short delay for state to update
|
// Short delay for state to update
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test that relays run in the forward direction and update their state
|
// TEST_CASE: Test that relays run in the forward direction and update their state
|
||||||
TEST_CASE("Relay channels run forward and update state", "[relay_chn][core]") {
|
TEST_CASE("Relay channels run forward and update state", "[relay_chn][core]")
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
{
|
||||||
relay_chn_run_forward(i); // relay_chn_run_forward returns void
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
relay_chn_run_forward(i);
|
||||||
// Short delay for state to update
|
// Short delay for state to update
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test that relays do nothing when an invlid channel id given
|
// TEST_CASE: Test that relays do nothing when an invlid channel id given
|
||||||
TEST_CASE("Run reverse does nothing if channel id is invalid", "[relay_chn][core]") {
|
TEST_CASE("Run reverse does nothing if channel id is invalid", "[relay_chn][core]")
|
||||||
|
{
|
||||||
// Verify that no valid channels were affected
|
// Verify that no valid channels were affected
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
int invalid_id = CONFIG_RELAY_CHN_COUNT * 2 + i;
|
||||||
// Call run_reverse with an invalid ID
|
// Call run_reverse with an invalid ID
|
||||||
relay_chn_run_reverse(invalid_id);
|
relay_chn_run_reverse(invalid_id);
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test that relays run in the reverse direction and update their state
|
// TEST_CASE: Test that relays run in the reverse direction and update their state
|
||||||
TEST_CASE("Relay channels run reverse and update state", "[relay_chn][core]") {
|
TEST_CASE("Relay channels run reverse and update state", "[relay_chn][core]")
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
{
|
||||||
relay_chn_run_reverse(i); // relay_chn_run_reverse returns void
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
relay_chn_run_reverse(i);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ### Broadcast Command (RELAY_CHN_ID_ALL) Tests
|
// ### Batch Control Tests
|
||||||
|
TEST_CASE("run_forward_all sets all channels to FORWARD", "[relay_chn][core][batch]")
|
||||||
TEST_CASE("run_forward with ID_ALL sets all channels to FORWARD", "[relay_chn][core][id_all]")
|
|
||||||
{
|
{
|
||||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
relay_chn_run_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("run_reverse with ID_ALL sets all channels to REVERSE", "[relay_chn][core][id_all]")
|
TEST_CASE("run_reverse_all sets all channels to REVERSE", "[relay_chn][core][batch]")
|
||||||
{
|
{
|
||||||
relay_chn_run_reverse(RELAY_CHN_ID_ALL);
|
relay_chn_run_reverse_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("stop with ID_ALL stops all running channels", "[relay_chn][core][id_all]")
|
TEST_CASE("stop_all stops all running channels", "[relay_chn][core][batch]")
|
||||||
{
|
{
|
||||||
// 1. Start all channels forward to ensure they are in a known running state
|
// 1. Start all channels forward to ensure they are in a known running state
|
||||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
relay_chn_run_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
// 2. Stop all channels using the broadcast command
|
// 2. Stop all channels
|
||||||
relay_chn_stop(RELAY_CHN_ID_ALL);
|
relay_chn_stop_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
// 3. Verify all channels have transitioned to the FREE state
|
// 3. Verify all channels have transitioned to the FREE state
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,84 +139,84 @@ TEST_CASE("stop with ID_ALL stops all running channels", "[relay_chn][core][id_a
|
|||||||
|
|
||||||
// TEST_CASE: Test that relays stop and transition to RELAY_CHN_STATE_IDLE
|
// TEST_CASE: Test that relays stop and transition to RELAY_CHN_STATE_IDLE
|
||||||
// This test also verifies the transition to FREE state after a STOP command.
|
// This test also verifies the transition to FREE state after a STOP command.
|
||||||
TEST_CASE("Relay channels stop and update to FREE state", "[relay_chn][core]") {
|
TEST_CASE("Relay channels stop and update to FREE state", "[relay_chn][core]")
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
{
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
// First, run forward to test stopping and transitioning to FREE state
|
// First, run forward to test stopping and transitioning to FREE state
|
||||||
relay_chn_run_forward(i); // relay_chn_run_forward returns void
|
relay_chn_run_forward(i);
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
||||||
|
|
||||||
// Now, issue the stop command
|
// Now, issue the stop command
|
||||||
relay_chn_stop(i); // relay_chn_stop returns void
|
relay_chn_stop(i);
|
||||||
// Immediately after stop, state should be STOPPED
|
// Immediately after stop, state should be STOPPED
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
|
|
||||||
// Then, wait for the inertia period for it to transition to RELAY_CHN_STATE_IDLE
|
// Then, wait for the inertia period for it to transition to RELAY_CHN_STATE_IDLE
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Get state should return UNDEFINED when id is not valid
|
// TEST_CASE: Get state should return UNDEFINED when id is not valid
|
||||||
TEST_CASE("Get state returns UNDEFINED when id is invalid", "[relay_chn][core]") {
|
TEST_CASE("Get state returns UNDEFINED when id is invalid", "[relay_chn][core]")
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
{
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
int invalid_id = CONFIG_RELAY_CHN_COUNT * 2 + i;
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_UNDEFINED, relay_chn_get_state(invalid_id));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_UNDEFINED, relay_chn_get_state(invalid_id));
|
||||||
}
|
}
|
||||||
// Test for running states also
|
// Test for running states also
|
||||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
relay_chn_run_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
int invalid_id = CONFIG_RELAY_CHN_COUNT * 2 + i;
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_UNDEFINED, relay_chn_get_state(invalid_id));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_UNDEFINED, relay_chn_get_state(invalid_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Get state string should return "UNKNOWN" when id is not valid
|
// TEST_CASE: Get state string should return "UNKNOWN" when id is not valid
|
||||||
TEST_CASE("Get state string returns UNKNOWN when id is invalid", "[relay_chn][core]") {
|
TEST_CASE("Get state string returns UNKNOWN when id is invalid", "[relay_chn][core]")
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
{
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
int invalid_id = CONFIG_RELAY_CHN_COUNT * 2 + i;
|
||||||
TEST_ASSERT_EQUAL_STRING("UNKNOWN", relay_chn_get_state_str(invalid_id));
|
TEST_ASSERT_EQUAL_STRING("UNKNOWN", relay_chn_get_state_str(invalid_id));
|
||||||
}
|
}
|
||||||
// Test for running states also
|
// Test for running states also
|
||||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
relay_chn_run_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
int invalid_id = CONFIG_RELAY_CHN_COUNT * 2 + i;
|
||||||
TEST_ASSERT_EQUAL_STRING("UNKNOWN", relay_chn_get_state_str(invalid_id));
|
TEST_ASSERT_EQUAL_STRING("UNKNOWN", relay_chn_get_state_str(invalid_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test independent operation of multiple relay channels
|
// TEST_CASE: Test independent operation of multiple relay channels
|
||||||
TEST_CASE("Multiple channels can operate independently", "[relay_chn][core]") {
|
TEST_CASE("Multiple channels can operate independently", "[relay_chn][core]")
|
||||||
if (relay_chn_count >= 2) {
|
{
|
||||||
// Start Channel 0 in forward direction
|
// Start Channel 0 in forward direction
|
||||||
relay_chn_run_forward(0); // relay_chn_run_forward returns void
|
relay_chn_run_forward(0);
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(0));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(0));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(1)); // Other channel should not be affected
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(1)); // Other channel should not be affected
|
||||||
|
|
||||||
// Start Channel 1 in reverse direction
|
// Start Channel 1 in reverse direction
|
||||||
relay_chn_run_reverse(1); // relay_chn_run_reverse returns void
|
relay_chn_run_reverse(1);
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(0));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(0));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(1));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(1));
|
||||||
|
|
||||||
// Stop Channel 0 and wait for it to become FREE
|
// Stop Channel 0 and wait for it to become FREE
|
||||||
relay_chn_stop(0); // relay_chn_stop returns void
|
relay_chn_stop(0);
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(0));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(0));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(1)); // Other channel should continue running
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(1)); // Other channel should continue running
|
||||||
|
|
||||||
// Stop Channel 1 and wait for it to become FREE
|
// Stop Channel 1 and wait for it to become FREE
|
||||||
relay_chn_stop(1); // relay_chn_stop returns void
|
relay_chn_stop(1);
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(0));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(0));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(1));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(1));
|
||||||
} else {
|
|
||||||
ESP_LOGW("TEST", "Skipping 'Multiple channels can operate independently' test: Not enough channels available.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -199,152 +226,221 @@ TEST_CASE("Multiple channels can operate independently", "[relay_chn][core]") {
|
|||||||
|
|
||||||
// TEST_CASE: Test transition from forward to reverse with inertia and state checks
|
// TEST_CASE: Test transition from forward to reverse with inertia and state checks
|
||||||
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_REVERSE
|
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_REVERSE
|
||||||
TEST_CASE("Forward to Reverse transition with opposite inertia", "[relay_chn][core][inertia]") {
|
TEST_CASE("Forward to Reverse transition with opposite inertia", "[relay_chn][core][inertia]")
|
||||||
uint8_t ch = 0; // Channel to test
|
{
|
||||||
|
|
||||||
// 1. Start in forward direction
|
// 1. Start in forward direction
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
relay_chn_run_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Short delay for state stabilization
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Short delay for state stabilization
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_FORWARD);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
// 2. Issue reverse command
|
// 2. Issue reverse command
|
||||||
relay_chn_run_reverse(ch); // relay_chn_run_reverse returns void
|
relay_chn_run_reverse_all();
|
||||||
// Immediately after the command, the motor should be stopped
|
// Immediately after the command, the motor should be stopped
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_REVERSE_PENDING);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
// Wait for the inertia period (after which the reverse command will be dispatched)
|
// Wait for the inertia period (after which the reverse command will be dispatched)
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch)); // Should now be in reverse state
|
// Should now be in reverse state
|
||||||
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_REVERSE);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from reverse to forward with inertia and state checks
|
// TEST_CASE: Test transition from reverse to forward with inertia and state checks
|
||||||
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_FORWARD
|
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_FORWARD
|
||||||
TEST_CASE("Reverse to Forward transition with opposite inertia", "[relay_chn][core][inertia]") {
|
TEST_CASE("Reverse to Forward transition with opposite inertia", "[relay_chn][core][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// 1. Start in reverse direction
|
// 1. Start in reverse direction
|
||||||
relay_chn_run_reverse(ch); // relay_chn_run_reverse returns void
|
relay_chn_run_reverse_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_REVERSE);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
// 2. Issue forward command
|
// 2. Issue forward command
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
relay_chn_run_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_FORWARD_PENDING);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
// Wait for inertia
|
// Wait for inertia
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_FORWARD);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test issuing the same run command while already running (no inertia expected)
|
// TEST_CASE: Test issuing the same run command while already running (no inertia expected)
|
||||||
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||||
TEST_CASE("Running in same direction does not incur inertia", "[relay_chn][core][inertia]") {
|
TEST_CASE("Running in same direction does not incur inertia", "[relay_chn][core][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// 1. Start in forward direction
|
// 1. Start in forward direction
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
relay_chn_run_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_FORWARD);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
// 2. Issue the same forward command again
|
// 2. Issue the same forward command again
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
relay_chn_run_forward_all();
|
||||||
// As per the code, is_direction_opposite_to_current_motion should return false, so no inertia.
|
// As per the code, is_direction_opposite_to_current_motion should return false, so no inertia.
|
||||||
// Just a short delay to check state remains the same.
|
// Just a short delay to check state remains the same.
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
}
|
test_set_expected_state_all(RELAY_CHN_STATE_FORWARD);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
// TEST_CASE: Test transition from FREE state to running (no inertia expected)
|
|
||||||
// Scenario: RELAY_CHN_STATE_IDLE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
|
||||||
TEST_CASE("FREE to Running transition without inertia", "[relay_chn][core][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
// setUp() should have already brought the channel to FREE state
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// Start in forward direction
|
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
|
||||||
// No inertia is expected when starting from FREE state.
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ### Direction Flipping Tests
|
// ### Direction Flipping Tests
|
||||||
|
|
||||||
TEST_CASE("Single channel direction can be flipped", "[relay_chn][core][direction]")
|
TEST_CASE("Direction can be flipped for each channel independently", "[relay_chn][core][direction]")
|
||||||
{
|
{
|
||||||
const uint8_t ch = 0;
|
|
||||||
|
|
||||||
// 1. Initial direction should be default
|
// 1. Initial direction should be default
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(ch));
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(i));
|
||||||
// 2. Flip the direction
|
|
||||||
relay_chn_flip_direction(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); // Wait for flip inertia
|
|
||||||
|
|
||||||
// 3. Verify direction is flipped
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(ch));
|
|
||||||
|
|
||||||
// 4. Flip back
|
|
||||||
relay_chn_flip_direction(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); // Wait for flip inertia
|
|
||||||
|
|
||||||
// 5. Verify direction is back to default
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(ch));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("All channels direction can be flipped simultaneously", "[relay_chn][core][direction][id_all]")
|
// 2. Flip the direction
|
||||||
{
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
// 1. Flip all channels
|
relay_chn_flip_direction(i);
|
||||||
relay_chn_flip_direction(RELAY_CHN_ID_ALL);
|
}
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS)); // Wait for flip inertia
|
||||||
|
|
||||||
// 2. Verify all channels are flipped
|
// 3. Verify direction is flipped
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Flip all back
|
// 4. Flip back
|
||||||
relay_chn_flip_direction(RELAY_CHN_ID_ALL);
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
relay_chn_flip_direction(i);
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS)); // Wait for flip inertia
|
||||||
|
|
||||||
// 4. Verify all channels are back to default
|
// 5. Verify direction is back to default
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("All channels direction can be flipped simultaneously", "[relay_chn][core][direction][batch]")
|
||||||
|
{
|
||||||
|
// 1. Flip all channels
|
||||||
|
relay_chn_flip_direction_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// 2. Verify all channels are flipped
|
||||||
|
TEST_ESP_OK(relay_chn_get_direction_all(s_directions));
|
||||||
|
test_set_expected_direction_all(RELAY_CHN_DIRECTION_FLIPPED);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_directions, s_directions, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
|
// 3. Flip all back
|
||||||
|
relay_chn_flip_direction_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// 4. Verify all channels are back to default
|
||||||
|
TEST_ESP_OK(relay_chn_get_direction_all(s_directions));
|
||||||
|
test_set_expected_direction_all(RELAY_CHN_DIRECTION_DEFAULT);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_directions, s_directions, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Flipping a running channel stops it and flips direction", "[relay_chn][core][direction]")
|
TEST_CASE("Flipping a running channel stops it and flips direction", "[relay_chn][core][direction]")
|
||||||
{
|
{
|
||||||
const uint8_t ch = 0;
|
|
||||||
|
|
||||||
// 1. Start channel running and verify state
|
// 1. Start channel running and verify state
|
||||||
relay_chn_run_forward(ch);
|
relay_chn_run_forward_all();
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_FORWARD);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
// 2. Flip the direction while running
|
// 2. Flip the direction while running
|
||||||
relay_chn_flip_direction(ch);
|
relay_chn_flip_direction_all();
|
||||||
|
|
||||||
// 3. The channel should stop as part of the flip process
|
// 3. The channel should stop as part of the flip process
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_STOPPED);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
// 4. Wait for the flip inertia to pass, after which it should be FREE and FLIPPED
|
// 4. Wait for the flip inertia to pass, after which it should be idle and FLIPPED
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(ch));
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_IDLE);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
|
TEST_ESP_OK(relay_chn_get_direction_all(s_directions));
|
||||||
|
test_set_expected_direction_all(RELAY_CHN_DIRECTION_FLIPPED);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_directions, s_directions, CONFIG_RELAY_CHN_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Direction flip handles invalid channel ID gracefully", "[relay_chn][core][direction]")
|
TEST_CASE("Direction flip handles invalid channel ID gracefully", "[relay_chn][core][direction]")
|
||||||
{
|
{
|
||||||
const uint8_t invalid_ch = relay_chn_count + 5;
|
const uint8_t invalid_ch = CONFIG_RELAY_CHN_COUNT + 5;
|
||||||
|
|
||||||
relay_chn_flip_direction(invalid_ch); // Call with an invalid ID
|
relay_chn_flip_direction(invalid_ch); // Call with an invalid ID
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(invalid_ch));
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(invalid_ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
TEST_CASE("get_state_all retrieves all channel states", "[relay_chn][core][batch]")
|
||||||
|
{
|
||||||
|
// 1. All should be IDLE initially
|
||||||
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
test_set_expected_state_all(RELAY_CHN_STATE_IDLE);
|
||||||
|
|
||||||
|
// 2. Set some states
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
relay_chn_run_forward(i);
|
||||||
|
} else {
|
||||||
|
relay_chn_run_reverse(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// 3. Get all states and verify
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
s_expect_states[i] = RELAY_CHN_STATE_FORWARD;
|
||||||
|
} else {
|
||||||
|
s_expect_states[i] = RELAY_CHN_STATE_REVERSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TEST_ESP_OK(relay_chn_get_state_all(s_states));
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_states, s_states, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("get_direction_all retrieves all channel directions", "[relay_chn][core][direction][batch]")
|
||||||
|
{
|
||||||
|
// 1. All should be default initially
|
||||||
|
TEST_ESP_OK(relay_chn_get_direction_all(s_directions));
|
||||||
|
test_set_expected_direction_all(RELAY_CHN_DIRECTION_DEFAULT);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_directions, s_directions, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
|
||||||
|
// 2. Flip all
|
||||||
|
relay_chn_flip_direction_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// 3. Get all directions and verify
|
||||||
|
TEST_ESP_OK(relay_chn_get_direction_all(s_directions));
|
||||||
|
test_set_expected_direction_all(RELAY_CHN_DIRECTION_FLIPPED);
|
||||||
|
TEST_ASSERT_EQUAL_UINT_ARRAY(s_expect_directions, s_directions, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("get_all functions handle NULL arguments", "[relay_chn][core][batch]")
|
||||||
|
{
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_get_state_all(NULL));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_get_direction_all(NULL));
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_get_run_limit_all(NULL));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_set_run_limit_all(NULL));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
#define TEST_RUN_LIMIT_SEC 5
|
#define TEST_RUN_LIMIT_SEC 5
|
||||||
#define TEST_SHORT_RUN_LIMIT_SEC 2
|
#define TEST_SHORT_RUN_LIMIT_SEC 2
|
||||||
// ### Run Limit Tests
|
// ### Run Limit Tests
|
||||||
@@ -380,7 +476,7 @@ TEST_CASE("Test run limit stops channel after timeout", "[relay_chn][run_limit]"
|
|||||||
relay_chn_set_run_limit(i, TEST_SHORT_RUN_LIMIT_SEC);
|
relay_chn_set_run_limit(i, TEST_SHORT_RUN_LIMIT_SEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
relay_chn_run_forward_all();
|
||||||
|
|
||||||
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
// Check running forward
|
// Check running forward
|
||||||
@@ -388,7 +484,7 @@ TEST_CASE("Test run limit stops channel after timeout", "[relay_chn][run_limit]"
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for run limit timeout
|
// Wait for run limit timeout
|
||||||
vTaskDelay(pdMS_TO_TICKS(TEST_SHORT_RUN_LIMIT_SEC * 1000 + test_delay_margin_ms));
|
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++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
}
|
}
|
||||||
@@ -396,28 +492,30 @@ TEST_CASE("Test run limit stops channel after timeout", "[relay_chn][run_limit]"
|
|||||||
|
|
||||||
TEST_CASE("Test run limit reset on direction change and time out finally", "[relay_chn][run_limit]")
|
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++) {
|
relay_chn_set_run_limit_all_with(TEST_SHORT_RUN_LIMIT_SEC);
|
||||||
// Set a short run limit
|
|
||||||
relay_chn_set_run_limit(i, TEST_SHORT_RUN_LIMIT_SEC);
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
|
// Wait for the NVS module task to process operations
|
||||||
|
vTaskDelay(300 / portTICK_PERIOD_MS); // Wait 1 second
|
||||||
|
#endif
|
||||||
|
|
||||||
// Start running forward
|
// Start running forward
|
||||||
relay_chn_run_forward(i);
|
relay_chn_run_forward_all();
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS); // Wait 1 second
|
vTaskDelay(1000 / portTICK_PERIOD_MS); // Wait 1 second
|
||||||
|
|
||||||
// Change direction before timeout
|
// Change direction before timeout
|
||||||
relay_chn_run_reverse(RELAY_CHN_ID_ALL);
|
relay_chn_run_reverse_all();
|
||||||
|
|
||||||
// Wait for the inertia period (after which the reverse command will be dispatched)
|
// Wait for the inertia period (after which the reverse command will be dispatched)
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(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
|
// 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));
|
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++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
@@ -438,4 +536,58 @@ TEST_CASE("Test run limit persistence across stop/start", "[relay_chn][run_limit
|
|||||||
TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit(i));
|
TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
|
||||||
|
TEST_CASE("Run limit functions handle invalid channel ID", "[relay_chn][run_limit]")
|
||||||
|
{
|
||||||
|
const uint8_t invalid_ch = CONFIG_RELAY_CHN_COUNT + 5;
|
||||||
|
const uint16_t original_limit = relay_chn_get_run_limit(0);
|
||||||
|
|
||||||
|
// get_run_limit with invalid ID should return 0
|
||||||
|
TEST_ASSERT_EQUAL(0, relay_chn_get_run_limit(invalid_ch));
|
||||||
|
|
||||||
|
// set_run_limit with invalid ID should not crash or affect other channels
|
||||||
|
relay_chn_set_run_limit(invalid_ch, 999);
|
||||||
|
TEST_ASSERT_EQUAL(original_limit, relay_chn_get_run_limit(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Run limit _all functions work correctly", "[relay_chn][run_limit][batch]")
|
||||||
|
{
|
||||||
|
// 1. Test set_run_limit_all_with
|
||||||
|
relay_chn_set_run_limit_all_with(TEST_RUN_LIMIT_SEC);
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Test get_run_limit_all
|
||||||
|
uint16_t limits[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
TEST_ESP_OK(relay_chn_get_run_limit_all(limits));
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, limits[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Test set_run_limit_all
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
limits[i] = TEST_RUN_LIMIT_SEC + i;
|
||||||
|
}
|
||||||
|
TEST_ESP_OK(relay_chn_set_run_limit_all(limits));
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC + i, relay_chn_get_run_limit(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
|
|
||||||
|
TEST_CASE("relay_chn_destroy allows clean-up and re-creation", "[relay_chn][core]")
|
||||||
|
{
|
||||||
|
relay_chn_run_forward_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
relay_chn_destroy();
|
||||||
|
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -8,7 +14,7 @@ TEST_CASE("relay_chn_create handles invalid arguments", "[relay_chn][core]")
|
|||||||
// 1. Test with NULL gpio_map
|
// 1. Test with NULL gpio_map
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(NULL, gpio_count));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(NULL, gpio_count));
|
||||||
|
|
||||||
// 2. Test with incorrect gpio_count (must be RELAY_CHN_COUNT * 2)
|
// 2. Test with incorrect gpio_count (must be CONFIG_RELAY_CHN_COUNT * 2)
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, gpio_count - 1));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, gpio_count - 1));
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 1));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 1));
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 0));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 0));
|
||||||
@@ -21,42 +27,46 @@ TEST_CASE("relay_chn_create handles invalid arguments", "[relay_chn][core]")
|
|||||||
// --- Basic Functionality Tests ---
|
// --- Basic Functionality Tests ---
|
||||||
|
|
||||||
// TEST_CASE: Test that relay channels initialize correctly to RELAY_CHN_STATE_IDLE
|
// TEST_CASE: Test that relay channels initialize correctly to RELAY_CHN_STATE_IDLE
|
||||||
TEST_CASE("Relay channels initialize correctly to IDLE state", "[relay_chn][core]") {
|
TEST_CASE("Relay channels initialize correctly to IDLE state", "[relay_chn][core]")
|
||||||
|
{
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test that relays run in the forward direction and update their state
|
// TEST_CASE: Test that relays run in the forward direction and update their state
|
||||||
TEST_CASE("Relay channels run forward and update state", "[relay_chn][core]") {
|
TEST_CASE("Relay channels run forward and update state", "[relay_chn][core]")
|
||||||
|
{
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
// Short delay for state to update
|
// Short delay for state to update
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test that relays run in the reverse direction and update their state
|
// TEST_CASE: Test that relays run in the reverse direction and update their state
|
||||||
TEST_CASE("Relay channels run reverse and update state", "[relay_chn][core]") {
|
TEST_CASE("Relay channels run reverse and update state", "[relay_chn][core]")
|
||||||
relay_chn_run_reverse(); // relay_chn_run_reverse returns void
|
{
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
relay_chn_run_reverse();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TEST_CASE: Test that relays stop and transition to RELAY_CHN_STATE_IDLE
|
// TEST_CASE: Test that relays stop and transition to RELAY_CHN_STATE_IDLE
|
||||||
// This test also verifies the transition to IDLE state after a STOP command.
|
// This test also verifies the transition to IDLE state after a STOP command.
|
||||||
TEST_CASE("Relay channels stop and update to IDLE state", "[relay_chn][core]") {
|
TEST_CASE("Relay channels stop and update to IDLE state", "[relay_chn][core]")
|
||||||
|
{
|
||||||
// First, run forward to test stopping and transitioning to IDLE state
|
// First, run forward to test stopping and transitioning to IDLE state
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// Now, issue the stop command
|
// Now, issue the stop command
|
||||||
relay_chn_stop(); // relay_chn_stop returns void
|
relay_chn_stop();
|
||||||
// Immediately after stop, state should be STOPPED
|
// Immediately after stop, state should be STOPPED
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||||
|
|
||||||
// Then, wait for the inertia period for it to transition to RELAY_CHN_STATE_IDLE
|
// Then, wait for the inertia period for it to transition to RELAY_CHN_STATE_IDLE
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,67 +77,71 @@ TEST_CASE("Relay channels stop and update to IDLE state", "[relay_chn][core]") {
|
|||||||
|
|
||||||
// TEST_CASE: Test transition from forward to reverse with inertia and state checks
|
// TEST_CASE: Test transition from forward to reverse with inertia and state checks
|
||||||
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_REVERSE
|
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_REVERSE
|
||||||
TEST_CASE("Forward to Reverse transition with opposite inertia", "[relay_chn][core][inertia]") {
|
TEST_CASE("Forward to Reverse transition with opposite inertia", "[relay_chn][core][inertia]")
|
||||||
|
{
|
||||||
// 1. Start in forward direction
|
// 1. Start in forward direction
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Short delay for state stabilization
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Short delay for state stabilization
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue reverse command
|
// 2. Issue reverse command
|
||||||
relay_chn_run_reverse(); // relay_chn_run_reverse returns void
|
relay_chn_run_reverse();
|
||||||
// Immediately after the command, the motor should be stopped
|
// Immediately after the command, the motor should be stopped
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state());
|
||||||
|
|
||||||
// Wait for the inertia period (after which the reverse command will be dispatched)
|
// Wait for the inertia period (after which the reverse command will be dispatched)
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state()); // Should now be in reverse state
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state()); // Should now be in reverse state
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from reverse to forward with inertia and state checks
|
// TEST_CASE: Test transition from reverse to forward with inertia and state checks
|
||||||
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_FORWARD
|
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_FORWARD
|
||||||
TEST_CASE("Reverse to Forward transition with opposite inertia", "[relay_chn][core][inertia]") {
|
TEST_CASE("Reverse to Forward transition with opposite inertia", "[relay_chn][core][inertia]")
|
||||||
|
{
|
||||||
// 1. Start in reverse direction
|
// 1. Start in reverse direction
|
||||||
relay_chn_run_reverse(); // relay_chn_run_reverse returns void
|
relay_chn_run_reverse();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue forward command
|
// 2. Issue forward command
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state());
|
||||||
|
|
||||||
// Wait for inertia
|
// Wait for inertia
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test issuing the same run command while already running (no inertia expected)
|
// TEST_CASE: Test issuing the same run command while already running (no inertia expected)
|
||||||
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||||
TEST_CASE("Running in same direction does not incur inertia", "[relay_chn][core][inertia]") {
|
TEST_CASE("Running in same direction does not incur inertia", "[relay_chn][core][inertia]")
|
||||||
|
{
|
||||||
// 1. Start in forward direction
|
// 1. Start in forward direction
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue the same forward command again
|
// 2. Issue the same forward command again
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
// As per the code, is_direction_opposite_to_current_motion should return false, so no inertia.
|
// As per the code, is_direction_opposite_to_current_motion should return false, so no inertia.
|
||||||
// Just a short delay to check state remains the same.
|
// Just a short delay to check state remains the same.
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from IDLE state to running (no inertia expected)
|
// TEST_CASE: Test transition from IDLE state to running (no inertia expected)
|
||||||
// Scenario: RELAY_CHN_STATE_IDLE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
// Scenario: RELAY_CHN_STATE_IDLE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||||
TEST_CASE("IDLE to Running transition without inertia", "[relay_chn][core][inertia]") {
|
TEST_CASE("IDLE to Running transition without inertia", "[relay_chn][core][inertia]")
|
||||||
|
{
|
||||||
// setUp() should have already brought the channel to IDLE state
|
// setUp() should have already brought the channel to IDLE state
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
|
|
||||||
// Start in forward direction
|
// Start in forward direction
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
// No inertia is expected when starting from IDLE state.
|
// No inertia is expected when starting from IDLE state.
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,14 +154,14 @@ TEST_CASE("Single channel direction can be flipped", "[relay_chn][core][directio
|
|||||||
|
|
||||||
// 2. Flip the direction
|
// 2. Flip the direction
|
||||||
relay_chn_flip_direction();
|
relay_chn_flip_direction();
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); // Wait for flip inertia
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS)); // Wait for flip inertia
|
||||||
|
|
||||||
// 3. Verify direction is flipped
|
// 3. Verify direction is flipped
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction());
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction());
|
||||||
|
|
||||||
// 4. Flip back
|
// 4. Flip back
|
||||||
relay_chn_flip_direction();
|
relay_chn_flip_direction();
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); // Wait for flip inertia
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS)); // Wait for flip inertia
|
||||||
|
|
||||||
// 5. Verify direction is back to default
|
// 5. Verify direction is back to default
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction());
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction());
|
||||||
@@ -157,23 +171,23 @@ TEST_CASE("Flipping a running channel stops it and flips direction", "[relay_chn
|
|||||||
{
|
{
|
||||||
// 1. Start channel running and verify state
|
// 1. Start channel running and verify state
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Flip the direction while running
|
// 2. Flip the direction while running
|
||||||
relay_chn_flip_direction();
|
relay_chn_flip_direction();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Give time for events to process
|
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
|
// 3. The channel should stop as part of the flip process
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||||
|
|
||||||
// 4. Wait for the flip inertia to pass, after which it should be IDLE and FLIPPED
|
// 4. Wait for the flip inertia to pass, after which it should be IDLE and FLIPPED
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction());
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
#define TEST_RUN_LIMIT_SEC 5
|
#define TEST_RUN_LIMIT_SEC 5
|
||||||
#define TEST_SHORT_RUN_LIMIT_SEC 2
|
#define TEST_SHORT_RUN_LIMIT_SEC 2
|
||||||
// ### Run Limit Tests
|
// ### Run Limit Tests
|
||||||
@@ -208,7 +222,7 @@ TEST_CASE("Test run limit stops channel after timeout", "[relay_chn][run_limit]"
|
|||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// Wait for run limit timeout
|
// Wait for run limit timeout
|
||||||
vTaskDelay(pdMS_TO_TICKS(TEST_SHORT_RUN_LIMIT_SEC * 1000 + test_delay_margin_ms));
|
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_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,12 +239,12 @@ TEST_CASE("Test run limit reset on direction change and time out finally", "[rel
|
|||||||
relay_chn_run_reverse();
|
relay_chn_run_reverse();
|
||||||
|
|
||||||
// Wait for the inertia period (after which the reverse command will be dispatched)
|
// Wait for the inertia period (after which the reverse command will be dispatched)
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||||
|
|
||||||
// Timer should time out and stop the channel after the run limit time
|
// 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));
|
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_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
@@ -248,3 +262,59 @@ TEST_CASE("Test run limit persistence across stop/start", "[relay_chn][run_limit
|
|||||||
TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit());
|
TEST_ASSERT_EQUAL(TEST_RUN_LIMIT_SEC, relay_chn_get_run_limit());
|
||||||
}
|
}
|
||||||
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
#endif // CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT == 1
|
||||||
|
|
||||||
|
TEST_CASE("relay_chn_get_state_str returns correct strings", "[relay_chn][core]")
|
||||||
|
{
|
||||||
|
// This test is a bit contrived as it's hard to force every state
|
||||||
|
// without complex sequences. We will test the most common ones.
|
||||||
|
TEST_ASSERT_EQUAL_STRING("IDLE", relay_chn_get_state_str());
|
||||||
|
|
||||||
|
relay_chn_run_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
TEST_ASSERT_EQUAL_STRING("FORWARD", relay_chn_get_state_str());
|
||||||
|
|
||||||
|
relay_chn_run_reverse();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
TEST_ASSERT_EQUAL_STRING("REVERSE_PENDING", relay_chn_get_state_str());
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS));
|
||||||
|
TEST_ASSERT_EQUAL_STRING("REVERSE", relay_chn_get_state_str());
|
||||||
|
|
||||||
|
relay_chn_stop();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
TEST_ASSERT_EQUAL_STRING("STOPPED", relay_chn_get_state_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Stop command interrupts pending commands", "[relay_chn][core][inertia]")
|
||||||
|
{
|
||||||
|
// 1. Start running forward
|
||||||
|
relay_chn_run_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
|
// 2. Issue a reverse command, which will make the state REVERSE_PENDING
|
||||||
|
relay_chn_run_reverse();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state());
|
||||||
|
|
||||||
|
// 3. Before the inertia timer fires, issue a stop command
|
||||||
|
relay_chn_stop();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||||
|
|
||||||
|
// 4. Wait for more than the inertia period
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
// The channel should transition to IDLE, not REVERSE, because stop cancelled the pending command.
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("relay_chn_destroy allows clean-up and re-creation", "[relay_chn][core]")
|
||||||
|
{
|
||||||
|
relay_chn_run_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
|
relay_chn_destroy();
|
||||||
|
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
#include "test_common.h"
|
|
||||||
|
|
||||||
|
|
||||||
// --- Listener Test Globals ---
|
|
||||||
typedef struct {
|
|
||||||
uint8_t chn_id;
|
|
||||||
relay_chn_state_t old_state;
|
|
||||||
relay_chn_state_t new_state;
|
|
||||||
int call_count;
|
|
||||||
} listener_callback_info_t;
|
|
||||||
|
|
||||||
static listener_callback_info_t listener1_info;
|
|
||||||
static listener_callback_info_t listener2_info;
|
|
||||||
|
|
||||||
// --- Listener Test Helper Functions ---
|
|
||||||
|
|
||||||
// Clear the memory from possible garbage values
|
|
||||||
static void reset_listener_info(listener_callback_info_t* info) {
|
|
||||||
memset(info, 0, sizeof(listener_callback_info_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_listener_1(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
|
||||||
listener1_info.chn_id = chn_id;
|
|
||||||
listener1_info.old_state = old_state;
|
|
||||||
listener1_info.new_state = new_state;
|
|
||||||
listener1_info.call_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_listener_2(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
|
||||||
listener2_info.chn_id = chn_id;
|
|
||||||
listener2_info.old_state = old_state;
|
|
||||||
listener2_info.new_state = new_state;
|
|
||||||
listener2_info.call_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### Listener Functionality Tests
|
|
||||||
|
|
||||||
TEST_CASE("Listener is called on state change", "[relay_chn][listener]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
reset_listener_info(&listener1_info);
|
|
||||||
|
|
||||||
// 1. Register the listener
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
|
||||||
|
|
||||||
// 2. Trigger a state change
|
|
||||||
relay_chn_run_forward(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Allow event to be processed
|
|
||||||
|
|
||||||
// 3. Verify the listener was called with correct parameters
|
|
||||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
|
||||||
TEST_ASSERT_EQUAL(ch, listener1_info.chn_id);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
|
||||||
|
|
||||||
// 4. Unregister to clean up
|
|
||||||
relay_chn_unregister_listener(test_listener_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Unregistered listener is not called", "[relay_chn][listener]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
reset_listener_info(&listener1_info);
|
|
||||||
|
|
||||||
// 1. Register and then immediately unregister the listener
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
|
||||||
relay_chn_unregister_listener(test_listener_1);
|
|
||||||
|
|
||||||
// 2. Trigger a state change
|
|
||||||
relay_chn_run_forward(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
|
|
||||||
// 3. Verify the listener was NOT called
|
|
||||||
TEST_ASSERT_EQUAL(0, listener1_info.call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Multiple listeners are called on state change", "[relay_chn][listener]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
reset_listener_info(&listener1_info);
|
|
||||||
reset_listener_info(&listener2_info);
|
|
||||||
|
|
||||||
// 1. Register two different listeners
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_2));
|
|
||||||
|
|
||||||
// 2. Trigger a state change
|
|
||||||
relay_chn_run_forward(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
|
|
||||||
// 3. Verify listener 1 was called correctly
|
|
||||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
|
||||||
|
|
||||||
// 4. Verify listener 2 was also called correctly
|
|
||||||
TEST_ASSERT_EQUAL(1, listener2_info.call_count);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener2_info.old_state);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener2_info.new_state);
|
|
||||||
|
|
||||||
// 5. Clean up
|
|
||||||
relay_chn_unregister_listener(test_listener_1);
|
|
||||||
relay_chn_unregister_listener(test_listener_2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Listener registration handles invalid arguments and duplicates", "[relay_chn][listener]") {
|
|
||||||
reset_listener_info(&listener1_info);
|
|
||||||
|
|
||||||
// 1. Registering a NULL listener should fail
|
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_register_listener(NULL));
|
|
||||||
|
|
||||||
// 2. Unregistering a NULL listener should not crash
|
|
||||||
relay_chn_unregister_listener(NULL);
|
|
||||||
|
|
||||||
// 3. Registering the same listener twice should be handled gracefully
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1)); // Second call should be a no-op
|
|
||||||
|
|
||||||
// 4. Trigger a state change and verify the listener is only called ONCE
|
|
||||||
relay_chn_run_forward(0);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
|
||||||
|
|
||||||
// 5. Clean up
|
|
||||||
relay_chn_unregister_listener(test_listener_1);
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
#include "test_common.h"
|
|
||||||
|
|
||||||
|
|
||||||
// --- Listener Test Globals ---
|
|
||||||
typedef struct {
|
|
||||||
relay_chn_state_t old_state;
|
|
||||||
relay_chn_state_t new_state;
|
|
||||||
int call_count;
|
|
||||||
} listener_callback_info_t;
|
|
||||||
|
|
||||||
static listener_callback_info_t listener1_info;
|
|
||||||
static listener_callback_info_t listener2_info;
|
|
||||||
|
|
||||||
// --- Listener Test Helper Functions ---
|
|
||||||
|
|
||||||
// Clear the memory from possible garbage values
|
|
||||||
static void reset_listener_info(listener_callback_info_t* info) {
|
|
||||||
memset(info, 0, sizeof(listener_callback_info_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_listener_1(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
|
||||||
/* Just ignore the channel id */
|
|
||||||
listener1_info.old_state = old_state;
|
|
||||||
listener1_info.new_state = new_state;
|
|
||||||
listener1_info.call_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_listener_2(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
|
||||||
/* Just ignore the channel id */
|
|
||||||
listener2_info.old_state = old_state;
|
|
||||||
listener2_info.new_state = new_state;
|
|
||||||
listener2_info.call_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### Listener Functionality Tests
|
|
||||||
|
|
||||||
TEST_CASE("Listener is called on state change", "[relay_chn][listener]") {
|
|
||||||
reset_listener_info(&listener1_info);
|
|
||||||
|
|
||||||
// 1. Register the listener
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
|
||||||
|
|
||||||
// 2. Trigger a state change
|
|
||||||
relay_chn_run_forward();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Allow event to be processed
|
|
||||||
|
|
||||||
// 3. Verify the listener was called with correct parameters
|
|
||||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
|
||||||
|
|
||||||
// 4. Unregister to clean up
|
|
||||||
relay_chn_unregister_listener(test_listener_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Unregistered listener is not called", "[relay_chn][listener]") {
|
|
||||||
reset_listener_info(&listener1_info);
|
|
||||||
|
|
||||||
// 1. Register and then immediately unregister the listener
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
|
||||||
relay_chn_unregister_listener(test_listener_1);
|
|
||||||
|
|
||||||
// 2. Trigger a state change
|
|
||||||
relay_chn_run_forward();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
|
|
||||||
// 3. Verify the listener was NOT called
|
|
||||||
TEST_ASSERT_EQUAL(0, listener1_info.call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Multiple listeners are called on state change", "[relay_chn][listener]") {
|
|
||||||
reset_listener_info(&listener1_info);
|
|
||||||
reset_listener_info(&listener2_info);
|
|
||||||
|
|
||||||
// 1. Register two different listeners
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_2));
|
|
||||||
|
|
||||||
// 2. Trigger a state change
|
|
||||||
relay_chn_run_forward();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
|
|
||||||
// 3. Verify listener 1 was called correctly
|
|
||||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
|
||||||
|
|
||||||
// 4. Verify listener 2 was also called correctly
|
|
||||||
TEST_ASSERT_EQUAL(1, listener2_info.call_count);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener2_info.old_state);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener2_info.new_state);
|
|
||||||
|
|
||||||
// 5. Clean up
|
|
||||||
relay_chn_unregister_listener(test_listener_1);
|
|
||||||
relay_chn_unregister_listener(test_listener_2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Listener registration handles invalid arguments and duplicates", "[relay_chn][listener]") {
|
|
||||||
reset_listener_info(&listener1_info);
|
|
||||||
|
|
||||||
// 1. Registering a NULL listener should fail
|
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_register_listener(NULL));
|
|
||||||
|
|
||||||
// 2. Unregistering a NULL listener should not crash
|
|
||||||
relay_chn_unregister_listener(NULL);
|
|
||||||
|
|
||||||
// 3. Registering the same listener twice should be handled gracefully
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
|
||||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1)); // Second call should be a no-op
|
|
||||||
|
|
||||||
// 4. Trigger a state change and verify the listener is only called ONCE
|
|
||||||
relay_chn_run_forward();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
|
||||||
|
|
||||||
// 5. Clean up
|
|
||||||
relay_chn_unregister_listener(test_listener_1);
|
|
||||||
}
|
|
||||||
55
test_apps/main/test_relay_chn_notify_common.c
Normal file
55
test_apps/main/test_relay_chn_notify_common.c
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test_relay_chn_notify_common.h"
|
||||||
|
|
||||||
|
listener_callback_info_t listener1_info;
|
||||||
|
listener_callback_info_t listener2_info;
|
||||||
|
|
||||||
|
// --- Globals for Advanced Tests ---
|
||||||
|
SemaphoreHandle_t blocking_listener_sem = NULL;
|
||||||
|
SemaphoreHandle_t log_check_sem = NULL;
|
||||||
|
volatile int blocking_listener_call_count = 0;
|
||||||
|
vprintf_like_t original_vprintf = NULL;
|
||||||
|
|
||||||
|
// --- Listener Test Helper Functions ---
|
||||||
|
|
||||||
|
// Clear the memory from possible garbage values
|
||||||
|
void reset_listener_info(listener_callback_info_t* info) {
|
||||||
|
memset(info, 0, sizeof(listener_callback_info_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_listener_1(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
||||||
|
listener1_info.chn_id = chn_id;
|
||||||
|
listener1_info.old_state = old_state;
|
||||||
|
listener1_info.new_state = new_state;
|
||||||
|
listener1_info.call_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_listener_2(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
||||||
|
listener2_info.chn_id = chn_id;
|
||||||
|
listener2_info.old_state = old_state;
|
||||||
|
listener2_info.new_state = new_state;
|
||||||
|
listener2_info.call_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blocking_listener(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
||||||
|
blocking_listener_call_count++;
|
||||||
|
// Block until the main test task unblocks us
|
||||||
|
xSemaphoreTake(blocking_listener_sem, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_check_vprintf(const char *format, va_list args) {
|
||||||
|
// Buffer to hold the formatted log message
|
||||||
|
char buffer[256];
|
||||||
|
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||||
|
|
||||||
|
if (strstr(buffer, "Notify queue is full")) {
|
||||||
|
xSemaphoreGive(log_check_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return original_vprintf(format, args);
|
||||||
|
}
|
||||||
54
test_apps/main/test_relay_chn_notify_common.h
Normal file
54
test_apps/main/test_relay_chn_notify_common.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "test_common.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This is defined in the source file, we redefine it here for the test.
|
||||||
|
// The test build must have the same CONFIG_RELAY_CHN_COUNT.
|
||||||
|
#define TEST_RELAY_CHN_NOTIFY_QUEUE_LEN (16 + CONFIG_RELAY_CHN_COUNT * 4)
|
||||||
|
|
||||||
|
// --- Listener Test Globals ---
|
||||||
|
typedef struct {
|
||||||
|
uint8_t chn_id;
|
||||||
|
relay_chn_state_t old_state;
|
||||||
|
relay_chn_state_t new_state;
|
||||||
|
int call_count;
|
||||||
|
} listener_callback_info_t;
|
||||||
|
|
||||||
|
// --- Listener callback infos to be defined ---
|
||||||
|
extern listener_callback_info_t listener1_info;
|
||||||
|
extern listener_callback_info_t listener2_info;
|
||||||
|
|
||||||
|
// --- Globals for Advanced Tests ---
|
||||||
|
extern SemaphoreHandle_t blocking_listener_sem;
|
||||||
|
extern SemaphoreHandle_t log_check_sem;
|
||||||
|
extern volatile int blocking_listener_call_count;
|
||||||
|
extern vprintf_like_t original_vprintf;
|
||||||
|
|
||||||
|
|
||||||
|
// --- Listener Test Helper Functions ---
|
||||||
|
|
||||||
|
// Clear the memory from possible garbage values
|
||||||
|
void reset_listener_info(listener_callback_info_t* info);
|
||||||
|
|
||||||
|
// State listeners for notify module testing
|
||||||
|
void test_listener_1(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||||
|
void test_listener_2(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||||
|
void blocking_listener(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||||
|
|
||||||
|
int log_check_vprintf(const char *format, va_list args);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
172
test_apps/main/test_relay_chn_notify_multi.c
Normal file
172
test_apps/main/test_relay_chn_notify_multi.c
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test_relay_chn_notify_common.h"
|
||||||
|
|
||||||
|
// This is a private header, but we need it for direct notification calls and queue length.
|
||||||
|
// It's included conditionally in the build via CMakeLists.txt when NVS is enabled.
|
||||||
|
#include "relay_chn_notify.h"
|
||||||
|
|
||||||
|
// ### Listener Functionality Tests
|
||||||
|
|
||||||
|
TEST_CASE("Listener is called on state change for each channel", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
// 1. Register the listener and reset info
|
||||||
|
reset_listener_info(&listener1_info);
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow registration to be processed
|
||||||
|
|
||||||
|
// Loop through each channel
|
||||||
|
for (uint8_t ch = 0; ch < CONFIG_RELAY_CHN_COUNT; ch++) {
|
||||||
|
// 2. Trigger a state change on the current channel.
|
||||||
|
// tearDown() ensures each channel starts as IDLE.
|
||||||
|
relay_chn_run_forward(ch);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow event to be processed
|
||||||
|
|
||||||
|
// 3. Verify the listener was called with correct parameters for this channel.
|
||||||
|
// The listener_info struct is overwritten each time, but we check it before the next iteration.
|
||||||
|
TEST_ASSERT_EQUAL(ch, listener1_info.chn_id);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Verify the total call count after the loop
|
||||||
|
TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_COUNT, listener1_info.call_count);
|
||||||
|
|
||||||
|
// 5. Unregister to clean up
|
||||||
|
relay_chn_unregister_listener(test_listener_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Unregistered listener is not called for any channel", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
reset_listener_info(&listener1_info);
|
||||||
|
|
||||||
|
// 1. Register and then immediately unregister the listener
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||||
|
relay_chn_unregister_listener(test_listener_1);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow commands to process
|
||||||
|
|
||||||
|
// 2. Trigger a state change on all channels
|
||||||
|
relay_chn_run_forward_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS * CONFIG_RELAY_CHN_COUNT)); // Allow all events to be processed
|
||||||
|
|
||||||
|
// 3. Verify the listener was NOT called
|
||||||
|
TEST_ASSERT_EQUAL(0, listener1_info.call_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Multiple listeners are called on state change for each channel", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
// 1. Register listeners and reset info
|
||||||
|
reset_listener_info(&listener1_info);
|
||||||
|
reset_listener_info(&listener2_info);
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_2));
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow registration commands to be processed
|
||||||
|
|
||||||
|
// Loop through each channel
|
||||||
|
for (uint8_t ch = 0; ch < CONFIG_RELAY_CHN_COUNT; ch++) {
|
||||||
|
// 2. Trigger a state change on the current channel
|
||||||
|
relay_chn_run_forward(ch);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// 3. Verify listener 1 was called correctly for this channel
|
||||||
|
TEST_ASSERT_EQUAL(ch, listener1_info.chn_id);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
||||||
|
|
||||||
|
// 4. Verify listener 2 was also called correctly for this channel
|
||||||
|
TEST_ASSERT_EQUAL(ch, listener2_info.chn_id);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener2_info.old_state);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener2_info.new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Verify total call counts
|
||||||
|
TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_COUNT, listener1_info.call_count);
|
||||||
|
TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_COUNT, listener2_info.call_count);
|
||||||
|
|
||||||
|
// 6. Clean up
|
||||||
|
relay_chn_unregister_listener(test_listener_1);
|
||||||
|
relay_chn_unregister_listener(test_listener_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Listener registration handles invalid arguments and duplicates", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
reset_listener_info(&listener1_info);
|
||||||
|
|
||||||
|
// 1. Registering a NULL listener should fail
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_register_listener(NULL));
|
||||||
|
|
||||||
|
// 2. Unregistering a NULL listener should not crash
|
||||||
|
relay_chn_unregister_listener(NULL);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow commands to process
|
||||||
|
|
||||||
|
// 3. Registering the same listener twice should be handled gracefully
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1)); // Second call should be a no-op
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow registration commands to be processed
|
||||||
|
|
||||||
|
// 4. Trigger a state change on all channels and verify the listener is only called ONCE per channel
|
||||||
|
relay_chn_run_forward_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS * CONFIG_RELAY_CHN_COUNT)); // Allow all events to be processed
|
||||||
|
TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_COUNT, listener1_info.call_count);
|
||||||
|
|
||||||
|
// 5. Clean up
|
||||||
|
relay_chn_unregister_listener(test_listener_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Notify queue full scenario is handled gracefully", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
// 1. Setup
|
||||||
|
blocking_listener_sem = xSemaphoreCreateBinary();
|
||||||
|
log_check_sem = xSemaphoreCreateBinary();
|
||||||
|
blocking_listener_call_count = 0;
|
||||||
|
|
||||||
|
// Intercept logs to check for the "queue full" warning
|
||||||
|
original_vprintf = esp_log_set_vprintf(log_check_vprintf);
|
||||||
|
|
||||||
|
// 2. Register a listener that will block, allowing the queue to fill up
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(blocking_listener));
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow task to start
|
||||||
|
|
||||||
|
// 3. Fill the queue. The first event will be consumed immediately by the dispatcher,
|
||||||
|
// which will then call the blocking_listener and block. The remaining (LEN - 1)
|
||||||
|
// events will sit in the queue, leaving one empty slot.
|
||||||
|
// Use different channel IDs to make the test more robust.
|
||||||
|
for (int i = 0; i < TEST_RELAY_CHN_NOTIFY_QUEUE_LEN; i++) {
|
||||||
|
uint8_t ch = i % CONFIG_RELAY_CHN_COUNT;
|
||||||
|
TEST_ESP_OK(relay_chn_notify_state_change(ch, RELAY_CHN_STATE_IDLE, RELAY_CHN_STATE_FORWARD));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Send one more event to fill the last slot in the queue. This should succeed.
|
||||||
|
TEST_ESP_OK(relay_chn_notify_state_change(0, RELAY_CHN_STATE_IDLE, RELAY_CHN_STATE_FORWARD)); // Use any valid channel
|
||||||
|
|
||||||
|
// 5. Now the queue is full. Trigger one more event to cause an overflow.
|
||||||
|
// This call should fail and log the warning.
|
||||||
|
TEST_ASSERT_EQUAL(ESP_FAIL, relay_chn_notify_state_change(1 % CONFIG_RELAY_CHN_COUNT, RELAY_CHN_STATE_IDLE, RELAY_CHN_STATE_FORWARD));
|
||||||
|
|
||||||
|
// 6. Wait for the "queue full" log message to be captured by our vprintf hook
|
||||||
|
TEST_ASSERT_TRUE_MESSAGE(xSemaphoreTake(log_check_sem, pdMS_TO_TICKS(1000)) == pdTRUE, "Did not receive 'queue full' log message");
|
||||||
|
|
||||||
|
// 7. Unblock the listener so it can process all queued items.
|
||||||
|
// There was 1 initial event + QUEUE_LEN events that were successfully queued.
|
||||||
|
for (int i = 0; i < TEST_RELAY_CHN_NOTIFY_QUEUE_LEN + 1; i++) {
|
||||||
|
xSemaphoreGive(blocking_listener_sem);
|
||||||
|
// Give the dispatcher task a moment to process one item from the queue
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. Verify the listener was called exactly QUEUE_LEN + 1 times
|
||||||
|
TEST_ASSERT_EQUAL_INT(TEST_RELAY_CHN_NOTIFY_QUEUE_LEN + 1, blocking_listener_call_count);
|
||||||
|
|
||||||
|
// 9. Cleanup
|
||||||
|
esp_log_set_vprintf(original_vprintf);
|
||||||
|
relay_chn_unregister_listener(blocking_listener);
|
||||||
|
vSemaphoreDelete(blocking_listener_sem);
|
||||||
|
vSemaphoreDelete(log_check_sem);
|
||||||
|
blocking_listener_sem = NULL;
|
||||||
|
log_check_sem = NULL;
|
||||||
|
original_vprintf = NULL;
|
||||||
|
}
|
||||||
152
test_apps/main/test_relay_chn_notify_single.c
Normal file
152
test_apps/main/test_relay_chn_notify_single.c
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test_relay_chn_notify_common.h"
|
||||||
|
|
||||||
|
// This is a private header, but we need it for direct notification calls and queue length.
|
||||||
|
// It's included conditionally in the build via CMakeLists.txt when NVS is enabled.
|
||||||
|
#include "relay_chn_notify.h"
|
||||||
|
|
||||||
|
// ### Listener Functionality Tests
|
||||||
|
|
||||||
|
TEST_CASE("Listener is called on state change", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
reset_listener_info(&listener1_info);
|
||||||
|
|
||||||
|
// 1. Register the listener
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||||
|
|
||||||
|
// 2. Trigger a state change
|
||||||
|
relay_chn_run_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow event to be processed
|
||||||
|
|
||||||
|
// 3. Verify the listener was called with correct parameters
|
||||||
|
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
||||||
|
|
||||||
|
// 4. Unregister to clean up
|
||||||
|
relay_chn_unregister_listener(test_listener_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Unregistered listener is not called", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
reset_listener_info(&listener1_info);
|
||||||
|
|
||||||
|
// 1. Register and then immediately unregister the listener
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||||
|
relay_chn_unregister_listener(test_listener_1);
|
||||||
|
|
||||||
|
// 2. Trigger a state change
|
||||||
|
relay_chn_run_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// 3. Verify the listener was NOT called
|
||||||
|
TEST_ASSERT_EQUAL(0, listener1_info.call_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Multiple listeners are called on state change", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
reset_listener_info(&listener1_info);
|
||||||
|
reset_listener_info(&listener2_info);
|
||||||
|
|
||||||
|
// 1. Register two different listeners
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_2));
|
||||||
|
|
||||||
|
// 2. Trigger a state change
|
||||||
|
relay_chn_run_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// 3. Verify listener 1 was called correctly
|
||||||
|
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
||||||
|
|
||||||
|
// 4. Verify listener 2 was also called correctly
|
||||||
|
TEST_ASSERT_EQUAL(1, listener2_info.call_count);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener2_info.old_state);
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener2_info.new_state);
|
||||||
|
|
||||||
|
// 5. Clean up
|
||||||
|
relay_chn_unregister_listener(test_listener_1);
|
||||||
|
relay_chn_unregister_listener(test_listener_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Listener registration handles invalid arguments and duplicates", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
reset_listener_info(&listener1_info);
|
||||||
|
|
||||||
|
// 1. Registering a NULL listener should fail
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_register_listener(NULL));
|
||||||
|
|
||||||
|
// 2. Unregistering a NULL listener should not crash
|
||||||
|
relay_chn_unregister_listener(NULL);
|
||||||
|
|
||||||
|
// 3. Registering the same listener twice should be handled gracefully
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(test_listener_1)); // Second call should be a no-op
|
||||||
|
|
||||||
|
// 4. Trigger a state change and verify the listener is only called ONCE
|
||||||
|
relay_chn_run_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
||||||
|
|
||||||
|
// 5. Clean up
|
||||||
|
relay_chn_unregister_listener(test_listener_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Notify queue full scenario is handled gracefully", "[relay_chn][notify]")
|
||||||
|
{
|
||||||
|
// 1. Setup
|
||||||
|
blocking_listener_sem = xSemaphoreCreateBinary();
|
||||||
|
log_check_sem = xSemaphoreCreateBinary();
|
||||||
|
blocking_listener_call_count = 0;
|
||||||
|
|
||||||
|
// Intercept logs to check for the "queue full" warning
|
||||||
|
original_vprintf = esp_log_set_vprintf(log_check_vprintf);
|
||||||
|
|
||||||
|
// 2. Register a listener that will block, allowing the queue to fill up
|
||||||
|
TEST_ESP_OK(relay_chn_register_listener(blocking_listener));
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow task to start
|
||||||
|
|
||||||
|
// 3. Fill the queue. The first event will be consumed immediately by the dispatcher,
|
||||||
|
// which will then call the blocking_listener and block. The remaining (LEN - 1)
|
||||||
|
// events will sit in the queue, leaving one empty slot.
|
||||||
|
for (int i = 0; i < TEST_RELAY_CHN_NOTIFY_QUEUE_LEN; i++) {
|
||||||
|
TEST_ESP_OK(relay_chn_notify_state_change(0, RELAY_CHN_STATE_IDLE, RELAY_CHN_STATE_FORWARD));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Send one more event to fill the last slot in the queue. This should succeed.
|
||||||
|
TEST_ESP_OK(relay_chn_notify_state_change(0, RELAY_CHN_STATE_IDLE, RELAY_CHN_STATE_FORWARD));
|
||||||
|
|
||||||
|
// 5. Now the queue is full. Trigger one more event to cause an overflow.
|
||||||
|
// This call should fail and log the warning.
|
||||||
|
TEST_ASSERT_EQUAL(ESP_FAIL, relay_chn_notify_state_change(0, RELAY_CHN_STATE_IDLE, RELAY_CHN_STATE_FORWARD));
|
||||||
|
|
||||||
|
// 6. Wait for the "queue full" log message to be captured by our vprintf hook
|
||||||
|
TEST_ASSERT_TRUE_MESSAGE(xSemaphoreTake(log_check_sem, pdMS_TO_TICKS(1000)) == pdTRUE, "Did not receive 'queue full' log message");
|
||||||
|
|
||||||
|
// 7. Unblock the listener so it can process all queued items.
|
||||||
|
// There was 1 initial event + QUEUE_LEN events that were successfully queued.
|
||||||
|
for (int i = 0; i < TEST_RELAY_CHN_NOTIFY_QUEUE_LEN + 1; i++) {
|
||||||
|
xSemaphoreGive(blocking_listener_sem);
|
||||||
|
// Give the dispatcher task a moment to process one item from the queue
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. Verify the listener was called exactly QUEUE_LEN + 1 times
|
||||||
|
TEST_ASSERT_EQUAL_INT(TEST_RELAY_CHN_NOTIFY_QUEUE_LEN + 1, blocking_listener_call_count);
|
||||||
|
|
||||||
|
// 9. Cleanup
|
||||||
|
esp_log_set_vprintf(original_vprintf);
|
||||||
|
relay_chn_unregister_listener(blocking_listener);
|
||||||
|
vSemaphoreDelete(blocking_listener_sem);
|
||||||
|
vSemaphoreDelete(log_check_sem);
|
||||||
|
blocking_listener_sem = NULL;
|
||||||
|
log_check_sem = NULL;
|
||||||
|
original_vprintf = NULL;
|
||||||
|
}
|
||||||
@@ -9,144 +9,181 @@
|
|||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
|
#include "test_common.h"
|
||||||
|
|
||||||
TEST_CASE("Test relay storage init/deinit", "[relay_chn][nvs]")
|
#define TEST_NVS_TASK_TIME_OUT_MS 300
|
||||||
{
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Test direction setting and getting", "[relay_chn][nvs]")
|
TEST_CASE("Test direction setting and getting", "[relay_chn][nvs]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
// Test all channels
|
// Test all channels
|
||||||
relay_chn_direction_t dir;
|
relay_chn_direction_t dir, expect;
|
||||||
relay_chn_direction_t test_directions[] = {
|
|
||||||
RELAY_CHN_DIRECTION_DEFAULT,
|
|
||||||
RELAY_CHN_DIRECTION_FLIPPED
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int channel = 0; channel < 2; channel++) {
|
for (int channel = 0; channel < CONFIG_RELAY_CHN_COUNT; channel++) {
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_direction(channel, test_directions[channel]));
|
dir = channel % 2 == 0 ? RELAY_CHN_DIRECTION_DEFAULT : RELAY_CHN_DIRECTION_FLIPPED;
|
||||||
TEST_ESP_OK(relay_chn_nvs_get_direction(channel, &dir));
|
TEST_ESP_OK(relay_chn_nvs_set_direction(channel, dir));
|
||||||
TEST_ASSERT_EQUAL(test_directions[channel], dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
// Wait for the batch commit timeout to ensure the value is written
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS));
|
||||||
|
|
||||||
|
for (int channel = 0; channel < CONFIG_RELAY_CHN_COUNT; channel++) {
|
||||||
|
expect = channel % 2 == 0 ? RELAY_CHN_DIRECTION_DEFAULT : RELAY_CHN_DIRECTION_FLIPPED;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_direction(channel, &dir, RELAY_CHN_DIRECTION_DEFAULT));
|
||||||
|
TEST_ASSERT_EQUAL(expect, dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test invalid parameters", "[relay_chn][nvs]")
|
TEST_CASE("Test invalid parameters", "[relay_chn][nvs]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
// Test NULL pointer for all channels
|
// Test NULL pointer for all channels
|
||||||
for (int channel = 0; channel < RELAY_CHN_COUNT; channel++) {
|
for (int channel = 0; channel < CONFIG_RELAY_CHN_COUNT; channel++) {
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_direction(channel, NULL));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_direction(channel, NULL, RELAY_CHN_DIRECTION_DEFAULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test relay_chn_nvs_erase_all", "[relay_chn][nvs]")
|
TEST_CASE("Test relay_chn_nvs_erase_all", "[relay_chn][nvs]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
// Store some test data first
|
// Store some test data first
|
||||||
relay_chn_direction_t direction = RELAY_CHN_DIRECTION_FLIPPED;
|
for (int channel = 0; channel < CONFIG_RELAY_CHN_COUNT; channel++) {
|
||||||
for (int channel = 0; channel < RELAY_CHN_COUNT; channel++) {
|
// Set direction for all channels
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_direction(0, direction));
|
TEST_ESP_OK(relay_chn_nvs_set_direction(channel, RELAY_CHN_DIRECTION_FLIPPED));
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef RELAY_CHN_ENABLE_TILTING
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
uint8_t sensitivity = 50;
|
TEST_ESP_OK(relay_chn_nvs_set_run_limit(channel, 100 + channel));
|
||||||
for (int channel = 0; channel < RELAY_CHN_COUNT; channel++) {
|
#endif
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_tilt_sensitivity(0, sensitivity));
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_tilt_count(0, 100));
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_set_tilt_sensitivity(channel, 50));
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_set_tilt_count(channel, 100 + channel));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Wait for the set operations and subsequent commits to complete
|
||||||
|
// Wait 4 times more since 4 x 8 = 32 operations to process
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS * 8));
|
||||||
|
|
||||||
// Test erase all
|
// Test erase all
|
||||||
TEST_ESP_OK(relay_chn_nvs_erase_all());
|
TEST_ESP_OK(relay_chn_nvs_erase_all());
|
||||||
|
|
||||||
|
// Wait for the erase operation and subsequent commit to complete
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS));
|
||||||
// Verify data was erased by trying to read it back
|
// Verify data was erased by trying to read it back
|
||||||
|
for (int channel = 0; channel < CONFIG_RELAY_CHN_COUNT; channel++) {
|
||||||
relay_chn_direction_t read_direction;
|
relay_chn_direction_t read_direction;
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, relay_chn_nvs_get_direction(0, &read_direction));
|
TEST_ESP_OK(relay_chn_nvs_get_direction(0, &read_direction, RELAY_CHN_DIRECTION_DEFAULT));
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, read_direction);
|
||||||
#ifdef RELAY_CHN_ENABLE_TILTING
|
|
||||||
uint8_t read_sensitivity;
|
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, relay_chn_nvs_get_tilt_sensitivity(0, &read_sensitivity));
|
|
||||||
|
|
||||||
uint16_t tilt_count;
|
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, relay_chn_nvs_get_tilt_count(0, &tilt_count));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
|
for (int channel = 0; channel < CONFIG_RELAY_CHN_COUNT; channel++) {
|
||||||
|
uint16_t read_run_limit;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_run_limit(channel, &read_run_limit, CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC));
|
||||||
|
TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC, read_run_limit);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
const uint8_t default_sensitivity_for_test = 42;
|
||||||
|
for (int channel = 0; channel < CONFIG_RELAY_CHN_COUNT; channel++) {
|
||||||
|
uint8_t read_sensitivity;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_tilt_sensitivity(channel, &read_sensitivity, default_sensitivity_for_test));
|
||||||
|
TEST_ASSERT_EQUAL(default_sensitivity_for_test, read_sensitivity);
|
||||||
|
uint16_t tilt_count;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_tilt_count(channel, &tilt_count, 0));
|
||||||
|
TEST_ASSERT_EQUAL(0, tilt_count);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
TEST_CASE("Test run limit setting and getting", "[relay_chn][nvs][run_limit]")
|
TEST_CASE("Test run limit setting and getting", "[relay_chn][nvs][run_limit]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
// Use different values for each channel to detect overwrites
|
||||||
|
uint16_t test_limits[CONFIG_RELAY_CHN_COUNT];
|
||||||
const uint16_t run_limit_sec = 32;
|
|
||||||
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_run_limit(i, run_limit_sec));
|
test_limits[i] = 30 + i; // e.g., 30, 31, 32...
|
||||||
|
|
||||||
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());
|
|
||||||
|
// 1. Set all values first
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_set_run_limit(i, test_limits[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the NVS task to process the batch and commit
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS));
|
||||||
|
|
||||||
|
// 2. Then, read them all back and verify
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
uint16_t run_limit_read;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_run_limit(i, &run_limit_read, CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC));
|
||||||
|
TEST_ASSERT_EQUAL_UINT16(test_limits[i], run_limit_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Verify that changing one channel doesn't affect another
|
||||||
|
uint16_t new_limit_ch0 = 99;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_set_run_limit(0, new_limit_ch0));
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS)); // Allow NVS task to write
|
||||||
|
uint16_t read_val_ch0, read_val_ch1;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_run_limit(0, &read_val_ch0, CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC));
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_run_limit(1, &read_val_ch1, CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC));
|
||||||
|
TEST_ASSERT_EQUAL_UINT16(new_limit_ch0, read_val_ch0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT16(test_limits[1], read_val_ch1); // Should still be the old value
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RELAY_CHN_ENABLE_TILTING
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
TEST_CASE("Test sensitivity setting and getting", "[relay_chn][nvs][tilt]")
|
TEST_CASE("Test sensitivity setting and getting", "[relay_chn][nvs][tilt]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
uint8_t test_sensitivities[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
const uint8_t test_sensitivity = 75;
|
test_sensitivities[i] = 70 + i; // e.g., 70, 71, 72...
|
||||||
uint8_t sensitivity;
|
|
||||||
|
|
||||||
// Test all channels
|
|
||||||
for (int channel = 0; channel < RELAY_CHN_COUNT; channel++) {
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_tilt_sensitivity(channel, test_sensitivity));
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_get_tilt_sensitivity(channel, &sensitivity));
|
|
||||||
TEST_ASSERT_EQUAL(test_sensitivity, sensitivity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
// 1. Set all values first
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_set_tilt_sensitivity(i, test_sensitivities[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the NVS task to process the batch and commit
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS));
|
||||||
|
|
||||||
|
// 2. Then, read them all back and verify
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
uint8_t sensitivity_read;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_tilt_sensitivity(i, &sensitivity_read, 0));
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(test_sensitivities[i], sensitivity_read);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test tilt counter operations", "[relay_chn][nvs][tilt]")
|
TEST_CASE("Test tilt counter operations", "[relay_chn][nvs][tilt]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
uint16_t test_counts[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
const uint16_t tilt_count = 100;
|
test_counts[i] = 100 + i; // e.g., 100, 101, 102...
|
||||||
uint16_t tilt_count_read;
|
|
||||||
|
|
||||||
// Test all channels
|
|
||||||
for (int channel = 0; channel < RELAY_CHN_COUNT; channel++) {
|
|
||||||
// Test setting counters
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_tilt_count(channel, tilt_count));
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_get_tilt_count(channel, &tilt_count_read));
|
|
||||||
TEST_ASSERT_EQUAL(tilt_count, tilt_count_read);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
// 1. Set all values first
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_set_tilt_count(i, test_counts[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the NVS task to process the batch and commit
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS));
|
||||||
|
|
||||||
|
// 2. Then, read them all back and verify
|
||||||
|
for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
uint16_t count_read;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_tilt_count(i, &count_read, 0));
|
||||||
|
TEST_ASSERT_EQUAL_UINT16(test_counts[i], count_read);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test tilting invalid parameters", "[relay_chn][nvs][tilt]")
|
TEST_CASE("Test tilting invalid parameters", "[relay_chn][nvs][tilt]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
// Test NULL pointers for all channels
|
// Test NULL pointers for all channels
|
||||||
for (int channel = 0; channel < RELAY_CHN_COUNT; channel++) {
|
for (int channel = 0; channel < CONFIG_RELAY_CHN_COUNT; channel++) {
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_tilt_sensitivity(channel, NULL));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_tilt_sensitivity(channel, NULL, 0));
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_tilt_count(channel, NULL));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_tilt_count(channel, NULL, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_ENABLE_TILTING
|
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
@@ -9,51 +9,44 @@
|
|||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "relay_chn_nvs.h"
|
#include "relay_chn_nvs.h"
|
||||||
|
#include "test_common.h"
|
||||||
|
|
||||||
|
#define TEST_NVS_TASK_TIME_OUT_MS 300
|
||||||
TEST_CASE("Test relay storage init/deinit", "[relay_chn][nvs]")
|
|
||||||
{
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Test direction setting and getting", "[relay_chn][nvs]")
|
TEST_CASE("Test direction setting and getting", "[relay_chn][nvs]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
// Test channel 0
|
// Test channel 0
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_direction(0, RELAY_CHN_DIRECTION_DEFAULT));
|
TEST_ESP_OK(relay_chn_nvs_set_direction(0, RELAY_CHN_DIRECTION_DEFAULT));
|
||||||
relay_chn_direction_t dir;
|
relay_chn_direction_t dir;
|
||||||
TEST_ESP_OK(relay_chn_nvs_get_direction(0, &dir));
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS)); // Allow NVS task to write and commit
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_direction(0, &dir, RELAY_CHN_DIRECTION_DEFAULT));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, dir);
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, dir);
|
||||||
|
|
||||||
// Test channel 1
|
// Test channel 1
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_direction(0, RELAY_CHN_DIRECTION_FLIPPED));
|
TEST_ESP_OK(relay_chn_nvs_set_direction(0, RELAY_CHN_DIRECTION_FLIPPED));
|
||||||
TEST_ESP_OK(relay_chn_nvs_get_direction(0, &dir));
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS)); // Allow NVS task to write and commit
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_direction(0, &dir, RELAY_CHN_DIRECTION_DEFAULT));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, dir);
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, dir);
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test invalid parameters", "[relay_chn][nvs]")
|
TEST_CASE("Test invalid parameters", "[relay_chn][nvs]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
// Test NULL pointer
|
// Test NULL pointer
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_direction(0, NULL));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_direction(0, NULL, RELAY_CHN_DIRECTION_DEFAULT));
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test relay_chn_nvs_erase_all", "[relay_chn][nvs]")
|
TEST_CASE("Test relay_chn_nvs_erase_all", "[relay_chn][nvs]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
// Store some test data first
|
// Store some test data first
|
||||||
relay_chn_direction_t direction = RELAY_CHN_DIRECTION_FLIPPED;
|
relay_chn_direction_t direction = RELAY_CHN_DIRECTION_FLIPPED;
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_direction(0, direction));
|
TEST_ESP_OK(relay_chn_nvs_set_direction(0, direction));
|
||||||
|
|
||||||
#ifdef RELAY_CHN_ENABLE_TILTING
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
|
uint16_t run_limit = 123;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_set_run_limit(0, run_limit));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
uint8_t sensitivity = 50;
|
uint8_t sensitivity = 50;
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_tilt_sensitivity(0, sensitivity));
|
TEST_ESP_OK(relay_chn_nvs_set_tilt_sensitivity(0, sensitivity));
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_tilt_count(0, 100));
|
TEST_ESP_OK(relay_chn_nvs_set_tilt_count(0, 100));
|
||||||
@@ -62,76 +55,71 @@ TEST_CASE("Test relay_chn_nvs_erase_all", "[relay_chn][nvs]")
|
|||||||
// Test erase all
|
// Test erase all
|
||||||
TEST_ESP_OK(relay_chn_nvs_erase_all());
|
TEST_ESP_OK(relay_chn_nvs_erase_all());
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS)); // Allow NVS task to write and commit
|
||||||
// Verify data was erased by trying to read it back
|
// Verify data was erased by trying to read it back
|
||||||
relay_chn_direction_t read_direction;
|
relay_chn_direction_t read_direction;
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, relay_chn_nvs_get_direction(0, &read_direction));
|
TEST_ESP_OK(relay_chn_nvs_get_direction(0, &read_direction, RELAY_CHN_DIRECTION_DEFAULT));
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, read_direction);
|
||||||
|
|
||||||
#ifdef RELAY_CHN_ENABLE_TILTING
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
uint8_t read_sensitivity;
|
uint16_t read_run_limit;
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, relay_chn_nvs_get_tilt_sensitivity(0, &read_sensitivity));
|
TEST_ESP_OK(relay_chn_nvs_get_run_limit(0, &read_run_limit, CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC));
|
||||||
|
TEST_ASSERT_EQUAL(CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC, read_run_limit);
|
||||||
uint16_t tilt_count;
|
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, relay_chn_nvs_get_tilt_count(0, &tilt_count));
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
|
const uint8_t default_sensitivity_for_test = 42;
|
||||||
|
uint8_t read_sensitivity;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_tilt_sensitivity(0, &read_sensitivity, default_sensitivity_for_test));
|
||||||
|
TEST_ASSERT_EQUAL(default_sensitivity_for_test, read_sensitivity);
|
||||||
|
uint16_t tilt_count;
|
||||||
|
TEST_ESP_OK(relay_chn_nvs_get_tilt_count(0, &tilt_count, 0));
|
||||||
|
TEST_ASSERT_EQUAL(0, tilt_count);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
||||||
TEST_CASE("Test run limit setting and getting", "[relay_chn][nvs][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;
|
const uint16_t run_limit_sec = 32;
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_run_limit(0, run_limit_sec));
|
TEST_ESP_OK(relay_chn_nvs_set_run_limit(0, run_limit_sec));
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS)); // Allow NVS task to write and commit
|
||||||
uint16_t run_limit_read;
|
uint16_t run_limit_read;
|
||||||
TEST_ESP_OK(relay_chn_nvs_get_run_limit(0, &run_limit_read));
|
TEST_ESP_OK(relay_chn_nvs_get_run_limit(0, &run_limit_read, CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC));
|
||||||
TEST_ASSERT_EQUAL(run_limit_sec, run_limit_read);
|
TEST_ASSERT_EQUAL(run_limit_sec, run_limit_read);
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RELAY_CHN_ENABLE_TILTING
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
TEST_CASE("Test sensitivity setting and getting", "[relay_chn][nvs][tilt]")
|
TEST_CASE("Test sensitivity setting and getting", "[relay_chn][nvs][tilt]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
const uint8_t test_sensitivity = 75;
|
const uint8_t test_sensitivity = 75;
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_tilt_sensitivity(0, test_sensitivity));
|
TEST_ESP_OK(relay_chn_nvs_set_tilt_sensitivity(0, test_sensitivity));
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS)); // Allow NVS task to write and commit
|
||||||
uint8_t sensitivity;
|
uint8_t sensitivity;
|
||||||
TEST_ESP_OK(relay_chn_nvs_get_tilt_sensitivity(0, &sensitivity));
|
TEST_ESP_OK(relay_chn_nvs_get_tilt_sensitivity(0, &sensitivity, 0));
|
||||||
TEST_ASSERT_EQUAL(test_sensitivity, sensitivity);
|
TEST_ASSERT_EQUAL(test_sensitivity, sensitivity);
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test tilt counter operations", "[relay_chn][nvs][tilt]")
|
TEST_CASE("Test tilt counter operations", "[relay_chn][nvs][tilt]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
const uint16_t tilt_count = 100;
|
const uint16_t tilt_count = 100;
|
||||||
|
|
||||||
// Test setting counters
|
// Test setting counters
|
||||||
TEST_ESP_OK(relay_chn_nvs_set_tilt_count(0, tilt_count));
|
TEST_ESP_OK(relay_chn_nvs_set_tilt_count(0, tilt_count));
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_NVS_TASK_TIME_OUT_MS)); // Allow NVS task to write and commit
|
||||||
uint16_t tilt_count_read;
|
uint16_t tilt_count_read;
|
||||||
TEST_ESP_OK(relay_chn_nvs_get_tilt_count(0, &tilt_count_read));
|
TEST_ESP_OK(relay_chn_nvs_get_tilt_count(0, &tilt_count_read, 0));
|
||||||
TEST_ASSERT_EQUAL(tilt_count, tilt_count_read);
|
TEST_ASSERT_EQUAL(tilt_count, tilt_count_read);
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test tilting invalid parameters", "[relay_chn][nvs][tilt]")
|
TEST_CASE("Test tilting invalid parameters", "[relay_chn][nvs][tilt]")
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(relay_chn_nvs_init());
|
|
||||||
|
|
||||||
// Test NULL pointers
|
// Test NULL pointers
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_tilt_sensitivity(0, NULL));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_tilt_sensitivity(0, NULL, 0));
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_tilt_count(0, NULL));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_nvs_get_tilt_count(0, NULL, 0));
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_nvs_deinit());
|
|
||||||
}
|
}
|
||||||
#endif // RELAY_CHN_ENABLE_TILTING
|
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -12,334 +18,433 @@
|
|||||||
#define RELAY_CHN_CMD_FORWARD 1
|
#define RELAY_CHN_CMD_FORWARD 1
|
||||||
#define RELAY_CHN_CMD_REVERSE 2
|
#define RELAY_CHN_CMD_REVERSE 2
|
||||||
|
|
||||||
|
void check_all_channels_for_state(relay_chn_state_t state)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(state, relay_chn_get_state(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to prepare channel for tilt tests
|
// Helper function to prepare channel for tilt tests
|
||||||
void prepare_channel_for_tilt(uint8_t chn_id, int initial_cmd) {
|
void prepare_channels_for_tilt_with_mixed_runs() {
|
||||||
// Ensure the channel reset tilt control
|
// Ensure the channel reset tilt control
|
||||||
relay_chn_tilt_stop(chn_id);
|
relay_chn_tilt_stop_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// Ensure the channel has had a 'last_run_cmd'
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
relay_chn_run_forward(i);
|
||||||
|
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
||||||
|
relay_chn_run_reverse(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow command to process
|
||||||
|
relay_chn_stop_all(); // Stop it to set last_run_cmd but return to FREE for next test
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to prepare channel for tilt tests
|
||||||
|
void prepare_all_channels_for_tilt(int initial_cmd) {
|
||||||
|
// Ensure the channel reset tilt control
|
||||||
|
relay_chn_tilt_stop_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
|
// If the channels are not IDLE yet, wait more
|
||||||
|
bool not_idle = false;
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
if (relay_chn_get_state(i) != RELAY_CHN_STATE_IDLE) {
|
||||||
|
not_idle = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not_idle) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS));
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the channel has had a 'last_run_cmd'
|
// Ensure the channel has had a 'last_run_cmd'
|
||||||
if (initial_cmd == RELAY_CHN_CMD_FORWARD) {
|
if (initial_cmd == RELAY_CHN_CMD_FORWARD) {
|
||||||
relay_chn_run_forward(chn_id);
|
relay_chn_run_forward_all();
|
||||||
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
||||||
relay_chn_run_reverse(chn_id);
|
relay_chn_run_reverse_all();
|
||||||
}
|
}
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Allow command to process
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow command to process
|
||||||
relay_chn_stop(chn_id); // Stop it to set last_run_cmd but return to FREE for next test
|
relay_chn_stop_all(); // Stop all to set last_run_cmd but return to FREE for next test
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(chn_id));
|
|
||||||
|
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from running forward to tilt forward
|
// TEST_CASE: Test transition from running forward to tilt forward
|
||||||
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
||||||
TEST_CASE("Run Forward to Tilt Forward transition with inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Run Forward to Tilt Forward transition with inertia", "[relay_chn][tilt][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd
|
// Prepare channel by running forward first to set last_run_cmd
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
|
|
||||||
// 1. Start in forward direction
|
// 1. Start in forward direction
|
||||||
relay_chn_run_forward(ch);
|
relay_chn_run_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_FORWARD);
|
||||||
|
|
||||||
// 2. Issue tilt forward command
|
// 2. Issue tilt forward command
|
||||||
relay_chn_tilt_forward(ch);
|
relay_chn_tilt_forward_all();
|
||||||
// After tilt command, it should immediately stop and then trigger inertia.
|
// After tilt command, it should immediately stop and then trigger inertia.
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_STOPPED);
|
||||||
|
|
||||||
// Wait for the inertia period (after which the tilt command will be dispatched)
|
// Wait for the inertia period (after which the tilt command will be dispatched)
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from running reverse to tilt reverse
|
// TEST_CASE: Test transition from running reverse to tilt reverse
|
||||||
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
||||||
TEST_CASE("Run Reverse to Tilt Reverse transition with inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Run Reverse to Tilt Reverse transition with inertia", "[relay_chn][tilt][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// Prepare channel by running reverse first to set last_run_cmd
|
// Prepare channel by running reverse first to set last_run_cmd
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_REVERSE);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
|
|
||||||
// 1. Start in reverse direction
|
// 1. Start in reverse direction
|
||||||
relay_chn_run_reverse(ch);
|
relay_chn_run_reverse_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE);
|
||||||
|
|
||||||
// 2. Issue tilt reverse command
|
// 2. Issue tilt reverse command
|
||||||
relay_chn_tilt_reverse(ch);
|
relay_chn_tilt_reverse_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_STOPPED);
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from FREE state to tilt forward (now with preparation)
|
// TEST_CASE: Test transition from FREE state to tilt forward (now with preparation)
|
||||||
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
||||||
TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn][tilt][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd
|
// Prepare channel by running forward first to set last_run_cmd
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch)); // Ensure we are back to FREE
|
|
||||||
|
|
||||||
// Issue tilt forward command
|
// Issue tilt forward command
|
||||||
relay_chn_tilt_forward(ch);
|
relay_chn_tilt_forward_all();
|
||||||
// From FREE state, tilt command should still incur the inertia due to the internal timer logic
|
// From FREE state, tilt command should still incur the inertia due to the internal timer logic
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from FREE state to tilt reverse (now with preparation)
|
// TEST_CASE: Test transition from FREE state to tilt reverse (now with preparation)
|
||||||
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
||||||
TEST_CASE("FREE to Tilt Reverse transition with inertia (prepared)", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("FREE to Tilt Reverse transition with inertia (prepared)", "[relay_chn][tilt][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// Prepare channel by running reverse first to set last_run_cmd
|
// Prepare channel by running reverse first to set last_run_cmd
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_REVERSE);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch)); // Ensure we are back to FREE
|
|
||||||
|
|
||||||
// Issue tilt reverse command
|
// Issue tilt reverse command
|
||||||
relay_chn_tilt_reverse(ch);
|
relay_chn_tilt_reverse_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from tilt forward to run forward (inertia expected for run)
|
// TEST_CASE: Test transition from tilt forward to run forward (inertia expected for run)
|
||||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||||
TEST_CASE("Tilt Forward to Run Forward transition with inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Tilt Forward to Run Forward transition with inertia", "[relay_chn][tilt][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_forward(ch); // Go to tilt state
|
relay_chn_tilt_forward_all(); // Go to tilt state
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
|
|
||||||
// 2. Issue run forward command
|
// 2. Issue run forward command
|
||||||
relay_chn_run_forward(ch);
|
relay_chn_run_forward_all();
|
||||||
// From Tilt to Run in the same logical name but in the opposite direction, inertia is expected.
|
// From Tilt to Run in the same logical name but in the opposite direction, inertia is expected.
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_FORWARD_PENDING);
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_FORWARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from tilt reverse to run reverse (no inertia expected for run)
|
// TEST_CASE: Test transition from tilt reverse to run reverse (no inertia expected for run)
|
||||||
// Scenario: RELAY_CHN_STATE_TILT_REVERSE -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
// Scenario: RELAY_CHN_STATE_TILT_REVERSE -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
||||||
TEST_CASE("Tilt Reverse to Run Reverse transition with inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Tilt Reverse to Run Reverse transition with inertia", "[relay_chn][tilt][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// Prepare channel by running reverse first to set last_run_cmd, then tilt
|
// Prepare channel by running reverse first to set last_run_cmd, then tilt
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_REVERSE);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
relay_chn_tilt_reverse(ch); // Go to tilt state
|
relay_chn_tilt_reverse_all(); // Go to tilt state
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||||
|
|
||||||
// 2. Issue run reverse command
|
// 2. Issue run reverse command
|
||||||
relay_chn_run_reverse(ch);
|
relay_chn_run_reverse_all();
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE_PENDING);
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from tilt forward to run reverse (without inertia)
|
// TEST_CASE: Test transition from tilt forward to run reverse (without inertia)
|
||||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
||||||
TEST_CASE("Tilt Forward to Run Reverse transition without inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Tilt Forward to Run Reverse transition without inertia", "[relay_chn][tilt][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_forward(ch); // Go to tilt state
|
relay_chn_tilt_forward_all(); // Go to tilt state
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
|
|
||||||
// 2. Issue run reverse command (opposite direction)
|
// 2. Issue run reverse command (opposite direction)
|
||||||
relay_chn_run_reverse(ch);
|
relay_chn_run_reverse_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test stopping from a tilt state (no inertia for stop command itself)
|
// TEST_CASE: Test stopping from a tilt state (no inertia for stop command itself)
|
||||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_stop) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_IDLE
|
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_tilt_stop) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_IDLE
|
||||||
TEST_CASE("Tilt to Stop transition without immediate inertia for stop", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Tilt to Stop transition without immediate inertia for stop", "[relay_chn][tilt][inertia]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
|
// Prepare all channels by running forward first to set last_run_cmd, then tilt
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
relay_chn_tilt_forward_all(); // Go to tilt state
|
||||||
relay_chn_tilt_forward(ch); // Go to tilt state
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
// Verify all channels are tilting forward
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
|
|
||||||
// 2. Issue stop command
|
// 2. Issue stop command
|
||||||
relay_chn_stop(ch);
|
relay_chn_tilt_stop_all();
|
||||||
// Stop command should apply immediately, setting state to FREE since last state was tilt.
|
// Stop command should apply immediately, setting state to FREE since last state was tilt.
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch));
|
// Verify all channels are IDLE
|
||||||
|
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ### Tilt Broadcast Command (RELAY_CHN_ID_ALL) Tests
|
// ### Batch Tilt Control Tests
|
||||||
|
|
||||||
TEST_CASE("tilt_forward with ID_ALL sets all channels to TILT_FORWARD", "[relay_chn][tilt][id_all]")
|
TEST_CASE("tilt_forward_all sets all channels to TILT_FORWARD", "[relay_chn][tilt][batch]")
|
||||||
{
|
{
|
||||||
// 1. Prepare all channels.
|
// 1. Prepare all channels.
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
prepare_channel_for_tilt(i, RELAY_CHN_CMD_FORWARD);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Issue tilt forward to all channels
|
// 2. Issue tilt forward to all channels
|
||||||
relay_chn_tilt_forward(RELAY_CHN_ID_ALL);
|
relay_chn_tilt_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Tilt from FREE doesn't have stop-inertia
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Tilt from FREE doesn't have stop-inertia
|
||||||
|
|
||||||
// 3. Verify all channels are tilting forward
|
// 3. Verify all channels are tilting forward
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("tilt_reverse with ID_ALL sets all channels to TILT_REVERSE", "[relay_chn][tilt][id_all]")
|
TEST_CASE("tilt_reverse_all sets all channels to TILT_REVERSE", "[relay_chn][tilt][batch]")
|
||||||
{
|
{
|
||||||
// 1. Prepare all channels.
|
// 1. Prepare all channels.
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
prepare_channel_for_tilt(i, RELAY_CHN_CMD_REVERSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Issue tilt reverse to all channels
|
// 2. Issue tilt reverse to all channels
|
||||||
relay_chn_tilt_reverse(RELAY_CHN_ID_ALL);
|
relay_chn_tilt_reverse_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
// 3. Verify all channels are tilting reverse
|
// 3. Verify all channels are tilting reverse
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("tilt_stop with ID_ALL stops all tilting channels", "[relay_chn][tilt][id_all]")
|
TEST_CASE("tilt_stop_all stops all tilting channels", "[relay_chn][tilt][batch]")
|
||||||
{
|
{
|
||||||
// 1. Prepare and start all channels tilting forward
|
// 1. Prepare and start all channels tilting forward
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
prepare_channel_for_tilt(i, RELAY_CHN_CMD_REVERSE);
|
|
||||||
}
|
relay_chn_tilt_forward_all();
|
||||||
relay_chn_tilt_forward(RELAY_CHN_ID_ALL);
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
|
|
||||||
// 2. Stop tilting on all channels
|
// 2. Stop tilting on all channels
|
||||||
relay_chn_tilt_stop(RELAY_CHN_ID_ALL);
|
relay_chn_tilt_stop_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
// 3. Verify all channels are free
|
// 3. Verify all channels are free
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("tilt_auto with ID_ALL tilts channels based on last run direction", "[relay_chn][tilt][id_all]")
|
TEST_CASE("tilt_auto_all tilts channels based on last run direction", "[relay_chn][tilt][batch]")
|
||||||
{
|
{
|
||||||
// This test requires at least 2 channels to demonstrate different behaviors
|
// This test requires at least 2 channels to demonstrate different behaviors
|
||||||
TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(2, relay_chn_count, "Test requires at least 2 channels");
|
TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(2, CONFIG_RELAY_CHN_COUNT, "Test requires at least 2 channels");
|
||||||
|
|
||||||
// 1. Prepare channel 0 with last run FORWARD and channel 1 with last run REVERSE
|
// 1. Prepare channel 0 with last run FORWARD and channel 1 with last run REVERSE
|
||||||
prepare_channel_for_tilt(0, RELAY_CHN_CMD_FORWARD);
|
prepare_channels_for_tilt_with_mixed_runs();
|
||||||
prepare_channel_for_tilt(1, RELAY_CHN_CMD_REVERSE);
|
|
||||||
|
|
||||||
// 2. Issue auto tilt command to all channels
|
// 2. Issue auto tilt command to all channels
|
||||||
relay_chn_tilt_auto(RELAY_CHN_ID_ALL);
|
relay_chn_tilt_auto_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Tilt from FREE state is dispatched immediately
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Tilt from FREE state is dispatched immediately
|
||||||
|
|
||||||
// 3. Verify channel 0 tilts forward (last run was forward) and channel 1 tilts reverse (last run was reverse)
|
// 3. Verify even channels tilt forward (last run was forward) and odd channels tilt reverse (last run was reverse)
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(0));
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(1));
|
relay_chn_state_t state = i % 2 == 0 ?
|
||||||
|
RELAY_CHN_STATE_TILT_FORWARD : RELAY_CHN_STATE_TILT_REVERSE;
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(state, relay_chn_get_state(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test relay_chn_tilt_auto() chooses correct tilt direction
|
// Test relay_chn_tilt_auto() chooses correct tilt direction
|
||||||
TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][auto]") {
|
TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][auto]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
// Prepare FORWARD
|
// Prepare FORWARD
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_auto(ch);
|
relay_chn_tilt_auto_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
// Verify all tilt forward
|
||||||
relay_chn_tilt_stop(ch);
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
|
relay_chn_tilt_stop_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
// Prepare REVERSE
|
// Prepare REVERSE
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_REVERSE);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
relay_chn_tilt_auto(ch);
|
relay_chn_tilt_auto_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(ch));
|
// Verify all tilt reverse
|
||||||
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test sensitivity set/get
|
// Test sensitivity set/get
|
||||||
TEST_CASE("relay_chn_tilt_set_sensitivity and get", "[relay_chn][tilt][sensitivity]") {
|
TEST_CASE("relay_chn_tilt_set_sensitivity and get", "[relay_chn][tilt][sensitivity]")
|
||||||
|
{
|
||||||
uint8_t ch = 0;
|
uint8_t ch = 0;
|
||||||
uint8_t val = 0;
|
|
||||||
relay_chn_tilt_set_sensitivity(ch, 0);
|
relay_chn_tilt_set_sensitivity(ch, 0);
|
||||||
TEST_ESP_OK(relay_chn_tilt_get_sensitivity(ch, &val, 1));
|
TEST_ASSERT_EQUAL_UINT8(0, relay_chn_tilt_get_sensitivity(ch));
|
||||||
TEST_ASSERT_EQUAL_UINT8(0, val);
|
|
||||||
|
|
||||||
relay_chn_tilt_set_sensitivity(ch, 50);
|
relay_chn_tilt_set_sensitivity(ch, 50);
|
||||||
TEST_ESP_OK(relay_chn_tilt_get_sensitivity(ch, &val, 1));
|
TEST_ASSERT_EQUAL_UINT8(50, relay_chn_tilt_get_sensitivity(ch));
|
||||||
TEST_ASSERT_EQUAL_UINT8(50, val);
|
|
||||||
|
|
||||||
relay_chn_tilt_set_sensitivity(ch, 100);
|
relay_chn_tilt_set_sensitivity(ch, 100);
|
||||||
TEST_ESP_OK(relay_chn_tilt_get_sensitivity(ch, &val, 1));
|
TEST_ASSERT_EQUAL_UINT8(100, relay_chn_tilt_get_sensitivity(ch));
|
||||||
TEST_ASSERT_EQUAL_UINT8(100, val);
|
|
||||||
|
|
||||||
// Set all channels
|
// Set all channels
|
||||||
relay_chn_tilt_set_sensitivity(RELAY_CHN_ID_ALL, 42);
|
relay_chn_tilt_set_sensitivity_all_with(42);
|
||||||
|
|
||||||
uint8_t vals[CONFIG_RELAY_CHN_COUNT] = {0};
|
uint8_t vals[CONFIG_RELAY_CHN_COUNT] = {0};
|
||||||
TEST_ESP_OK(relay_chn_tilt_get_sensitivity(RELAY_CHN_ID_ALL, vals, relay_chn_count));
|
uint8_t expect[CONFIG_RELAY_CHN_COUNT];
|
||||||
for (int i = 0; i < relay_chn_count; ++i) {
|
memset(expect, 42, CONFIG_RELAY_CHN_COUNT);
|
||||||
TEST_ASSERT_EQUAL_UINT8(42, vals[i]);
|
|
||||||
|
TEST_ESP_OK(relay_chn_tilt_get_sensitivity_all(vals));
|
||||||
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(expect, vals, CONFIG_RELAY_CHN_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("relay_chn_tilt_get_default_sensitivity returns correct value", "[relay_chn][tilt][sensitivity]")
|
||||||
|
{
|
||||||
|
// The default sensitivity is calculated from default timing values.
|
||||||
|
// Default run time: 15ms, Min run time: 50ms, Max run time: 10ms.
|
||||||
|
// Formula: ( (DEFAULT_RUN - MIN_RUN) * 100 ) / (MAX_RUN - MIN_RUN)
|
||||||
|
// ( (15 - 50) * 100 ) / (10 - 50) = (-35 * 100) / -40 = -3500 / -40 = 87.5
|
||||||
|
// As integer arithmetic, this is 87.
|
||||||
|
uint8_t expected_sensitivity = 87;
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(expected_sensitivity, relay_chn_tilt_get_default_sensitivity());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sensitivity upper boundary for all set functions
|
||||||
|
TEST_CASE("relay_chn_tilt_set_sensitivity functions handle upper boundary", "[relay_chn][tilt][sensitivity]")
|
||||||
|
{
|
||||||
|
// 1. Test relay_chn_tilt_set_sensitivity() for each channel
|
||||||
|
for (uint8_t ch = 0; ch < CONFIG_RELAY_CHN_COUNT; ch++) {
|
||||||
|
relay_chn_tilt_set_sensitivity(ch, 101);
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(100, relay_chn_tilt_get_sensitivity(ch));
|
||||||
|
|
||||||
|
relay_chn_tilt_set_sensitivity(ch, 255);
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(100, relay_chn_tilt_get_sensitivity(ch));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Test relay_chn_tilt_set_sensitivity_all_with()
|
||||||
|
relay_chn_tilt_set_sensitivity_all_with(150);
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(100, relay_chn_tilt_get_sensitivity(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Test relay_chn_tilt_set_sensitivity_all()
|
||||||
|
uint8_t sensitivities[CONFIG_RELAY_CHN_COUNT];
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
sensitivities[i] = 100 + i * 10; // Values like 100, 110, 120...
|
||||||
|
}
|
||||||
|
TEST_ESP_OK(relay_chn_tilt_set_sensitivity_all(sensitivities));
|
||||||
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(100, relay_chn_tilt_get_sensitivity(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test tilt counter logic: forward x3, reverse x3, extra reverse fails
|
// Test tilt counter logic: forward x3, reverse x3, extra reverse fails
|
||||||
TEST_CASE("tilt counter logic: forward and reverse consumption", "[relay_chn][tilt][counter]") {
|
TEST_CASE("tilt counter logic: forward and reverse consumption", "[relay_chn][tilt][counter]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
// Tilt execution time at 100% sensitivity in milliseconds (10 + 90)
|
||||||
|
#define TEST_TILT_EXECUTION_TIME_MS 100
|
||||||
|
|
||||||
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
|
relay_chn_tilt_set_sensitivity_all_with(100); // Set sentivity to max for fastest execution
|
||||||
|
|
||||||
// Tilt forward 3 times
|
// Tilt forward 3 times
|
||||||
for (int i = 0; i < 3; ++i) {
|
relay_chn_tilt_forward_all();
|
||||||
relay_chn_tilt_forward(ch);
|
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS * 3 + TEST_DELAY_MARGIN_MS));
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
|
||||||
relay_chn_tilt_stop(ch);
|
// Stop tilt on all channels
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
relay_chn_tilt_stop_all();
|
||||||
}
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
||||||
|
// Tilt stop should save the latest tilt count to the NVS
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS + 300));
|
||||||
|
#else
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
#endif
|
||||||
|
|
||||||
// Now tilt reverse 3 times (should succeed)
|
// Now tilt reverse 3 times (should succeed)
|
||||||
for (int i = 0; i < 3; ++i) {
|
relay_chn_tilt_reverse_all();
|
||||||
relay_chn_tilt_reverse(ch);
|
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS * 3 + TEST_DELAY_MARGIN_MS));
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||||
if (i < 3) {
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(ch));
|
|
||||||
relay_chn_tilt_stop(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra reverse tilt should fail (counter exhausted)
|
// One more reverse tilt should fail (counter exhausted)
|
||||||
relay_chn_tilt_reverse(ch);
|
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS * 3));
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
// Should not enter TILT_REVERSE, should remain IDLE
|
||||||
// Should not enter TILT_REVERSE, should remain FREE or STOPPED
|
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||||
relay_chn_state_t state = relay_chn_get_state(ch);
|
|
||||||
TEST_ASSERT(state != RELAY_CHN_STATE_TILT_REVERSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test run command during TILT state
|
// Test run command during TILT state
|
||||||
TEST_CASE("run command during TILT state transitions correctly", "[relay_chn][tilt][run-during-tilt]") {
|
TEST_CASE("run command during TILT state transitions correctly", "[relay_chn][tilt][run-during-tilt]")
|
||||||
uint8_t ch = 0;
|
{
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_forward(ch);
|
relay_chn_tilt_forward_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
|
|
||||||
// Issue run reverse while in TILT_FORWARD
|
// Issue run reverse while in TILT_FORWARD
|
||||||
relay_chn_run_reverse(ch);
|
relay_chn_run_reverse_all();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
// Should transition to REVERSE or REVERSE_PENDING depending on inertia logic
|
// Should transition to REVERSE
|
||||||
relay_chn_state_t state = relay_chn_get_state(ch);
|
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE);
|
||||||
TEST_ASSERT(state == RELAY_CHN_STATE_REVERSE || state == RELAY_CHN_STATE_REVERSE_PENDING);
|
}
|
||||||
|
|
||||||
|
// Test run command during active tilt cycle (move/pause)
|
||||||
|
TEST_CASE("run_all command during active tilt cycle stops tilt", "[relay_chn][tilt][interrupt]")
|
||||||
|
{
|
||||||
|
// Set a known sensitivity for predictable timing.
|
||||||
|
// For sensitivity=50, move_time=30ms, pause_time=270ms.
|
||||||
|
relay_chn_tilt_set_sensitivity_all_with(50);
|
||||||
|
const uint32_t move_time_ms = 30;
|
||||||
|
|
||||||
|
// --- Test interrupting during MOVE step ---
|
||||||
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
|
relay_chn_tilt_forward_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(move_time_ms / 2)); // Wait for half of the move time
|
||||||
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
|
|
||||||
|
// Interrupt with run_reverse_all while in the MOVE part of the cycle
|
||||||
|
relay_chn_run_reverse_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
// Should stop tilting and go to REVERSE immediately (no inertia from TILT_FORWARD)
|
||||||
|
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE);
|
||||||
|
|
||||||
|
// --- Test interrupting during PAUSE step ---
|
||||||
|
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
|
relay_chn_tilt_forward_all();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(move_time_ms + TEST_DELAY_MARGIN_MS)); // Wait past MOVE, into PAUSE
|
||||||
|
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||||
|
|
||||||
|
// Interrupt with run_forward_all while in the PAUSE part of the cycle
|
||||||
|
relay_chn_run_forward_all();
|
||||||
|
// Should stop tilting and go to FORWARD_PENDING (inertia from TILT_FORWARD)
|
||||||
|
check_all_channels_for_state(RELAY_CHN_STATE_FORWARD_PENDING);
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -16,7 +22,7 @@
|
|||||||
void prepare_channel_for_tilt(int initial_cmd) {
|
void prepare_channel_for_tilt(int initial_cmd) {
|
||||||
// Ensure the channel reset tilt control
|
// Ensure the channel reset tilt control
|
||||||
relay_chn_tilt_stop();
|
relay_chn_tilt_stop();
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
// Ensure the channel has had a 'last_run_cmd'
|
// Ensure the channel has had a 'last_run_cmd'
|
||||||
if (initial_cmd == RELAY_CHN_CMD_FORWARD) {
|
if (initial_cmd == RELAY_CHN_CMD_FORWARD) {
|
||||||
@@ -24,57 +30,60 @@ void prepare_channel_for_tilt(int initial_cmd) {
|
|||||||
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
||||||
relay_chn_run_reverse();
|
relay_chn_run_reverse();
|
||||||
}
|
}
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Allow command to process
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow command to process
|
||||||
relay_chn_stop(); // Stop it to set last_run_cmd but return to FREE for next test
|
relay_chn_stop(); // Stop it to set last_run_cmd but return to FREE for next test
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from running forward to tilt forward
|
// Test transition from running forward to tilt forward
|
||||||
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
||||||
TEST_CASE("Run Forward to Tilt Forward transition with inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Run Forward to Tilt Forward transition with inertia", "[relay_chn][tilt][inertia]")
|
||||||
|
{
|
||||||
// Prepare channel by running forward first to set last_run_cmd
|
// Prepare channel by running forward first to set last_run_cmd
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
|
|
||||||
// 1. Start in forward direction
|
// 1. Start in forward direction
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue tilt forward command
|
// 2. Issue tilt forward command
|
||||||
relay_chn_tilt_forward();
|
relay_chn_tilt_forward();
|
||||||
// After tilt command, it should immediately stop and then trigger inertia.
|
// After tilt command, it should immediately stop and then trigger inertia.
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||||
|
|
||||||
// Wait for the inertia period (after which the tilt command will be dispatched)
|
// Wait for the inertia period (after which the tilt command will be dispatched)
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from running reverse to tilt reverse
|
// Test transition from running reverse to tilt reverse
|
||||||
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
||||||
TEST_CASE("Run Reverse to Tilt Reverse transition with inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Run Reverse to Tilt Reverse transition with inertia", "[relay_chn][tilt][inertia]")
|
||||||
|
{
|
||||||
// Prepare channel by running reverse first to set last_run_cmd
|
// Prepare channel by running reverse first to set last_run_cmd
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
|
|
||||||
// 1. Start in reverse direction
|
// 1. Start in reverse direction
|
||||||
relay_chn_run_reverse();
|
relay_chn_run_reverse();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue tilt reverse command
|
// 2. Issue tilt reverse command
|
||||||
relay_chn_tilt_reverse();
|
relay_chn_tilt_reverse();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from FREE state to tilt forward (now with preparation)
|
// Test transition from FREE state to tilt forward (now with preparation)
|
||||||
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
||||||
TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn][tilt][inertia]")
|
||||||
|
{
|
||||||
// Prepare channel by running forward first to set last_run_cmd
|
// Prepare channel by running forward first to set last_run_cmd
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); // Ensure we are back to FREE
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); // Ensure we are back to FREE
|
||||||
@@ -82,106 +91,113 @@ TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn
|
|||||||
// Issue tilt forward command
|
// Issue tilt forward command
|
||||||
relay_chn_tilt_forward();
|
relay_chn_tilt_forward();
|
||||||
// From FREE state, tilt command should still incur the inertia due to the internal timer logic
|
// From FREE state, tilt command should still incur the inertia due to the internal timer logic
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from FREE state to tilt reverse (now with preparation)
|
// Test transition from FREE state to tilt reverse (now with preparation)
|
||||||
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
||||||
TEST_CASE("FREE to Tilt Reverse transition with inertia (prepared)", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("FREE to Tilt Reverse transition with inertia (prepared)", "[relay_chn][tilt][inertia]")
|
||||||
|
{
|
||||||
// Prepare channel by running reverse first to set last_run_cmd
|
// Prepare channel by running reverse first to set last_run_cmd
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); // Ensure we are back to FREE
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); // Ensure we are back to FREE
|
||||||
|
|
||||||
// Issue tilt reverse command
|
// Issue tilt reverse command
|
||||||
relay_chn_tilt_reverse();
|
relay_chn_tilt_reverse();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from tilt forward to run forward (inertia expected for run)
|
// Test transition from tilt forward to run forward (inertia expected for run)
|
||||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||||
TEST_CASE("Tilt Forward to Run Forward transition with inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Tilt Forward to Run Forward transition with inertia", "[relay_chn][tilt][inertia]")
|
||||||
|
{
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_forward(); // Go to tilt state
|
relay_chn_tilt_forward(); // Go to tilt state
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue run forward command
|
// 2. Issue run forward command
|
||||||
relay_chn_run_forward();
|
relay_chn_run_forward();
|
||||||
// From Tilt to Run in the same logical name but in the opposite direction, inertia is expected.
|
// From Tilt to Run in the same logical name but in the opposite direction, inertia is expected.
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state());
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from tilt reverse to run reverse (no inertia expected for run)
|
// Test transition from tilt reverse to run reverse (no inertia expected for run)
|
||||||
// Scenario: RELAY_CHN_STATE_TILT_REVERSE -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
// Scenario: RELAY_CHN_STATE_TILT_REVERSE -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
||||||
TEST_CASE("Tilt Reverse to Run Reverse transition with inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Tilt Reverse to Run Reverse transition with inertia", "[relay_chn][tilt][inertia]")
|
||||||
|
{
|
||||||
// Prepare channel by running reverse first to set last_run_cmd, then tilt
|
// Prepare channel by running reverse first to set last_run_cmd, then tilt
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
relay_chn_tilt_reverse(); // Go to tilt state
|
relay_chn_tilt_reverse(); // Go to tilt state
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue run reverse command
|
// 2. Issue run reverse command
|
||||||
relay_chn_run_reverse();
|
relay_chn_run_reverse();
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state());
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test transition from tilt forward to run reverse (without inertia)
|
// Test transition from tilt forward to run reverse (without inertia)
|
||||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
||||||
TEST_CASE("Tilt Forward to Run Reverse transition without inertia", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Tilt Forward to Run Reverse transition without inertia", "[relay_chn][tilt][inertia]")
|
||||||
|
{
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_forward(); // Go to tilt state
|
relay_chn_tilt_forward(); // Go to tilt state
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue run reverse command (opposite direction)
|
// 2. Issue run reverse command (opposite direction)
|
||||||
relay_chn_run_reverse();
|
relay_chn_run_reverse();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_CASE: Test stopping from a tilt state (no inertia for stop command itself)
|
// Test stopping from a tilt state (no inertia for stop command itself)
|
||||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_stop) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_IDLE
|
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_tilt_stop) -> RELAY_CHN_STATE_IDLE
|
||||||
TEST_CASE("Tilt to Stop transition without immediate inertia for stop", "[relay_chn][tilt][inertia]") {
|
TEST_CASE("Tilt to Stop transition without immediate inertia for stop", "[relay_chn][tilt][inertia]")
|
||||||
|
{
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_forward(); // Go to tilt state
|
relay_chn_tilt_forward(); // Go to tilt state
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// 2. Issue stop command
|
// 2. Issue stop command
|
||||||
relay_chn_stop();
|
relay_chn_tilt_stop();
|
||||||
// Stop command should apply immediately, setting state to FREE since last state was tilt.
|
// Stop command should apply immediately, setting state to FREE since last state was tilt.
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test relay_chn_tilt_auto() chooses correct tilt direction
|
// Test relay_chn_tilt_auto() chooses correct tilt direction
|
||||||
TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][auto]") {
|
TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][auto]")
|
||||||
|
{
|
||||||
// Prepare FORWARD
|
// Prepare FORWARD
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_auto();
|
relay_chn_tilt_auto();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
relay_chn_tilt_stop();
|
relay_chn_tilt_stop();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
|
||||||
// Prepare REVERSE
|
// Prepare REVERSE
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||||
relay_chn_tilt_auto();
|
relay_chn_tilt_auto();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test sensitivity set/get
|
// Test sensitivity set/get
|
||||||
TEST_CASE("relay_chn_tilt_set_sensitivity and get", "[relay_chn][tilt][sensitivity]") {
|
TEST_CASE("relay_chn_tilt_set_sensitivity and get", "[relay_chn][tilt][sensitivity]")
|
||||||
|
{
|
||||||
relay_chn_tilt_set_sensitivity(0);
|
relay_chn_tilt_set_sensitivity(0);
|
||||||
TEST_ASSERT_EQUAL_UINT8(0, relay_chn_tilt_get_sensitivity());
|
TEST_ASSERT_EQUAL_UINT8(0, relay_chn_tilt_get_sensitivity());
|
||||||
|
|
||||||
@@ -195,49 +211,106 @@ TEST_CASE("relay_chn_tilt_set_sensitivity and get", "[relay_chn][tilt][sensitivi
|
|||||||
TEST_ASSERT_EQUAL_UINT8(42, relay_chn_tilt_get_sensitivity());
|
TEST_ASSERT_EQUAL_UINT8(42, relay_chn_tilt_get_sensitivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("relay_chn_tilt_get_default_sensitivity returns correct value", "[relay_chn][tilt][sensitivity]")
|
||||||
|
{
|
||||||
|
// The default sensitivity is calculated from default timing values.
|
||||||
|
// Default run time: 15ms, Min run time: 50ms, Max run time: 10ms.
|
||||||
|
// Formula: ( (DEFAULT_RUN - MIN_RUN) * 100 ) / (MAX_RUN - MIN_RUN)
|
||||||
|
// ( (15 - 50) * 100 ) / (10 - 50) = (-35 * 100) / -40 = -3500 / -40 = 87.5
|
||||||
|
// As integer arithmetic, this is 87.
|
||||||
|
uint8_t expected_sensitivity = 87;
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(expected_sensitivity, relay_chn_tilt_get_default_sensitivity());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sensitivity upper boundary
|
||||||
|
TEST_CASE("relay_chn_tilt_set_sensitivity handles upper boundary", "[relay_chn][tilt][sensitivity]")
|
||||||
|
{
|
||||||
|
// Set sensitivity to a value greater than 100
|
||||||
|
relay_chn_tilt_set_sensitivity(101);
|
||||||
|
// It should be capped at 100
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(100, relay_chn_tilt_get_sensitivity());
|
||||||
|
|
||||||
|
relay_chn_tilt_set_sensitivity(200);
|
||||||
|
TEST_ASSERT_EQUAL_UINT8(100, relay_chn_tilt_get_sensitivity());
|
||||||
|
}
|
||||||
|
|
||||||
// Test tilt counter logic: forward x3, reverse x3, extra reverse fails
|
// Test tilt counter logic: forward x3, reverse x3, extra reverse fails
|
||||||
TEST_CASE("tilt counter logic: forward and reverse consumption", "[relay_chn][tilt][counter]") {
|
TEST_CASE("tilt counter logic: forward and reverse consumption", "[relay_chn][tilt][counter]")
|
||||||
|
{
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
|
|
||||||
// Tilt forward 3 times
|
// Tilt forward 3 times
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
relay_chn_tilt_forward();
|
relay_chn_tilt_forward();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
relay_chn_tilt_stop();
|
relay_chn_tilt_stop();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now tilt reverse 3 times (should succeed)
|
// Now tilt reverse 3 times (should succeed)
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
relay_chn_tilt_reverse();
|
relay_chn_tilt_reverse();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
if (i < 3) {
|
if (i < 3) {
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||||
relay_chn_tilt_stop();
|
relay_chn_tilt_stop();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra reverse tilt should fail (counter exhausted)
|
// Extra reverse tilt should fail (counter exhausted)
|
||||||
relay_chn_tilt_reverse();
|
relay_chn_tilt_reverse();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
// Should not enter TILT_REVERSE, should remain FREE or STOPPED
|
// Should not enter TILT_REVERSE, should remain FREE or STOPPED
|
||||||
relay_chn_state_t state = relay_chn_get_state();
|
relay_chn_state_t state = relay_chn_get_state();
|
||||||
TEST_ASSERT(state != RELAY_CHN_STATE_TILT_REVERSE);
|
TEST_ASSERT(state != RELAY_CHN_STATE_TILT_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test run command during TILT state
|
// Test run command during TILT state
|
||||||
TEST_CASE("run command during TILT state transitions correctly", "[relay_chn][tilt][run-during-tilt]") {
|
TEST_CASE("run command during TILT state transitions correctly", "[relay_chn][tilt][run-during-tilt]")
|
||||||
|
{
|
||||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
relay_chn_tilt_forward();
|
relay_chn_tilt_forward();
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
// Issue run reverse while in TILT_FORWARD
|
// Issue run reverse while in TILT_FORWARD
|
||||||
relay_chn_run_reverse();
|
relay_chn_run_reverse();
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
// Should transition to REVERSE or REVERSE_PENDING depending on inertia logic
|
// Should transition to REVERSE or REVERSE_PENDING depending on inertia logic
|
||||||
relay_chn_state_t state = relay_chn_get_state();
|
relay_chn_state_t state = relay_chn_get_state();
|
||||||
TEST_ASSERT(state == RELAY_CHN_STATE_REVERSE || state == RELAY_CHN_STATE_REVERSE_PENDING);
|
TEST_ASSERT(state == RELAY_CHN_STATE_REVERSE || state == RELAY_CHN_STATE_REVERSE_PENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test run command during active tilt cycle (move/pause)
|
||||||
|
TEST_CASE("run command during active tilt cycle stops tilt", "[relay_chn][tilt][interrupt]")
|
||||||
|
{
|
||||||
|
// Set a known sensitivity for predictable timing.
|
||||||
|
// For sensitivity=50, move_time=30ms, pause_time=270ms.
|
||||||
|
relay_chn_tilt_set_sensitivity(50);
|
||||||
|
const uint32_t move_time_ms = 30;
|
||||||
|
|
||||||
|
// --- Test interrupting during MOVE step ---
|
||||||
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
|
relay_chn_tilt_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(move_time_ms / 2)); // Wait for half of the move time
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
|
// Interrupt with run_reverse while in the MOVE part of the cycle
|
||||||
|
relay_chn_run_reverse();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||||
|
// Should stop tilting and go to REVERSE immediately (no inertia from TILT_FORWARD)
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||||
|
|
||||||
|
// --- Test interrupting during PAUSE step ---
|
||||||
|
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||||
|
relay_chn_tilt_forward();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(move_time_ms + TEST_DELAY_MARGIN_MS)); // Wait past MOVE, into PAUSE
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||||
|
|
||||||
|
// Interrupt with run_forward while in the PAUSE part of the cycle
|
||||||
|
relay_chn_run_forward();
|
||||||
|
// Should stop tilting and go to FORWARD_PENDING (inertia from TILT_FORWARD)
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state());
|
||||||
|
}
|
||||||
1
test_apps/profiles/full_multi
Normal file
1
test_apps/profiles/full_multi
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.multi;sdkconfig.defaults.run_limit;sdkconfig.defaults.tilt;sdkconfig.defaults.nvs;sdkconfig.defaults.nvs_custom"
|
||||||
1
test_apps/profiles/full_single
Normal file
1
test_apps/profiles/full_single
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.run_limit;sdkconfig.defaults.tilt;sdkconfig.defaults.nvs;sdkconfig.defaults.nvs_custom"
|
||||||
1
test_apps/profiles/multi
Normal file
1
test_apps/profiles/multi
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.multi"
|
||||||
1
test_apps/profiles/nvs
Normal file
1
test_apps/profiles/nvs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.nvs"
|
||||||
1
test_apps/profiles/nvs_custom
Normal file
1
test_apps/profiles/nvs_custom
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.nvs;sdkconfig.defaults.nvs_custom"
|
||||||
1
test_apps/profiles/run_limit
Normal file
1
test_apps/profiles/run_limit
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.run_limit"
|
||||||
1
test_apps/profiles/tilt
Normal file
1
test_apps/profiles/tilt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.tilt"
|
||||||
1414
test_apps/sdkconfig
1414
test_apps/sdkconfig
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1 @@
|
|||||||
# 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_COUNT=8
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# 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_NVS=y
|
|
||||||
CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=y
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# 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
|
|
||||||
1
test_apps/sdkconfig.defaults.nvs
Normal file
1
test_apps/sdkconfig.defaults.nvs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CONFIG_RELAY_CHN_ENABLE_NVS=y
|
||||||
6
test_apps/sdkconfig.defaults.nvs_custom
Normal file
6
test_apps/sdkconfig.defaults.nvs_custom
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Partition configuration
|
||||||
|
CONFIG_PARTITION_TABLE_SINGLE_APP=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/part_nvs.csv"
|
||||||
|
|
||||||
|
CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=y
|
||||||
3
test_apps/sdkconfig.defaults.run_limit
Normal file
3
test_apps/sdkconfig.defaults.run_limit
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT=y
|
||||||
|
# Keep this as short as possible for tests
|
||||||
|
CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC=1
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# 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_NVS=y
|
|
||||||
CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=y
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# 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
|
|
||||||
1
test_apps/sdkconfig.defaults.tilt
Normal file
1
test_apps/sdkconfig.defaults.tilt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CONFIG_RELAY_CHN_ENABLE_TILTING=y
|
||||||
Reference in New Issue
Block a user