Compare commits
8 Commits
a587036093
...
v0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a06f58f42b | ||
| 349868a148 | |||
| 102918fdc3 | |||
| 03fcb344bb | |||
| 0917abba31 | |||
| 4ed116b1a9 | |||
| 63b0c31908 | |||
| 5e6e0c9a0e |
180
.gitignore
vendored
180
.gitignore
vendored
@@ -1,111 +1,107 @@
|
|||||||
.config
|
# ---> C
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Object files
|
||||||
*.o
|
*.o
|
||||||
*.pyc
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
|
||||||
# gtags
|
# Linker output
|
||||||
GTAGS
|
*.ilk
|
||||||
GRTAGS
|
*.map
|
||||||
GPATH
|
*.exp
|
||||||
|
|
||||||
# emacs
|
# Precompiled Headers
|
||||||
.dir-locals.el
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
# emacs temp file suffixes
|
# Libraries
|
||||||
*~
|
*.lib
|
||||||
.#*
|
*.a
|
||||||
\#*#
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
# eclipse setting
|
# Shared objects (inc. Windows DLLs)
|
||||||
.settings
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
# MacOS directory files
|
# Executables
|
||||||
.DS_Store
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
# cache dir
|
# Debug files
|
||||||
.cache/
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
|
||||||
# Doc build artifacts
|
# Kernel Module Compile Results
|
||||||
docs/_build/
|
*.mod*
|
||||||
docs/doxygen_sqlite3.db
|
*.cmd
|
||||||
|
.tmp_versions/
|
||||||
|
modules.order
|
||||||
|
Module.symvers
|
||||||
|
Mkfile.old
|
||||||
|
dkms.conf
|
||||||
|
|
||||||
# Downloaded font files
|
# ---> C++
|
||||||
docs/_static/DejaVuSans.ttf
|
# Prerequisites
|
||||||
docs/_static/NotoSansSC-Regular.otf
|
*.d
|
||||||
|
|
||||||
# Components Unit Test Apps files
|
# Compiled Object files
|
||||||
components/**/build/
|
*.slo
|
||||||
components/**/build_*_*/
|
*.lo
|
||||||
components/**/sdkconfig
|
*.o
|
||||||
components/**/sdkconfig.old
|
*.obj
|
||||||
|
|
||||||
# Example project files
|
# Precompiled Headers
|
||||||
examples/**/build/
|
*.gch
|
||||||
examples/**/build_*_*/
|
*.pch
|
||||||
examples/**/sdkconfig
|
|
||||||
examples/**/sdkconfig.old
|
|
||||||
|
|
||||||
# Unit test app files
|
# Compiled Dynamic libraries
|
||||||
tools/unit-test-app/build
|
*.so
|
||||||
tools/unit-test-app/build_*_*/
|
*.dylib
|
||||||
tools/unit-test-app/sdkconfig
|
*.dll
|
||||||
tools/unit-test-app/sdkconfig.old
|
|
||||||
|
|
||||||
# test application build files
|
# Fortran module files
|
||||||
tools/test_apps/**/build/
|
*.mod
|
||||||
tools/test_apps/**/build_*_*/
|
*.smod
|
||||||
tools/test_apps/**/sdkconfig
|
|
||||||
tools/test_apps/**/sdkconfig.old
|
|
||||||
|
|
||||||
TEST_LOGS/
|
# Compiled Static libraries
|
||||||
build_summary_*.xml
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
# gcov coverage reports
|
# Executables
|
||||||
*.gcda
|
*.exe
|
||||||
*.gcno
|
*.out
|
||||||
coverage.info
|
*.app
|
||||||
coverage_report/
|
|
||||||
|
|
||||||
test_multi_heap_host
|
# ---> CMake
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
CMakeUserPresets.json
|
||||||
|
|
||||||
# VS Code Settings
|
# Build directory
|
||||||
.vscode/
|
|
||||||
|
|
||||||
# VIM files
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
|
|
||||||
# Sublime Text files
|
|
||||||
*.sublime-project
|
|
||||||
*.sublime-workspace
|
|
||||||
|
|
||||||
# Clion IDE CMake build & config
|
|
||||||
.idea/
|
|
||||||
cmake-build-*/
|
|
||||||
|
|
||||||
# Results for the checking of the Python coding style and static analysis
|
|
||||||
.mypy_cache
|
|
||||||
flake8_output.txt
|
|
||||||
|
|
||||||
# ESP-IDF default build directory name
|
|
||||||
build
|
build
|
||||||
|
|
||||||
# lock files for examples and components
|
# unity-app directory
|
||||||
dependencies.lock
|
unity-app
|
||||||
|
|
||||||
# managed_components for examples
|
|
||||||
managed_components
|
|
||||||
|
|
||||||
# pytest log
|
|
||||||
pytest-embedded/
|
|
||||||
# legacy one
|
|
||||||
pytest_embedded_log/
|
|
||||||
list_job*.txt
|
|
||||||
size_info*.txt
|
|
||||||
XUNIT_RESULT*.xml
|
|
||||||
.manifest_sha
|
|
||||||
|
|
||||||
# clang config (for LSP)
|
|
||||||
.clangd
|
|
||||||
|
|
||||||
# Vale
|
|
||||||
.vale/styles/*
|
|
||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"relay_chn.h": "c"
|
"relay_chn.h": "c"
|
||||||
},
|
}
|
||||||
"idf.port": "/dev/ttyUSB0"
|
|
||||||
}
|
}
|
||||||
9
Kconfig
9
Kconfig
@@ -17,13 +17,4 @@ menu "Relay Channel Driver Configuration"
|
|||||||
help
|
help
|
||||||
Number of relay channels between 1 and 8.
|
Number of relay channels between 1 and 8.
|
||||||
|
|
||||||
config RELAY_CHN_ENABLE_TILTING
|
|
||||||
bool "Enable tilting on relay channels"
|
|
||||||
default n
|
|
||||||
help
|
|
||||||
This option controls enabling tilting on channels. Tilting makes
|
|
||||||
a channel move with a specific pattern moving with small steps
|
|
||||||
at a time. Tilting is specifically designed for controlling some
|
|
||||||
types of curtains that need to be adjusted to let enter specific
|
|
||||||
amount of day light.
|
|
||||||
endmenu
|
endmenu
|
||||||
39
README.md
39
README.md
@@ -11,15 +11,10 @@ An ESP-IDF component for controlling relay channels, specifically designed for d
|
|||||||
- Forward/Reverse direction control
|
- Forward/Reverse direction control
|
||||||
- Direction flipping capability
|
- Direction flipping capability
|
||||||
- State monitoring and reporting
|
- State monitoring and reporting
|
||||||
- Optional sensitivty adjustable tilting feature
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Each relay channel consists of 2 output relays controlled by 2 GPIO pins. The component provides APIs to control these relay pairs while ensuring safe operation, particularly for driving bipolar motors. To prevent mechanical strain on the motor, the component automatically manages direction changes with a configurable inertia delay, protecting it from abrupt reversals.
|
Each relay channel consists of 2 output relays controlled by 2 GPIO pins. The component provides APIs to control these relay pairs while ensuring safe operation, particularly for driving bipolar motors. It prevents short-circuits by automatically managing direction changes with configurable inertia timing.
|
||||||
|
|
||||||
It also provides an optional tilting interface per channel base. Tilting makes a channel move with a specific pattern moving with small steps at a time. Tilting is specifically designed for controlling some types of curtains that need to be adjusted to let enter specific amount of day light.
|
|
||||||
Since it operates on relays, the switching frequency is limited to 10Hz which complies with the most of the general purpose relays' requirements. The minimum frequency is 2Hz and the duty cycle is about 10% in all ranges.
|
|
||||||
The module also handles all the required timing between the movement transitions automatically to ensure reliable operation.
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
@@ -27,18 +22,16 @@ Configure the component through menuconfig under "Relay Channel Driver Configura
|
|||||||
|
|
||||||
- `CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS`: Time to wait before changing direction (200-1500ms, default: 800ms)
|
- `CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS`: Time to wait before changing direction (200-1500ms, default: 800ms)
|
||||||
- `CONFIG_RELAY_CHN_COUNT`: Number of relay channels (1-8, default: 1)
|
- `CONFIG_RELAY_CHN_COUNT`: Number of relay channels (1-8, default: 1)
|
||||||
- `CONFIG_RELAY_CHN_ENABLE_TILTING`: Enable tilting interface on all channels. (default: n)
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Just add it as a custom dependency to your project's `idf_component.yml`:
|
1. Copy the component to your project's components directory
|
||||||
|
2. Add dependency to your project's `idf_component.yml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
dependencies:
|
dependencies:
|
||||||
# Add as a custom component from git repository
|
|
||||||
relay_chn:
|
relay_chn:
|
||||||
git: https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn.git
|
version: "^0.1.0"
|
||||||
version: '>=0.4.0'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -84,30 +77,6 @@ char *state_str = relay_chn_get_state_str(0);
|
|||||||
relay_chn_direction_t direction = relay_chn_get_direction(0);
|
relay_chn_direction_t direction = relay_chn_get_direction(0);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Tilting Interface (if enabled)
|
|
||||||
|
|
||||||
```c
|
|
||||||
// Assuming CONFIG_RELAY_CHN_ENABLE_TILTING is enabled
|
|
||||||
|
|
||||||
// Start tilting automatically (channel 0)
|
|
||||||
relay_chn_tilt_auto(0);
|
|
||||||
|
|
||||||
// Tilt forward (channel 0)
|
|
||||||
relay_chn_tilt_forward(0);
|
|
||||||
|
|
||||||
// Tilt reverse (channel 0)
|
|
||||||
relay_chn_tilt_reverse(0);
|
|
||||||
|
|
||||||
// Stop tilting (channel 0)
|
|
||||||
relay_chn_tilt_stop(0);
|
|
||||||
|
|
||||||
// Set tilting sensitivity (channel 0, sensitivity as percentage)
|
|
||||||
relay_chn_tilt_sensitivity_set(0, 90);
|
|
||||||
|
|
||||||
// Get tilting sensitivity (channel 0, sensitivty as percentage)
|
|
||||||
uint8_t sensitivity = relay_chn_tilt_sensitivity_get(0);
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT License](LICENSE) - Copyright (c) 2025 kozmotronik.
|
[MIT License](LICENSE) - Copyright (c) 2025 kozmotronik.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
name: relay_chn
|
name: relay_chn
|
||||||
version: "0.4.0"
|
version: 0.1.0
|
||||||
description: "Custom component for relay channel control"
|
description: Custom component for relay channel control
|
||||||
license: "MIT"
|
dependencies:
|
||||||
url: "https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn_component"
|
idf:
|
||||||
repository: "https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn_component.git"
|
version: ">=4.0"
|
||||||
|
# TODO: Repo ve belgelendirme bağlantılarını ekle.
|
||||||
@@ -14,8 +14,7 @@
|
|||||||
* One relay channel consists of 2 output relays, hence 2 GPIO pins are required for each relay channel.
|
* One relay channel consists of 2 output relays, hence 2 GPIO pins are required for each relay channel.
|
||||||
* This module provides an API to control the relay channels, specifically to drive bipolar motors.
|
* This module provides an API to control the relay channels, specifically to drive bipolar motors.
|
||||||
* It also provides APIs to control the direction of the relay channel, bipolar motors in mind.
|
* It also provides APIs to control the direction of the relay channel, bipolar motors in mind.
|
||||||
* To prevent mechanical strain on the motor, the component automatically manages direction changes
|
* The module also automatically manages the direction change inertia to prevent short-circuiting the motor.
|
||||||
* with a configurable inertia delay, protecting it from abrupt reversals.
|
|
||||||
* The STOP command overrides any other command and clears the pending command if any.
|
* The STOP command overrides any other command and clears the pending command if any.
|
||||||
*
|
*
|
||||||
* The module internally uses a custom esp event loop to handle relay commands serially to ensure
|
* The module internally uses a custom esp event loop to handle relay commands serially to ensure
|
||||||
@@ -49,17 +48,12 @@ typedef enum relay_chn_direction_enum relay_chn_direction_t;
|
|||||||
* @brief Enums that represent the state of a relay channel.
|
* @brief Enums that represent the state of a relay channel.
|
||||||
*/
|
*/
|
||||||
enum relay_chn_state_enum {
|
enum relay_chn_state_enum {
|
||||||
RELAY_CHN_STATE_UNDEFINED, ///< The relay channel state is undefined.
|
|
||||||
RELAY_CHN_STATE_FREE, ///< The relay channel is free to run or execute commands.
|
RELAY_CHN_STATE_FREE, ///< The relay channel is free to run or execute commands.
|
||||||
RELAY_CHN_STATE_STOPPED, ///< The relay channel is stopped and not running.
|
RELAY_CHN_STATE_STOPPED, ///< The relay channel is stopped and not running.
|
||||||
RELAY_CHN_STATE_FORWARD, ///< The relay channel is running in the forward direction.
|
RELAY_CHN_STATE_FORWARD, ///< The relay channel is running in the forward direction.
|
||||||
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
|
|
||||||
RELAY_CHN_STATE_TILT_FORWARD, ///< The relay channel is tilting for forward.
|
|
||||||
RELAY_CHN_STATE_TILT_REVERSE, ///< The relay channel is tilting for reverse.
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,13 +91,6 @@ typedef void (*relay_chn_state_listener_t)(uint8_t chn_id, relay_chn_state_t old
|
|||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count);
|
esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Destroy the relay channels and free resources.
|
|
||||||
*
|
|
||||||
* This function cleans up the relay channels and releases any resources allocated during their creation.
|
|
||||||
*/
|
|
||||||
void relay_chn_destroy(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register a channel state change listener.
|
* @brief Register a channel state change listener.
|
||||||
*
|
*
|
||||||
@@ -211,77 +198,6 @@ 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 CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enables automatic tilting for the specified relay channel.
|
|
||||||
*
|
|
||||||
* This function enables automatic tilting mode for the given relay channel. The channel will automatically
|
|
||||||
* switch between forward and reverse tilting based on some internal sensing mechanism (not detailed here).
|
|
||||||
* Requires appropriate hardware support and configuration.
|
|
||||||
*
|
|
||||||
* @param chn_id The ID of the relay channel to enable automatic tilting.
|
|
||||||
*/
|
|
||||||
void relay_chn_tilt_auto(uint8_t chn_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Tilts the specified relay channel forward.
|
|
||||||
*
|
|
||||||
* This function initiates a forward tilting action for the specified relay channel. This is a manual tilting
|
|
||||||
* operation, unlike `relay_chn_tilt_auto()`.
|
|
||||||
*
|
|
||||||
* @param chn_id The ID of the relay channel to tilt forward.
|
|
||||||
*/
|
|
||||||
void relay_chn_tilt_forward(uint8_t chn_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Tilts the specified relay channel reverse.
|
|
||||||
*
|
|
||||||
* This function initiates a reverse tilting action for the specified relay channel. This is a manual tilting
|
|
||||||
* operation, unlike `relay_chn_tilt_auto()`.
|
|
||||||
*
|
|
||||||
* @param chn_id The ID of the relay channel to tilt reverse.
|
|
||||||
*/
|
|
||||||
void relay_chn_tilt_reverse(uint8_t chn_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops the tilting action on the specified relay channel.
|
|
||||||
*
|
|
||||||
* This function stops any ongoing tilting action (automatic or manual) on the specified relay channel.
|
|
||||||
*
|
|
||||||
* @param chn_id The ID of the relay channel to stop tilting.
|
|
||||||
*/
|
|
||||||
void relay_chn_tilt_stop(uint8_t chn_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets the tilting sensitivity for the specified relay channel.
|
|
||||||
*
|
|
||||||
* This function sets the sensitivity for the automatic tilting mechanism. A higher sensitivity value
|
|
||||||
* typically means the channel will react more readily to tilting events.
|
|
||||||
*
|
|
||||||
* @param chn_id The ID of the relay channel to set the sensitivity for.
|
|
||||||
* @param sensitivity The sensitivity in percentage: 0 - 100%.
|
|
||||||
*/
|
|
||||||
void relay_chn_tilt_sensitivity_set(uint8_t chn_id, uint8_t sensitivity);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the tilting sensitivity for the specified relay channel.
|
|
||||||
*
|
|
||||||
* This function retrieves the currently set sensitivity for the specified relay channel's automatic
|
|
||||||
* tilting mechanism.
|
|
||||||
*
|
|
||||||
* @param chn_id The ID of the relay channel to get the sensitivity for.
|
|
||||||
* @param sensitivity The pointer to the memory in to which the sensitivity values will be copied.
|
|
||||||
* @param length The length of the sensitvity memory.
|
|
||||||
* @return
|
|
||||||
* - ESP_OK: Success
|
|
||||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
|
||||||
*/
|
|
||||||
esp_err_t relay_chn_tilt_sensitivity_get(uint8_t chn_id, uint8_t *sensitivity, size_t length);
|
|
||||||
|
|
||||||
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
937
src/relay_chn.c
937
src/relay_chn.c
File diff suppressed because it is too large
Load Diff
8
test/CMakeLists.txt
Normal file
8
test/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||||
|
# in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
|
||||||
|
"../../relay_chn")
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(relay_chn_test)
|
||||||
3
test/main/CMakeLists.txt
Normal file
3
test/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
idf_component_register(SRCS_DIRS "."
|
||||||
|
PRIV_INCLUDE_DIRS "."
|
||||||
|
PRIV_REQUIRES unity test_utils relay_chn)
|
||||||
95
test/main/test_relay_chn.c
Normal file
95
test/main/test_relay_chn.c
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "unity_test_utils.h"
|
||||||
|
#include "relay_chn.h"
|
||||||
|
|
||||||
|
|
||||||
|
const gpio_num_t gpio_map[] = {GPIO_NUM_4, GPIO_NUM_5, GPIO_NUM_18, GPIO_NUM_19};
|
||||||
|
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||||
|
const uint8_t relay_chn_count = gpio_count / 2;
|
||||||
|
|
||||||
|
TEST_CASE("relay chn inits correctly", "[relay_chn]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Relay channels run forward and update state", "[relay_chn][forward]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||||
|
// Test forward run on all channels
|
||||||
|
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
|
relay_chn_run_forward(i); // Run the channel forward
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
||||||
|
relay_chn_stop(i); // Stop the channel
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
|
|
||||||
|
relay_chn_flip_direction(i); // Flip the direction
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(i));
|
||||||
|
relay_chn_run_forward(i); // Run the channel forward
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
||||||
|
relay_chn_stop(i); // Stop the channel
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Relay channels run reverse and update state", "[relay_chn][reverse]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||||
|
// Test reverse run on all channels
|
||||||
|
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
|
relay_chn_run_reverse(i); // Run the channel reverse
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
||||||
|
relay_chn_stop(i); // Stop the channel
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
|
|
||||||
|
relay_chn_flip_direction(i); // Flip the direction
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(i));
|
||||||
|
relay_chn_run_reverse(i); // Run the channel forward
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
||||||
|
relay_chn_stop(i); // Stop the channel
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_channels_state_unchanged(void)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Relay channels do not change state for invalid channel", "[relay_chn][invalid]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||||
|
// Test invalid channel run
|
||||||
|
relay_chn_run_forward(relay_chn_count + 1); // Run the channel forward
|
||||||
|
check_channels_state_unchanged();
|
||||||
|
relay_chn_run_reverse(relay_chn_count + 1); // Run the channel reverse
|
||||||
|
check_channels_state_unchanged();
|
||||||
|
relay_chn_stop(relay_chn_count + 1); // Stop the channel
|
||||||
|
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(relay_chn_count + 1));
|
||||||
|
check_channels_state_unchanged();
|
||||||
|
relay_chn_flip_direction(relay_chn_count + 1); // Flip the direction
|
||||||
|
check_channels_state_unchanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
// Run before each test
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
// Run after each test
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test app entry point
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
// Run the Unity tests menu
|
||||||
|
unity_run_menu();
|
||||||
|
}
|
||||||
5
test/sdkconfig.defaults
Normal file
5
test/sdkconfig.defaults
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# For IDF 5.0
|
||||||
|
CONFIG_ESP_TASK_WDT_EN=n
|
||||||
|
|
||||||
|
# For IDF4.4
|
||||||
|
CONFIG_ESP_TASK_WDT=n
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# This is the project CMakeLists.txt file for the test subproject
|
|
||||||
cmake_minimum_required(VERSION 3.5)
|
|
||||||
|
|
||||||
# Define component search paths
|
|
||||||
# IMPORTANT: We should tell to the ESP-IDF
|
|
||||||
# where it can find relay_chn component.
|
|
||||||
# We add the 'relay_chn' root directory to the EXTRA_COMPONENT_DIRS by specifying: "../"
|
|
||||||
set(EXTRA_COMPONENT_DIRS "../")
|
|
||||||
|
|
||||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
|
||||||
set(COMPONENTS main)
|
|
||||||
|
|
||||||
# Include ESP-IDF project build system
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
|
||||||
|
|
||||||
# Define the name of this project
|
|
||||||
project(relay_chn_test)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
idf_component_register(SRCS "test_relay_chn.c"
|
|
||||||
INCLUDE_DIRS "."
|
|
||||||
REQUIRES unity relay_chn)
|
|
||||||
@@ -1,663 +0,0 @@
|
|||||||
#include "driver/gpio.h"
|
|
||||||
#include "unity.h"
|
|
||||||
#include "unity_test_utils.h"
|
|
||||||
#include "relay_chn.h" // Main header file for the relay_chn component
|
|
||||||
#include <esp_log.h>
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
#include "sdkconfig.h" // For accessing CONFIG_* values
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
const char *TAG = "RELAY_CHN_TEST";
|
|
||||||
|
|
||||||
// Test GPIOs and channel IDs
|
|
||||||
// Please ensure these GPIOs are correct and suitable for your board.
|
|
||||||
// Two channels (4 GPIOs) are used as an example.
|
|
||||||
const gpio_num_t gpio_map[] = {GPIO_NUM_4, GPIO_NUM_5, GPIO_NUM_18, GPIO_NUM_19};
|
|
||||||
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
|
||||||
// Assuming 2 GPIOs are used per channel
|
|
||||||
const uint8_t relay_chn_count = gpio_count / 2;
|
|
||||||
|
|
||||||
const uint32_t opposite_inertia_ms = CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS;
|
|
||||||
|
|
||||||
// Tolerant delay margin to ensure operations complete, especially after inertia.
|
|
||||||
const uint32_t test_delay_margin_ms = 50;
|
|
||||||
|
|
||||||
static bool g_is_component_initialized = false;
|
|
||||||
|
|
||||||
// --- Test Setup/Teardown Functions ---
|
|
||||||
void setUp(void) {
|
|
||||||
// Reset state before each test. Initialization is now done inside each test case
|
|
||||||
// to allow for testing of initialization failures.
|
|
||||||
g_is_component_initialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tearDown(void) {
|
|
||||||
// Conditionally destroy the component to avoid crashing if creation failed.
|
|
||||||
if (g_is_component_initialized) {
|
|
||||||
relay_chn_destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// --- Initialization Tests ---
|
|
||||||
|
|
||||||
TEST_CASE("relay_chn_create handles invalid arguments", "[relay_chn][init]")
|
|
||||||
{
|
|
||||||
// 1. Test with NULL gpio_map
|
|
||||||
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)
|
|
||||||
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, 0));
|
|
||||||
|
|
||||||
// 3. Test with invalid GPIO numbers (GPIO_NUM_MAX is an invalid GPIO for output)
|
|
||||||
gpio_num_t invalid_gpio_map[] = {GPIO_NUM_4, GPIO_NUM_MAX, GPIO_NUM_18, GPIO_NUM_19};
|
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(invalid_gpio_map, gpio_count));
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Basic Functionality Tests ---
|
|
||||||
|
|
||||||
// TEST_CASE: Test that relay channels initialize correctly to RELAY_CHN_STATE_FREE
|
|
||||||
TEST_CASE("Relay channels initialize correctly to FREE state", "[relay_chn]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
|
||||||
relay_chn_run_forward(invalid_id); // relay_chn_run_forward returns void
|
|
||||||
// Short delay for state to update
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
relay_chn_run_forward(i); // relay_chn_run_forward returns void
|
|
||||||
// Short delay for state to update
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
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("Run reverse does nothing if channel id is invalid", "[relay_chn]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Verify that no valid channels were affected
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
|
||||||
// Call run_reverse with an invalid ID
|
|
||||||
relay_chn_run_reverse(invalid_id);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
relay_chn_run_reverse(i); // relay_chn_run_reverse returns void
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST_CASE: Test that relays stop and transition to RELAY_CHN_STATE_FREE
|
|
||||||
// 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]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
// First, run forward to test stopping and transitioning to FREE state
|
|
||||||
relay_chn_run_forward(i); // relay_chn_run_forward returns void
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
|
||||||
|
|
||||||
// Now, issue the stop command
|
|
||||||
relay_chn_stop(i); // relay_chn_stop returns void
|
|
||||||
// Immediately after stop, state should be STOPPED
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
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_FREE
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST_CASE: Get state should return UNDEFINED when id is not valid
|
|
||||||
TEST_CASE("Get state returns UNDEFINED when id is invalid", "[relay_chn]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_UNDEFINED, relay_chn_get_state(invalid_id));
|
|
||||||
}
|
|
||||||
// Test for running states also
|
|
||||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
|
||||||
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 returns UNKNOWN when id is invalid", "[relay_chn]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
|
||||||
TEST_ASSERT_EQUAL_STRING("UNKNOWN", relay_chn_get_state_str(invalid_id));
|
|
||||||
}
|
|
||||||
// Test for running states also
|
|
||||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
|
||||||
int invalid_id = relay_chn_count * 2 + i;
|
|
||||||
TEST_ASSERT_EQUAL_STRING("UNKNOWN", relay_chn_get_state_str(invalid_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST_CASE: Test independent operation of multiple relay channels
|
|
||||||
TEST_CASE("Multiple channels can operate independently", "[relay_chn]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
if (relay_chn_count >= 2) {
|
|
||||||
// Start Channel 0 in forward direction
|
|
||||||
relay_chn_run_forward(0); // relay_chn_run_forward returns void
|
|
||||||
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_FREE, relay_chn_get_state(1)); // Other channel should not be affected
|
|
||||||
|
|
||||||
// Start Channel 1 in reverse direction
|
|
||||||
relay_chn_run_reverse(1); // relay_chn_run_reverse returns void
|
|
||||||
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_REVERSE, relay_chn_get_state(1));
|
|
||||||
|
|
||||||
// Stop Channel 0 and wait for it to become FREE
|
|
||||||
relay_chn_stop(0); // relay_chn_stop returns void
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(0));
|
|
||||||
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
|
|
||||||
relay_chn_stop(1); // relay_chn_stop returns void
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(0));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(1));
|
|
||||||
} else {
|
|
||||||
ESP_LOGW("TEST", "Skipping 'Multiple channels can operate independently' test: Not enough channels available.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ### Inertia and State Transition Tests
|
|
||||||
|
|
||||||
// This section specifically targets the inertia periods and complex state transitions as per the component's logic.
|
|
||||||
|
|
||||||
// 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
|
|
||||||
TEST_CASE("Forward to Reverse transition with opposite inertia", "[relay_chn][inertia]") {
|
|
||||||
uint8_t ch = 0; // Channel to test
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// 1. Start in forward direction
|
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
|
||||||
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));
|
|
||||||
|
|
||||||
// 2. Issue reverse command
|
|
||||||
relay_chn_run_reverse(ch); // relay_chn_run_reverse returns void
|
|
||||||
// Immediately after the command, the motor should be stopped
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// Wait for the inertia period (after which the reverse command will be dispatched)
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch)); // Should now be in reverse state
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
TEST_CASE("Reverse to Forward transition with opposite inertia", "[relay_chn][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// 1. Start in reverse direction
|
|
||||||
relay_chn_run_reverse(ch); // relay_chn_run_reverse returns void
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// 2. Issue forward command
|
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// Wait for inertia
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
TEST_CASE("Running in same direction does not incur inertia", "[relay_chn][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// 1. Start in forward direction
|
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// 2. Issue the same forward command again
|
|
||||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
|
||||||
// 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.
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST_CASE: Test transition from FREE state to running (no inertia expected)
|
|
||||||
// Scenario: RELAY_CHN_STATE_FREE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
|
||||||
TEST_CASE("FREE to Running transition without inertia", "[relay_chn][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// setUp() should have already brought the channel to FREE state
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 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;
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
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_FREE, 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;
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
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;
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
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_FREE, 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_FREE, 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]") {
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ### Tilt Functionality Tests (Conditional)
|
|
||||||
|
|
||||||
// This section will only be compiled if **`CONFIG_RELAY_CHN_ENABLE_TILTING`** is defined as **`1`** in `sdkconfig`.
|
|
||||||
|
|
||||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
|
||||||
|
|
||||||
#define RELAY_CHN_CMD_FORWARD 1
|
|
||||||
#define RELAY_CHN_CMD_REVERSE 2
|
|
||||||
|
|
||||||
// Helper function to prepare channel for tilt tests
|
|
||||||
void prepare_channel_for_tilt(uint8_t chn_id, int initial_cmd) {
|
|
||||||
// Ensure the channel has had a 'last_run_cmd'
|
|
||||||
if (initial_cmd == RELAY_CHN_CMD_FORWARD) {
|
|
||||||
relay_chn_run_forward(chn_id);
|
|
||||||
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
|
||||||
relay_chn_run_reverse(chn_id);
|
|
||||||
}
|
|
||||||
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
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(chn_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
TEST_CASE("Run Forward to Tilt Forward transition with inertia", "[relay_chn][tilt][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd
|
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
|
||||||
|
|
||||||
// 1. Start in forward direction
|
|
||||||
relay_chn_run_forward(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// 2. Issue tilt forward command
|
|
||||||
relay_chn_tilt_forward(ch);
|
|
||||||
// After tilt command, it should immediately stop and then trigger inertia.
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// Wait for the inertia period (after which the tilt command will be dispatched)
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
TEST_CASE("Run Reverse to Tilt Reverse transition with inertia", "[relay_chn][tilt][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Prepare channel by running reverse first to set last_run_cmd
|
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_REVERSE);
|
|
||||||
|
|
||||||
// 1. Start in reverse direction
|
|
||||||
relay_chn_run_reverse(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// 2. Issue tilt reverse command
|
|
||||||
relay_chn_tilt_reverse(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST_CASE: Test transition from FREE state to tilt forward (now with preparation)
|
|
||||||
// Scenario: RELAY_CHN_STATE_FREE -> (prepare) -> RELAY_CHN_STATE_FREE -> (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]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd
|
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(ch)); // Ensure we are back to FREE
|
|
||||||
|
|
||||||
// Issue tilt forward command
|
|
||||||
relay_chn_tilt_forward(ch);
|
|
||||||
// From FREE state, tilt command should still incur the inertia due to the internal timer logic
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST_CASE: Test transition from FREE state to tilt reverse (now with preparation)
|
|
||||||
// Scenario: RELAY_CHN_STATE_FREE -> (prepare) -> RELAY_CHN_STATE_FREE -> (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]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Prepare channel by running reverse first to set last_run_cmd
|
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_REVERSE);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(ch)); // Ensure we are back to FREE
|
|
||||||
|
|
||||||
// Issue tilt reverse command
|
|
||||||
relay_chn_tilt_reverse(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
TEST_CASE("Tilt Forward to Run Forward transition with inertia", "[relay_chn][tilt][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
|
||||||
relay_chn_tilt_forward(ch); // Go to tilt state
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// 2. Issue run forward command
|
|
||||||
relay_chn_run_forward(ch);
|
|
||||||
// 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));
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
TEST_CASE("Tilt Reverse to Run Reverse transition with inertia", "[relay_chn][tilt][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Prepare channel by running reverse first to set last_run_cmd, then tilt
|
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_REVERSE);
|
|
||||||
relay_chn_tilt_reverse(ch); // Go to tilt state
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// 2. Issue run reverse command
|
|
||||||
relay_chn_run_reverse(ch);
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state(ch));
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
TEST_CASE("Tilt Forward to Run Reverse transition without inertia", "[relay_chn][tilt][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
|
||||||
relay_chn_tilt_forward(ch); // Go to tilt state
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// 2. Issue run reverse command (opposite direction)
|
|
||||||
relay_chn_run_reverse(ch);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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_FREE
|
|
||||||
TEST_CASE("Tilt to Stop transition without immediate inertia for stop", "[relay_chn][tilt][inertia]") {
|
|
||||||
uint8_t ch = 0;
|
|
||||||
|
|
||||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
|
||||||
g_is_component_initialized = true;
|
|
||||||
|
|
||||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
|
||||||
prepare_channel_for_tilt(ch, RELAY_CHN_CMD_FORWARD);
|
|
||||||
relay_chn_tilt_forward(ch); // Go to tilt state
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state(ch));
|
|
||||||
|
|
||||||
// 2. Issue stop command
|
|
||||||
relay_chn_stop(ch);
|
|
||||||
// Stop command should apply immediately, setting state to FREE since last state was tilt.
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
|
||||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // CONFIG_RELAY_CHN_ENABLE_TILTING == 0
|
|
||||||
// If tilt functionality is disabled, these tests are skipped.
|
|
||||||
// A dummy test case is added to indicate this in the test output.
|
|
||||||
TEST_CASE("Tilt functionality is disabled, skipping tilt tests", "[relay_chn][tilt_disabled]") {
|
|
||||||
TEST_ASSERT_TRUE(true); // Just to ensure at least one test passes for visibility
|
|
||||||
}
|
|
||||||
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
||||||
|
|
||||||
|
|
||||||
// ### `app_main` Function
|
|
||||||
|
|
||||||
// --- app_main function ---
|
|
||||||
void app_main(void) {
|
|
||||||
// Run the Unity test runner
|
|
||||||
unity_run_all_tests();
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "============================== END OF TESTS ==============================");
|
|
||||||
|
|
||||||
// After tests complete, instead of restarting, the device will halt.
|
|
||||||
while (1) {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000)); // Wait with low power consumption
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1387
test_apps/sdkconfig
1387
test_apps/sdkconfig
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
|||||||
# Relay Channel Driver Default Configuration for Testing
|
|
||||||
CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200
|
|
||||||
CONFIG_RELAY_CHN_COUNT=2
|
|
||||||
CONFIG_RELAY_CHN_ENABLE_TILTING=y
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user