Compare commits
25 Commits
9ff243c673
...
0.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ebe1c791e | |||
|
bacbe03e12
|
|||
|
be09cb883a
|
|||
|
925fd5de74
|
|||
|
2e3e92bb63
|
|||
|
c4482b8d49
|
|||
| 41c292cc89 | |||
|
ed5b86e863
|
|||
| a1c66d51c7 | |||
| 421dea7d69 | |||
| 99d753238b | |||
| 7afe6144bd | |||
| 4f39308f13 | |||
| fb425edc4b | |||
| 805df016fe | |||
| f230477cad | |||
| e19bd09389 | |||
| 11786b7a06 | |||
| 7c18ddcc04 | |||
| e8303a9418 | |||
| 496755ed56 | |||
| 5fe76bb738 | |||
| 46dd0db939 | |||
| 46f7c28829 | |||
| 0e68c1f627 |
180
.gitignore
vendored
180
.gitignore
vendored
@@ -1,107 +1,111 @@
|
||||
# ---> C
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
.config
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
*.pyc
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
# gtags
|
||||
GTAGS
|
||||
GRTAGS
|
||||
GPATH
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
# emacs
|
||||
.dir-locals.el
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
# emacs temp file suffixes
|
||||
*~
|
||||
.#*
|
||||
\#*#
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
# eclipse setting
|
||||
.settings
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
# MacOS directory files
|
||||
.DS_Store
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
# cache dir
|
||||
.cache/
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
# Doc build artifacts
|
||||
docs/_build/
|
||||
docs/doxygen_sqlite3.db
|
||||
|
||||
# ---> C++
|
||||
# Prerequisites
|
||||
*.d
|
||||
# Downloaded font files
|
||||
docs/_static/DejaVuSans.ttf
|
||||
docs/_static/NotoSansSC-Regular.otf
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
# Components Unit Test Apps files
|
||||
components/**/build/
|
||||
components/**/build_*_*/
|
||||
components/**/sdkconfig
|
||||
components/**/sdkconfig.old
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
# Example project files
|
||||
examples/**/build/
|
||||
examples/**/build_*_*/
|
||||
examples/**/sdkconfig
|
||||
examples/**/sdkconfig.old
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
# Unit test app files
|
||||
tools/unit-test-app/build
|
||||
tools/unit-test-app/build_*_*/
|
||||
tools/unit-test-app/sdkconfig
|
||||
tools/unit-test-app/sdkconfig.old
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
# test application build files
|
||||
tools/test_apps/**/build/
|
||||
tools/test_apps/**/build_*_*/
|
||||
tools/test_apps/**/sdkconfig
|
||||
tools/test_apps/**/sdkconfig.old
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
TEST_LOGS/
|
||||
build_summary_*.xml
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
# gcov coverage reports
|
||||
*.gcda
|
||||
*.gcno
|
||||
coverage.info
|
||||
coverage_report/
|
||||
|
||||
# ---> CMake
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
CMakeUserPresets.json
|
||||
test_multi_heap_host
|
||||
|
||||
# Build directory
|
||||
# VS Code Settings
|
||||
.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
|
||||
|
||||
# unity-app directory
|
||||
unity-app
|
||||
# lock files for examples and components
|
||||
dependencies.lock
|
||||
|
||||
# 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,5 +1,6 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"relay_chn.h": "c"
|
||||
}
|
||||
},
|
||||
"idf.port": "/dev/ttyUSB0"
|
||||
}
|
||||
11
README.md
11
README.md
@@ -15,7 +15,7 @@ An ESP-IDF component for controlling relay channels, specifically designed for d
|
||||
|
||||
## 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. It prevents short-circuits by automatically managing direction changes with configurable inertia timing.
|
||||
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.
|
||||
|
||||
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.
|
||||
@@ -31,13 +31,14 @@ Configure the component through menuconfig under "Relay Channel Driver Configura
|
||||
|
||||
## Installation
|
||||
|
||||
1. Copy the component to your project's components directory
|
||||
2. Add dependency to your project's `idf_component.yml`:
|
||||
Just add it as a custom dependency to your project's `idf_component.yml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
# Add as a custom component from git repository
|
||||
relay_chn:
|
||||
version: "^0.1.0"
|
||||
git: https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn.git
|
||||
version: '>=0.4.0'
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -105,7 +106,7 @@ 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
|
||||
|
||||
|
||||
13
app_test/CMakeLists.txt
Normal file
13
app_test/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
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' directory to the COMPONENT_DIRS by specifying: ../relay_chn
|
||||
set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../relay_chn")
|
||||
|
||||
# Include ESP-IDF project build system
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# Define the name of this project
|
||||
project(relay_chn_app_test)
|
||||
3
app_test/main/CMakeLists.txt
Normal file
3
app_test/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "test_relay_chn.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES unity relay_chn)
|
||||
443
app_test/main/test_relay_chn.c
Normal file
443
app_test/main/test_relay_chn.c
Normal file
@@ -0,0 +1,443 @@
|
||||
#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
|
||||
|
||||
// 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;
|
||||
|
||||
// Retrieve inertia value from SDKconfig
|
||||
#ifndef CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS
|
||||
#define CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS 500 // Default if not defined in SDKconfig
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
// --- Test Setup/Teardown Functions ---
|
||||
void setUp(void) {
|
||||
ESP_LOGI("TEST_SETUP", "Running setUp for relay_chn tests.");
|
||||
// Re-create the component before each test. relay_chn_create returns esp_err_t.
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
// Ensure all relays are stopped at the beginning, and transition to FREE state
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
relay_chn_stop(i); // relay_chn_stop returns void
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); // Wait for FREE state
|
||||
}
|
||||
ESP_LOGI("TEST_SETUP", "All channels initialized to RELAY_CHN_STATE_FREE.");
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
ESP_LOGI("TEST_TEARDOWN", "Running tearDown for relay_chn tests.");
|
||||
// Stop all relays after each test, and transition to FREE state
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
relay_chn_stop(i); // relay_chn_stop returns void
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); // Wait for FREE state
|
||||
}
|
||||
ESP_LOGI("TEST_TEARDOWN", "All channels returned to RELAY_CHN_STATE_FREE.");
|
||||
}
|
||||
|
||||
// --- Basic Functionality Tests ---
|
||||
|
||||
// TEST_CASE 1: Test that relay channels initialize correctly to RELAY_CHN_STATE_FREE
|
||||
TEST_CASE("Relay channels initialize correctly to FREE state", "[relay_chn]") {
|
||||
ESP_LOGI("TEST", "Running test: Relay channels initialize correctly to FREE state");
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
// TEST_CASE 2: Test that relays run in the forward direction and update their state
|
||||
TEST_CASE("Relay channels run forward and update state", "[relay_chn]") {
|
||||
ESP_LOGI("TEST", "Running test: Relay channels run forward and update state");
|
||||
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 3: Test that relays run in the reverse direction and update their state
|
||||
TEST_CASE("Relay channels run reverse and update state", "[relay_chn]") {
|
||||
ESP_LOGI("TEST", "Running test: Relay channels run reverse and update state");
|
||||
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 4: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Relay channels stop and update to FREE state");
|
||||
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 5: Test function calls with invalid channel IDs
|
||||
// TEST_CASE("Invalid channel ID handling", "[relay_chn]") {
|
||||
// ESP_LOGI("TEST", "Running test: Invalid channel ID handling");
|
||||
// uint8_t invalid_channel_id = relay_chn_count + 1; // An ID that is out of bounds
|
||||
|
||||
// // These calls are expected to return ESP_ERR_INVALID_ARG, so TEST_ASSERT_EQUAL is appropriate.
|
||||
// TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_run_forward(invalid_channel_id));
|
||||
// TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_run_reverse(invalid_channel_id));
|
||||
// TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_stop(invalid_channel_id));
|
||||
|
||||
// // Test tilt commands only if tilt functionality is enabled
|
||||
// #if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
||||
// TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_tilt_forward(invalid_channel_id));
|
||||
// TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_tilt_reverse(invalid_channel_id));
|
||||
// #endif
|
||||
|
||||
// TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_get_state(invalid_channel_id));
|
||||
// }
|
||||
|
||||
// TEST_CASE 6: Test independent operation of multiple relay channels
|
||||
TEST_CASE("Multiple channels can operate independently", "[relay_chn]") {
|
||||
ESP_LOGI("TEST", "Running test: Multiple channels can operate independently");
|
||||
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 7: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Forward to Reverse transition with opposite inertia");
|
||||
uint8_t ch = 0; // Channel to test
|
||||
|
||||
// 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 8: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Reverse to Forward transition with opposite inertia");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 9: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Running in same direction does not incur inertia");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 10: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: FREE to Running transition without inertia");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
|
||||
// ### 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 11: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Run Forward to Tilt Forward transition with inertia");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 12: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Run Reverse to Tilt Reverse transition with inertia");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 13: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: FREE to Tilt Forward transition with inertia (prepared)");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 14: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: FREE to Tilt Reverse transition with inertia (prepared)");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 15: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Tilt Forward to Run Forward transition with inertia");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 16: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Tilt Reverse to Run Reverse transition with inertia");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 17: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Tilt Forward to Run Reverse transition without inertia");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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 18: 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]") {
|
||||
ESP_LOGI("TEST", "Running test: Tilt to Stop transition without immediate inertia for stop");
|
||||
uint8_t ch = 0;
|
||||
|
||||
// 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]") {
|
||||
ESP_LOGI("TEST", "Tilt functionality is disabled (CONFIG_RELAY_CHN_ENABLE_TILTING is 0). Skipping tilt tests.");
|
||||
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) {
|
||||
ESP_LOGI("APP_MAIN", "Starting relay_chn unit tests...");
|
||||
|
||||
// Run the Unity test runner
|
||||
unity_run_all_tests();
|
||||
|
||||
// After tests complete, instead of restarting, the device will halt.
|
||||
ESP_LOGI("APP_MAIN", "All relay_chn tests completed. Device halted.");
|
||||
while (1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // Wait with low power consumption
|
||||
}
|
||||
}
|
||||
2033
app_test/sdkconfig
Normal file
2033
app_test/sdkconfig
Normal file
File diff suppressed because it is too large
Load Diff
2033
app_test/sdkconfig.old
Normal file
2033
app_test/sdkconfig.old
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
name: relay_chn
|
||||
version: 0.1.0
|
||||
description: Custom component for relay channel control
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=4.0"
|
||||
# TODO: Repo ve belgelendirme bağlantılarını ekle.
|
||||
6
relay_chn/idf_component.yml
Normal file
6
relay_chn/idf_component.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
name: relay_chn
|
||||
version: "0.4.0"
|
||||
description: "Custom component for relay channel control"
|
||||
license: "MIT"
|
||||
url: "https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn_component"
|
||||
repository: "https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn_component.git"
|
||||
@@ -14,7 +14,8 @@
|
||||
* 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.
|
||||
* It also provides APIs to control the direction of the relay channel, bipolar motors in mind.
|
||||
* The module also automatically manages the direction change inertia to prevent short-circuiting the motor.
|
||||
* To prevent mechanical strain on the motor, the component automatically manages direction changes
|
||||
* with a configurable inertia delay, protecting it from abrupt reversals.
|
||||
* The STOP command overrides any other command and clears the pending command if any.
|
||||
*
|
||||
* The module internally uses a custom esp event loop to handle relay commands serially to ensure
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_task.h"
|
||||
#include "driver/gpio.h"
|
||||
@@ -110,9 +111,13 @@ typedef struct relay_chn_type {
|
||||
* 100 / (RELAY_CHN_TILT_RUN_MAX_MS - RELAY_CHN_TILT_RUN_MIN_MS) )
|
||||
/// @}
|
||||
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(RELAY_CHN_TILT_CMD_EVENT_BASE);
|
||||
|
||||
/// @brief Tilt commands.
|
||||
enum relay_chn_tilt_cmd_enum {
|
||||
RELAY_CHN_TILT_CMD_NONE, ///< No command.
|
||||
RELAY_CHN_TILT_CMD_STOP, ///< Tilt command stop.
|
||||
RELAY_CHN_TILT_CMD_FORWARD, ///< Tilt command for forward.
|
||||
RELAY_CHN_TILT_CMD_REVERSE ///< Tilt command for reverse.
|
||||
};
|
||||
@@ -122,9 +127,10 @@ typedef enum relay_chn_tilt_cmd_enum relay_chn_tilt_cmd_t;
|
||||
|
||||
/// @brief Tilt steps.
|
||||
enum relay_chn_tilt_step_enum {
|
||||
RELAY_CHN_TILT_STEP_NONE, ///< No step.
|
||||
RELAY_CHN_TILT_STEP_RUN, ///< Run step. Tilt is either driving for forward or reverse.
|
||||
RELAY_CHN_TILT_STEP_PAUSE ///< Pause step. Tilt is paused.
|
||||
RELAY_CHN_TILT_STEP_NONE, ///< No step.
|
||||
RELAY_CHN_TILT_STEP_PENDING, ///< Pending step.
|
||||
RELAY_CHN_TILT_STEP_MOVE, ///< Move step. Tilt is driving either for forward or reverse.
|
||||
RELAY_CHN_TILT_STEP_PAUSE ///< Pause step. Tilt is paused.
|
||||
};
|
||||
|
||||
/// @brief Alias for the enum relay_chn_tilt_step_enum.
|
||||
@@ -132,16 +138,23 @@ typedef enum relay_chn_tilt_step_enum relay_chn_tilt_step_t;
|
||||
|
||||
/// @brief Tilt timing structure to manage tilt pattern timing.
|
||||
typedef struct relay_chn_tilt_timing_struct {
|
||||
uint8_t sensitivity; ///< Tilt sensitivity in percent value (%).
|
||||
uint32_t run_time_ms; ///< Run time in milliseconds.
|
||||
uint8_t sensitivity; ///< Tilt sensitivity in percentage (%).
|
||||
uint32_t move_time_ms; ///< Move time in milliseconds.
|
||||
uint32_t pause_time_ms; ///< Pause time in milliseconds.
|
||||
} relay_chn_tilt_timing_t;
|
||||
|
||||
/// @brief Tilt counter structure to manage tilt count.
|
||||
typedef struct relay_chn_tilt_counter_struct {
|
||||
uint32_t tilt_forward_count; ///< Tilt forward count.
|
||||
uint32_t tilt_reverse_count; ///< Tilt reverse count.
|
||||
} relay_chn_tilt_counter_t;
|
||||
|
||||
/// @brief Tilt control structure to manage tilt operations.
|
||||
typedef struct relay_chn_tilt_control_struct {
|
||||
relay_chn_tilt_cmd_t cmd; ///< Current tilt command.
|
||||
relay_chn_tilt_cmd_t cmd; ///< The tilt command in process.
|
||||
relay_chn_tilt_step_t step; ///< Current tilt step.
|
||||
relay_chn_tilt_timing_t tilt_timing; ///< Tilt timing structure.
|
||||
relay_chn_tilt_counter_t tilt_counter; ///< Tilt counter structure.
|
||||
esp_timer_handle_t tilt_timer; ///< Tilt timer handle.
|
||||
} relay_chn_tilt_control_t;
|
||||
|
||||
@@ -155,13 +168,13 @@ typedef struct relay_chn_type {
|
||||
relay_chn_output_t output; ///< Output configuration of the relay channel.
|
||||
relay_chn_cmd_t pending_cmd; ///< The command that is pending to be issued
|
||||
esp_timer_handle_t inertia_timer; ///< Timer to handle the opposite direction inertia time.
|
||||
relay_chn_tilt_control_t tilt_control;
|
||||
relay_chn_tilt_control_t tilt_control; ///< Tilt control block.
|
||||
} relay_chn_t;
|
||||
|
||||
static esp_err_t relay_chn_init_tilt_control(relay_chn_t *relay_chn);
|
||||
static void relay_chn_tilt_state_handler(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||
|
||||
static uint32_t relay_chn_tilting_channels;
|
||||
static esp_err_t relay_chn_tilt_init(void);
|
||||
static void relay_chn_tilt_count_reset(relay_chn_t *relay_chn);
|
||||
static esp_err_t relay_chn_dispatch_tilt_cmd(relay_chn_t *relay_chn, relay_chn_tilt_cmd_t cmd);
|
||||
|
||||
#endif // RELAY_CHN_ENABLE_TILTING
|
||||
|
||||
@@ -268,7 +281,8 @@ static esp_err_t relay_chn_create_event_loop()
|
||||
.task_core_id = tskNO_AFFINITY
|
||||
};
|
||||
esp_err_t ret = esp_event_loop_create(&loop_args, &relay_chn_event_loop);
|
||||
ret |= esp_event_handler_register_with(relay_chn_event_loop,
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create event loop for relay channel");
|
||||
ret = esp_event_handler_register_with(relay_chn_event_loop,
|
||||
RELAY_CHN_CMD_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
relay_chn_event_handler, NULL);
|
||||
@@ -309,14 +323,14 @@ esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count)
|
||||
|
||||
// Initialize the GPIOs
|
||||
ret = gpio_reset_pin(forward_pin);
|
||||
ret |= gpio_set_direction(forward_pin, GPIO_MODE_OUTPUT);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to reset GPIO forward pin for channel %d", i);
|
||||
ret = gpio_set_direction(forward_pin, GPIO_MODE_OUTPUT);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set GPIO direction for forward pin for channel %d", i);
|
||||
|
||||
ret |= gpio_reset_pin(reverse_pin);
|
||||
ret |= gpio_set_direction(reverse_pin, GPIO_MODE_OUTPUT);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize GPIOs relay channel %d!", i);
|
||||
return ret;
|
||||
}
|
||||
ret = gpio_reset_pin(reverse_pin);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to reset GPIO reverse pin for channel %d", i);
|
||||
ret = gpio_set_direction(reverse_pin, GPIO_MODE_OUTPUT);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set GPIO direction for reverse pin for channel %d", i);
|
||||
// Initialize the GPIOs
|
||||
|
||||
// Initialize the relay channel
|
||||
@@ -328,22 +342,23 @@ esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count)
|
||||
relay_chn->state = RELAY_CHN_STATE_FREE;
|
||||
relay_chn->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_NONE;
|
||||
ret |= relay_chn_init_timer(relay_chn); // Create direction change inertia timer
|
||||
ret = relay_chn_init_timer(relay_chn); // Create direction change inertia timer
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create relay channel timer for channel %d", i);
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
ret |= relay_chn_init_tilt_control(relay_chn);
|
||||
ret = relay_chn_init_tilt_control(relay_chn);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize tilt control for channel %d", i);
|
||||
#endif
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize relay channel %d!", i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
relay_chn_tilting_channels = 0;
|
||||
#endif
|
||||
|
||||
// Create relay channel command event loop
|
||||
ret |= relay_chn_create_event_loop();
|
||||
ret = relay_chn_create_event_loop();
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create relay channel event loop");
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
// Must call after the event loop is initialized
|
||||
ret = relay_chn_tilt_init(); // Initialize tilt feature
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize tilt feature");
|
||||
#endif
|
||||
|
||||
// Init the state listener manager
|
||||
relay_chn_state_listener_manager.listeners = malloc(sizeof(relay_chn_state_listener_t*));
|
||||
@@ -452,6 +467,13 @@ static void relay_chn_dispatch_cmd(relay_chn_t *relay_chn, relay_chn_cmd_t cmd)
|
||||
cmd,
|
||||
&relay_chn->id,
|
||||
sizeof(relay_chn->id), portMAX_DELAY);
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
// Reset the tilt counter when the command is either FORWARD or REVERSE
|
||||
if (cmd == RELAY_CHN_CMD_FORWARD || cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
relay_chn_tilt_count_reset(relay_chn);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static esp_err_t relay_chn_start_esp_timer_once(esp_timer_handle_t esp_timer, uint32_t time_ms)
|
||||
@@ -473,17 +495,6 @@ static void relay_chn_update_state(relay_chn_t *relay_chn, relay_chn_state_t new
|
||||
relay_chn_state_t old = relay_chn->state;
|
||||
relay_chn->state = new_state;
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
if (relay_chn->tilt_control.cmd != RELAY_CHN_TILT_CMD_NONE) {
|
||||
// The channel is tilting, pipe the internal state to the tilt state handler
|
||||
// unless the state sent from the tilt module
|
||||
if (relay_chn->state != RELAY_CHN_STATE_TILT_FORWARD && relay_chn->state != RELAY_CHN_STATE_TILT_REVERSE) {
|
||||
relay_chn_tilt_state_handler(relay_chn->id, old, new_state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (uint8_t i = 0; i < relay_chn_state_listener_manager.listener_count; i++) {
|
||||
relay_chn_state_listener_t listener = relay_chn_state_listener_manager.listeners[i];
|
||||
if (listener == NULL) {
|
||||
@@ -599,6 +610,37 @@ static void relay_chn_issue_cmd(relay_chn_t* relay_chn, relay_chn_cmd_t cmd)
|
||||
relay_chn_start_esp_timer_once(relay_chn->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
break;
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
case RELAY_CHN_STATE_TILT_FORWARD:
|
||||
// Terminate tilting first
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, RELAY_CHN_TILT_CMD_STOP);
|
||||
if (cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
// Schedule for running forward
|
||||
relay_chn->pending_cmd = cmd;
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_FORWARD_PENDING);
|
||||
relay_chn_start_esp_timer_once(relay_chn->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
} else if (cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
// Run directly since it is the same direction
|
||||
relay_chn_dispatch_cmd(relay_chn, cmd);
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_REVERSE);
|
||||
}
|
||||
break;
|
||||
case RELAY_CHN_STATE_TILT_REVERSE:
|
||||
// Terminate tilting first
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, RELAY_CHN_TILT_CMD_STOP);
|
||||
if (cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
// Run directly since it is the same direction
|
||||
relay_chn_dispatch_cmd(relay_chn, cmd);
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_FORWARD);
|
||||
} else if (cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
// Schedule for running reverse
|
||||
relay_chn->pending_cmd = cmd;
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_REVERSE_PENDING);
|
||||
relay_chn_start_esp_timer_once(relay_chn->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default: ESP_LOGD(TAG, "relay_chn_evaluate: Unknown relay channel state!");
|
||||
}
|
||||
}
|
||||
@@ -688,47 +730,76 @@ relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id)
|
||||
}
|
||||
/* relay_chn APIs */
|
||||
|
||||
static esp_err_t relay_chn_output_stop(relay_chn_t *relay_chn)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = gpio_set_level(relay_chn->output.forward_pin, 0);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to LOW for relay channel #%d", relay_chn->id);
|
||||
ret = gpio_set_level(relay_chn->output.reverse_pin, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t relay_chn_output_forward(relay_chn_t *relay_chn)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = gpio_set_level(relay_chn->output.forward_pin, 1);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to HIGH for relay channel #%d", relay_chn->id);
|
||||
ret = gpio_set_level(relay_chn->output.reverse_pin, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t relay_chn_output_reverse(relay_chn_t *relay_chn)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = gpio_set_level(relay_chn->output.forward_pin, 0);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to LOW for relay channel #%d", relay_chn->id);
|
||||
ret = gpio_set_level(relay_chn->output.reverse_pin, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void relay_chn_execute_stop(relay_chn_t *relay_chn)
|
||||
{
|
||||
gpio_set_level(relay_chn->output.forward_pin, 0);
|
||||
gpio_set_level(relay_chn->output.reverse_pin, 0);
|
||||
if (relay_chn_output_stop(relay_chn) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_execute_stop: Failed to output stop for relay channel #%d!", relay_chn->id);
|
||||
}
|
||||
relay_chn_state_t previous_state = relay_chn->state;
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_STOPPED);
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
// Just stop and update state if tilting is active
|
||||
if (relay_chn->tilt_control.cmd != RELAY_CHN_TILT_CMD_NONE) return;
|
||||
#endif
|
||||
|
||||
// If there is any pending command, cancel it since the STOP command is issued right after it
|
||||
relay_chn->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||
// Invalidate the channel's timer if it is active
|
||||
esp_timer_stop(relay_chn->inertia_timer);
|
||||
|
||||
// If the channel was running, schedule a free command for the channel
|
||||
if (relay_chn->run_info.last_run_cmd != RELAY_CHN_CMD_NONE) {
|
||||
// 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.last_run_cmd_time_ms = esp_timer_get_time() / 1000;
|
||||
// Schedule a free command for the channel
|
||||
relay_chn->pending_cmd = RELAY_CHN_CMD_FREE;
|
||||
relay_chn_start_esp_timer_once(relay_chn->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
} else {
|
||||
// If the channel was not running, issue a free command immediately
|
||||
// If the channel was not running one of the run or fwd, issue a free command immediately
|
||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_FREE);
|
||||
}
|
||||
}
|
||||
|
||||
static void relay_chn_execute_forward(relay_chn_t *relay_chn)
|
||||
{
|
||||
gpio_set_level(relay_chn->output.reverse_pin, 0);
|
||||
gpio_set_level(relay_chn->output.forward_pin, 1);
|
||||
if (relay_chn_output_forward(relay_chn) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_execute_forward: Failed to output forward for relay channel #%d!", relay_chn->id);
|
||||
return;
|
||||
}
|
||||
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_FORWARD;
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_FORWARD);
|
||||
}
|
||||
|
||||
static void relay_chn_execute_reverse(relay_chn_t *relay_chn)
|
||||
{
|
||||
gpio_set_level(relay_chn->output.forward_pin, 0);
|
||||
gpio_set_level(relay_chn->output.reverse_pin, 1);
|
||||
if (relay_chn_output_reverse(relay_chn) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_execute_reverse: Failed to output reverse for relay channel #%d!", relay_chn->id);
|
||||
return;
|
||||
}
|
||||
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_REVERSE;
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_REVERSE);
|
||||
}
|
||||
@@ -831,67 +902,50 @@ char *relay_chn_state_str(relay_chn_state_t state)
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
|
||||
// Timer callback for the relay_chn_tilt_control_t::tilt_timer
|
||||
static void relay_chn_tilt_timer_cb(void *arg)
|
||||
/**
|
||||
* @brief Dispatch a tilt command to the relay channel event loop.
|
||||
*
|
||||
* @param relay_chn The relay channel to send the command to.
|
||||
* @param cmd The tilt command.
|
||||
* @return
|
||||
* - ESP_OK on success.
|
||||
* - ESP_ERR_INVALID_ARG if the command is none.
|
||||
* - Other error codes on failure.
|
||||
*/
|
||||
static esp_err_t relay_chn_dispatch_tilt_cmd(relay_chn_t *relay_chn, relay_chn_tilt_cmd_t cmd)
|
||||
{
|
||||
uint8_t chn_id = *(uint8_t*) arg;
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_timer_cb: Invalid relay channel ID!");
|
||||
return;
|
||||
}
|
||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||
switch (relay_chn->tilt_control.step)
|
||||
{
|
||||
case RELAY_CHN_TILT_STEP_RUN:
|
||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||
break;
|
||||
|
||||
case RELAY_CHN_TILT_STEP_PAUSE:
|
||||
if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_REVERSE);
|
||||
}
|
||||
else if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_FORWARD);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (cmd == RELAY_CHN_TILT_CMD_NONE) return ESP_ERR_INVALID_ARG;
|
||||
return esp_event_post_to(relay_chn_event_loop,
|
||||
RELAY_CHN_TILT_CMD_EVENT_BASE,
|
||||
cmd,
|
||||
&relay_chn->id,
|
||||
sizeof(relay_chn->id), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// This listener is active until the relay_chn_tilt_stop() is called.
|
||||
static void relay_chn_tilt_state_handler(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state)
|
||||
/**
|
||||
* @brief Get the required timing before tilting depending on the last run.
|
||||
*
|
||||
* @param relay_chn the relay channel.
|
||||
* @param cmd The tilt command.
|
||||
* @return The time that is required in ms.
|
||||
*/
|
||||
static uint32_t relay_chn_get_required_timing_before_tilting(relay_chn_t *relay_chn, relay_chn_tilt_cmd_t cmd)
|
||||
{
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_state_listener: #%u, old_state: %s, new_state: %s",
|
||||
chn_id, relay_chn_state_str(old_state), relay_chn_state_str(new_state));
|
||||
if (cmd == RELAY_CHN_TILT_CMD_FORWARD && relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_REVERSE)
|
||||
return 0;
|
||||
else if (cmd == RELAY_CHN_TILT_CMD_REVERSE && relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_FORWARD)
|
||||
return 0;
|
||||
|
||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||
// Check whether this channel is the one that's been tilting
|
||||
if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (new_state)
|
||||
{
|
||||
case RELAY_CHN_STATE_FORWARD:
|
||||
case RELAY_CHN_STATE_REVERSE:
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_RUN;
|
||||
// Start the tilt run timer
|
||||
esp_timer_start_once(relay_chn->tilt_control.tilt_timer,
|
||||
relay_chn->tilt_control.tilt_timing.run_time_ms * 1000);
|
||||
break;
|
||||
case RELAY_CHN_STATE_STOPPED:
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_PAUSE;
|
||||
esp_timer_start_once(relay_chn->tilt_control.tilt_timer,
|
||||
relay_chn->tilt_control.tilt_timing.pause_time_ms * 1000);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
uint32_t inertia_time_passed_ms = (uint32_t) (esp_timer_get_time() / 1000) - relay_chn->run_info.last_run_cmd_time_ms;
|
||||
return RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Issue a tilt command to a specific relay channel.
|
||||
*
|
||||
* @param chn_id The channel ID.
|
||||
* @param cmd The tilt command.
|
||||
*/
|
||||
static void relay_chn_issue_tilt_cmd(uint8_t chn_id, relay_chn_tilt_cmd_t cmd)
|
||||
{
|
||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||
@@ -901,36 +955,70 @@ static void relay_chn_issue_tilt_cmd(uint8_t chn_id, relay_chn_tilt_cmd_t cmd)
|
||||
ESP_LOGD(TAG, "relay_chn_issue_tilt_cmd: Tilt will not be executed since the channel hasn't been run yet");
|
||||
return;
|
||||
}
|
||||
else if (relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_REVERSE && cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
ESP_LOGD(TAG, "relay_chn_issue_tilt_cmd: Invalid tilt command: TILT_FORWARD after the REVERSE command issued");
|
||||
return;
|
||||
}
|
||||
else if (relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_FORWARD && cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
ESP_LOGD(TAG, "relay_chn_issue_tilt_cmd: Invalid tilt command: TILT_REVERSE after the FORWARD command issued");
|
||||
return;
|
||||
}
|
||||
|
||||
if (relay_chn->tilt_control.cmd == cmd) {
|
||||
ESP_LOGD(TAG, "relay_chn_issue_tilt_cmd: There is already a tilt command in progress!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set tilt control parameters
|
||||
// Set the command that will be processed
|
||||
relay_chn->tilt_control.cmd = cmd;
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_NONE;
|
||||
switch (relay_chn->state) {
|
||||
case RELAY_CHN_STATE_FREE:
|
||||
// Relay channel is free, tilt can be issued immediately
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, cmd);
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_FORWARD_PENDING:
|
||||
case RELAY_CHN_STATE_REVERSE_PENDING:
|
||||
// Issue a stop command first so that the timer and pending cmd get cleared
|
||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||
// break not put intentionally
|
||||
case RELAY_CHN_STATE_STOPPED: {
|
||||
// Check if channel needs timing before tilting
|
||||
uint32_t req_timing_ms = relay_chn_get_required_timing_before_tilting(relay_chn, cmd);
|
||||
if (req_timing_ms == 0) {
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, cmd);
|
||||
} else {
|
||||
// Channel needs timing before running tilting action, schedule it
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_PENDING;
|
||||
relay_chn_start_esp_timer_once(relay_chn->tilt_control.tilt_timer, req_timing_ms);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Set channel tilting active flag
|
||||
relay_chn_tilting_channels |= (1 << chn_id);
|
||||
case RELAY_CHN_STATE_FORWARD:
|
||||
if (cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
// Stop the running channel first
|
||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||
// Schedule for tilting
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_PENDING;
|
||||
relay_chn_start_esp_timer_once(relay_chn->tilt_control.tilt_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
} else if (cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
// Stop the running channel first
|
||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||
// If the tilt cmd is TILT_REVERSE then dispatch it immediately
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, cmd);
|
||||
}
|
||||
break;
|
||||
|
||||
if (cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_REVERSE);
|
||||
// Emit the tilt state change for the channel
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_TILT_FORWARD);
|
||||
}
|
||||
else if (cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_FORWARD);
|
||||
// Emit the tilt state change for the channel
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_TILT_REVERSE);
|
||||
case RELAY_CHN_STATE_REVERSE:
|
||||
if (cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
// Stop the running channel first
|
||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||
// Schedule for tilting
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_PENDING;
|
||||
relay_chn_start_esp_timer_once(relay_chn->tilt_control.tilt_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
} else if (cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
// Stop the running channel first
|
||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||
// If the tilt cmd is TILT_FORWARD then dispatch it immediately
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, cmd);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGD(TAG, "relay_chn_issue_tilt_cmd: Unexpected relay channel state: %s!", relay_chn_state_str(relay_chn->state));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,10 +1032,10 @@ static void relay_chn_issue_tilt_cmd_on_all_channels(relay_chn_tilt_cmd_t cmd)
|
||||
static void relay_chn_issue_tilt_auto(uint8_t chn_id)
|
||||
{
|
||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||
if (relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
if (relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_FORWARD || relay_chn->state == RELAY_CHN_STATE_FORWARD) {
|
||||
relay_chn_issue_tilt_cmd(chn_id, RELAY_CHN_TILT_CMD_FORWARD);
|
||||
}
|
||||
else if (relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
else if (relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_REVERSE || relay_chn->state == RELAY_CHN_STATE_REVERSE) {
|
||||
relay_chn_issue_tilt_cmd(chn_id, RELAY_CHN_TILT_CMD_REVERSE);
|
||||
}
|
||||
}
|
||||
@@ -989,19 +1077,15 @@ void relay_chn_tilt_reverse(uint8_t chn_id)
|
||||
else relay_chn_issue_tilt_cmd(chn_id, RELAY_CHN_TILT_CMD_REVERSE);
|
||||
}
|
||||
|
||||
static void relay_chn_issue_tilt_stop(uint8_t chn_id)
|
||||
static void _relay_chn_tilt_stop(uint8_t chn_id)
|
||||
{
|
||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||
if (relay_chn->tilt_control.cmd != RELAY_CHN_TILT_CMD_NONE) {
|
||||
// Stop the channel's timer if active
|
||||
esp_timer_stop(relay_chn->tilt_control.tilt_timer);
|
||||
// Invalidate tilt cmd and step
|
||||
relay_chn->tilt_control.cmd = RELAY_CHN_TILT_CMD_NONE;
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_NONE;
|
||||
// Unset channel tilting active flag
|
||||
relay_chn_tilting_channels &= ~(1 << chn_id);
|
||||
// Stop the channel
|
||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||
esp_event_post_to(relay_chn_event_loop,
|
||||
RELAY_CHN_TILT_CMD_EVENT_BASE,
|
||||
RELAY_CHN_TILT_CMD_STOP,
|
||||
&relay_chn->id,
|
||||
sizeof(relay_chn->id), portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1010,21 +1094,14 @@ void relay_chn_tilt_stop(uint8_t chn_id)
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether there is an active tilting channel
|
||||
if (!relay_chn_tilting_channels) {
|
||||
// No active tilting channels, so nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
// Any channel executing tilt?
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_issue_tilt_stop(i);
|
||||
_relay_chn_tilt_stop(i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
relay_chn_issue_tilt_stop(chn_id);
|
||||
_relay_chn_tilt_stop(chn_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1034,7 +1111,7 @@ static void relay_chn_set_tilt_timing_values(relay_chn_tilt_timing_t *tilt_timin
|
||||
uint32_t pause_time_ms)
|
||||
{
|
||||
tilt_timing->sensitivity = sensitivity;
|
||||
tilt_timing->run_time_ms = run_time_ms;
|
||||
tilt_timing->move_time_ms = run_time_ms;
|
||||
tilt_timing->pause_time_ms = pause_time_ms;
|
||||
}
|
||||
|
||||
@@ -1104,14 +1181,212 @@ esp_err_t relay_chn_tilt_sensitivity_get(uint8_t chn_id, uint8_t *sensitivity, s
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_count_reset(relay_chn_t *relay_chn)
|
||||
{
|
||||
relay_chn->tilt_control.tilt_counter.tilt_forward_count = 0;
|
||||
relay_chn->tilt_control.tilt_counter.tilt_reverse_count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update tilt count automatically and return the current value.
|
||||
*
|
||||
* This helper function updates the relevant tilt count depending on the
|
||||
* last run info and helps the tilt module in deciding whether the requested
|
||||
* tilt should execute or not.
|
||||
* This is useful to control reverse tilting particularly. For example:
|
||||
* - If the channel's last run was FORWARD and a TILT_FORWARD is requested,
|
||||
* then the tilt counter will count up on the
|
||||
* relay_chn_tilt_counter_struct::tilt_forward_count and the function will
|
||||
* return the actual count.
|
||||
* - If the channel's last run was FORWARD and a TILT_REVERSE is requested,
|
||||
* then the relay_chn_tilt_counter_struct::tilt_forward_count will be checked
|
||||
* against zero first, and then it will count down and return the actual count
|
||||
* if it is greater than 0, else the function will return 0.
|
||||
* - If the tilt command is irrelevant then the function will return 0.
|
||||
* - If the last run is irrelevant then the function will return 0.
|
||||
*
|
||||
* @param relay_chn The relay channel handle.
|
||||
* @return uint32_t The actual value of the relevant counter.
|
||||
* @return 0 if:
|
||||
* - related counter is already 0.
|
||||
* - tilt command is irrelevant.
|
||||
* - last run info is irrelevant.
|
||||
*/
|
||||
static uint32_t relay_chn_tilt_count_update(relay_chn_t *relay_chn)
|
||||
{
|
||||
if (relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
return ++relay_chn->tilt_control.tilt_counter.tilt_forward_count;
|
||||
}
|
||||
else if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
if (relay_chn->tilt_control.tilt_counter.tilt_forward_count > 0)
|
||||
return --relay_chn->tilt_control.tilt_counter.tilt_forward_count;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
relay_chn_tilt_count_reset(relay_chn);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
return ++relay_chn->tilt_control.tilt_counter.tilt_reverse_count;
|
||||
}
|
||||
else if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
if (relay_chn->tilt_control.tilt_counter.tilt_reverse_count > 0)
|
||||
return --relay_chn->tilt_control.tilt_counter.tilt_reverse_count;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
relay_chn_tilt_count_reset(relay_chn);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_execute_tilt_stop(relay_chn_t *relay_chn)
|
||||
{
|
||||
// Stop the channel's timer if active
|
||||
esp_timer_stop(relay_chn->tilt_control.tilt_timer);
|
||||
// Invalidate tilt cmd and step
|
||||
relay_chn->tilt_control.cmd = RELAY_CHN_TILT_CMD_NONE;
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_NONE;
|
||||
// Stop the channel
|
||||
if (relay_chn_output_stop(relay_chn) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_tilt_stop: Failed to output stop for relay channel #%d!", relay_chn->id);
|
||||
}
|
||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_execute_tilt_forward(relay_chn_t *relay_chn)
|
||||
{
|
||||
if (relay_chn_output_reverse(relay_chn) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_tilt_forward: Failed to output reverse for relay channel #%d!", relay_chn->id);
|
||||
// Stop tilting because of the error
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, RELAY_CHN_TILT_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
// Set the move time timer
|
||||
relay_chn_start_esp_timer_once(relay_chn->tilt_control.tilt_timer,
|
||||
relay_chn->tilt_control.tilt_timing.move_time_ms);
|
||||
// Set to pause step
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_PAUSE;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_execute_tilt_reverse(relay_chn_t *relay_chn)
|
||||
{
|
||||
if (relay_chn_output_forward(relay_chn) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_tilt_reverse: Failed to output forward for relay channel #%d!", relay_chn->id);
|
||||
// Stop tilting because of the error
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, RELAY_CHN_TILT_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
// Set the move time timer
|
||||
relay_chn_start_esp_timer_once(relay_chn->tilt_control.tilt_timer,
|
||||
relay_chn->tilt_control.tilt_timing.move_time_ms);
|
||||
// Set to pause step
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_PAUSE;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_execute_tilt_pause(relay_chn_t *relay_chn)
|
||||
{
|
||||
// Pause the channel
|
||||
if (relay_chn_output_stop(relay_chn) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_tilt_stop: Failed to output stop for relay channel #%d!", relay_chn->id);
|
||||
// Stop tilting because of the error
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, RELAY_CHN_TILT_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the tilt counter before the next move and expect the return value to be greater than 0
|
||||
if (relay_chn_tilt_count_update(relay_chn) == 0) {
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_execute_tilt_stop: Relay channel cannot tilt anymore");
|
||||
// Stop tilting since the tilting limit has been reached
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, RELAY_CHN_TILT_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the pause time timer
|
||||
relay_chn_start_esp_timer_once(relay_chn->tilt_control.tilt_timer,
|
||||
relay_chn->tilt_control.tilt_timing.pause_time_ms);
|
||||
// Set to move step
|
||||
relay_chn->tilt_control.step = RELAY_CHN_TILT_STEP_MOVE;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_event_handler(void *handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||
{
|
||||
uint8_t chn_id = *(uint8_t*) event_data;
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return;
|
||||
}
|
||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||
ESP_LOGD(TAG, "relay_chn_event_handler: Channel %d, Command: %s", relay_chn->id, relay_chn_cmd_str(event_id));
|
||||
switch(event_id) {
|
||||
case RELAY_CHN_TILT_CMD_STOP:
|
||||
relay_chn_tilt_execute_tilt_stop(relay_chn);
|
||||
break;
|
||||
case RELAY_CHN_TILT_CMD_FORWARD:
|
||||
relay_chn_tilt_execute_tilt_forward(relay_chn);
|
||||
// Update channel state
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_TILT_FORWARD);
|
||||
break;
|
||||
case RELAY_CHN_TILT_CMD_REVERSE:
|
||||
relay_chn_tilt_execute_tilt_reverse(relay_chn);
|
||||
// Update channel state
|
||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_TILT_REVERSE);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unexpected relay channel tilt command: %ld!", event_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Timer callback for the relay_chn_tilt_control_t::tilt_timer
|
||||
static void relay_chn_tilt_timer_cb(void *arg)
|
||||
{
|
||||
uint8_t chn_id = *(uint8_t*) arg;
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_timer_cb: Invalid relay channel ID!");
|
||||
return;
|
||||
}
|
||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||
|
||||
switch (relay_chn->tilt_control.step)
|
||||
{
|
||||
case RELAY_CHN_TILT_STEP_MOVE:
|
||||
if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
relay_chn_tilt_execute_tilt_forward(relay_chn);
|
||||
}
|
||||
else if (relay_chn->tilt_control.cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
relay_chn_tilt_execute_tilt_reverse(relay_chn);
|
||||
}
|
||||
break;
|
||||
|
||||
case RELAY_CHN_TILT_STEP_PAUSE:
|
||||
relay_chn_tilt_execute_tilt_pause(relay_chn);
|
||||
break;
|
||||
|
||||
case RELAY_CHN_TILT_STEP_PENDING:
|
||||
// Just dispatch the pending tilt command
|
||||
relay_chn_dispatch_tilt_cmd(relay_chn, relay_chn->tilt_control.cmd);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t relay_chn_init_tilt_control(relay_chn_t *relay_chn)
|
||||
{
|
||||
relay_chn_tilt_control_t *tilt_control = &relay_chn->tilt_control;
|
||||
tilt_control->cmd = RELAY_CHN_TILT_CMD_NONE;
|
||||
tilt_control->step = RELAY_CHN_TILT_STEP_NONE;
|
||||
tilt_control->tilt_timing.sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
|
||||
tilt_control->tilt_timing.run_time_ms = RELAY_CHN_TILT_DEFAULT_RUN_MS;
|
||||
tilt_control->tilt_timing.move_time_ms = RELAY_CHN_TILT_DEFAULT_RUN_MS;
|
||||
tilt_control->tilt_timing.pause_time_ms = RELAY_CHN_TILT_DEFAULT_PAUSE_MS;
|
||||
relay_chn_tilt_count_reset(relay_chn);
|
||||
|
||||
// Create tilt timer for the channel
|
||||
char timer_name[32];
|
||||
@@ -1124,6 +1399,17 @@ static esp_err_t relay_chn_init_tilt_control(relay_chn_t *relay_chn)
|
||||
return esp_timer_create(&timer_args, &relay_chn->tilt_control.tilt_timer);
|
||||
}
|
||||
|
||||
// Should call once from relay_chn_init
|
||||
static esp_err_t relay_chn_tilt_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = esp_event_handler_register_with(relay_chn_event_loop,
|
||||
RELAY_CHN_TILT_CMD_EVENT_BASE,
|
||||
ESP_EVENT_ANY_ID,
|
||||
relay_chn_tilt_event_handler, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // RELAY_CHN_ENABLE_TILTING
|
||||
|
||||
/// @}
|
||||
@@ -1,8 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,3 +0,0 @@
|
||||
idf_component_register(SRCS_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity test_utils relay_chn)
|
||||
@@ -1,95 +0,0 @@
|
||||
#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();
|
||||
}
|
||||
Reference in New Issue
Block a user