Compare commits
17 Commits
a3f83eaaee
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
497f45e336
|
|||
|
95ca976bc6
|
|||
|
300f9a1317
|
|||
|
5440440c4d
|
|||
|
8416187d86
|
|||
|
9f45a2310d
|
|||
|
a1ff54b6e9
|
|||
| c718a1380f | |||
|
6caa4f1bd5
|
|||
|
4edebf206e
|
|||
|
e30b445b91
|
|||
|
9ee974e677
|
|||
|
31e351a129
|
|||
|
3ce079c2e8
|
|||
|
a5b320c152
|
|||
|
087deb338e
|
|||
|
fbf8b5dfc8
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -59,6 +59,7 @@ tools/test_apps/**/sdkconfig.old
|
||||
# autogenerated config files
|
||||
sdkconfig
|
||||
test_apps/sdkconfig
|
||||
test_apps/sdkconfig.old
|
||||
|
||||
TEST_LOGS/
|
||||
build_summary_*.xml
|
||||
@@ -73,6 +74,7 @@ test_multi_heap_host
|
||||
|
||||
# VS Code Settings
|
||||
# .vscode/
|
||||
settings.json
|
||||
|
||||
# VIM files
|
||||
*.swp
|
||||
@@ -112,4 +114,4 @@ XUNIT_RESULT*.xml
|
||||
.clangd
|
||||
|
||||
# Vale
|
||||
.vale/styles/*
|
||||
.vale/styles/*
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"C_Cpp.intelliSenseEngine": "default"
|
||||
}
|
||||
@@ -16,7 +16,7 @@ else()
|
||||
list(APPEND srcs "src/relay_chn_ctl_single.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_RELAY_CHN_NVS)
|
||||
if(CONFIG_RELAY_CHN_ENABLE_NVS)
|
||||
list(APPEND srcs "src/relay_chn_nvs.c")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ dependencies:
|
||||
# Add as a custom component from git repository
|
||||
relay_chn:
|
||||
git: https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn.git
|
||||
version: '>=0.5.0'
|
||||
version: '>=1.0.0'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
6
examples/relay_chn_multi/.gitignore
vendored
Normal file
6
examples/relay_chn_multi/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
build/
|
||||
sdkconfig
|
||||
sdkconfig.old
|
||||
|
||||
# Exclude auto-populated settings file
|
||||
settings.json
|
||||
23
examples/relay_chn_multi/.vscode/c_cpp_properties.json
vendored
Normal file
23
examples/relay_chn_multi/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ESP-IDF",
|
||||
"compilerPath": "${config:idf.toolsPath}/tools/riscv32-esp-elf/esp-14.2.0_20241119/riscv32-esp-elf/bin/riscv32-esp-elf-gcc",
|
||||
"compileCommands": "/disk/Projeler/ESP-Components/relay_chn/examples/relay_chn_single/build/compile_commands.json",
|
||||
"includePath": [
|
||||
"${config:idf.espIdfPath}/components/**",
|
||||
"${config:idf.espIdfPathWin}/components/**",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${config:idf.espIdfPath}/components",
|
||||
"${config:idf.espIdfPathWin}/components",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
15
examples/relay_chn_multi/.vscode/launch.json
vendored
Normal file
15
examples/relay_chn_multi/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "gdbtarget",
|
||||
"request": "attach",
|
||||
"name": "Eclipse CDT GDB Adapter"
|
||||
},
|
||||
{
|
||||
"type": "espidf",
|
||||
"name": "Launch",
|
||||
"request": "launch"
|
||||
}
|
||||
]
|
||||
}
|
||||
10
examples/relay_chn_multi/CMakeLists.txt
Normal file
10
examples/relay_chn_multi/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five 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(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(relay_chn_single)
|
||||
176
examples/relay_chn_multi/README.md
Normal file
176
examples/relay_chn_multi/README.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# Relay Channel Multi Example
|
||||
|
||||
## Introduction
|
||||
|
||||
This example demonstrates how to use the relay channel component to control a 3-channel setup with button inputs and LED status indication. It showcases:
|
||||
|
||||
- Basic relay channel operations (forward/reverse running, stopping)
|
||||
- Secondary operations (tilting, direction flipping)
|
||||
- State change event handling with a listener
|
||||
- Relay channel run limit
|
||||
- Button event handling using esp-iot-solution's button component
|
||||
- Visual feedback using esp-iot-solution's LED indicator component
|
||||
|
||||
## How to Use Example
|
||||
|
||||
This example has been tested on an `ESP32-C3-DevKitM-1U` board. However, it can be adapted to any ESP32-based board with at least six available GPIO pins by adjusting the configuration options.
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* An ESP32-based development board
|
||||
* 2 relays connected to GPIO pins (default: GPIO4, GPIO5)
|
||||
* 3 buttons connected to GPIO pins:
|
||||
- UP button (default: GPIO0)
|
||||
- DOWN button (default: GPIO1)
|
||||
- STOP button (default: GPIO2)
|
||||
- SELECT button (default: GPIO3)
|
||||
* LED indicators for status indication of each channel (default: GPIO4, GPIO10 and GPIO9 respectively)
|
||||
|
||||
#### Hardware Schematic
|
||||
|
||||
Relay blocks are ommitted for simplicity. You can refer to schematic of the [Single-channel example](/examples/relay_chn_single/README.md) for a fully implemented relay block.
|
||||
|
||||
> [!NOTE]
|
||||
> A single relay channel consists of two relay block and two GPIO pins.
|
||||
|
||||

|
||||
|
||||
### Configuration
|
||||
|
||||
The example can be configured through `menuconfig` under "Relay Channel Multi Example Configuration":
|
||||
|
||||
1. Button active level (`EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL`)
|
||||
- Select between active LOW or HIGH logic level for buttons
|
||||
|
||||
2. GPIO assignments:
|
||||
- UP button pin (`EXAMPLE_RLCHN_BTN_UP_IO_NUM`, default: 0)
|
||||
- DOWN button pin (`EXAMPLE_RLCHN_BTN_DOWN_IO_NUM`, default: 1)
|
||||
- STOP button pin (`EXAMPLE_RLCHN_BTN_STOP_IO_NUM`, default: 2)
|
||||
- SELECT button pin (`EXAMPLE_RLCHN_BTN_SELECT_IO_NUM`, default: 3)
|
||||
- LED indicator pin (`EXAMPLE_RLCHN_LED_INDICATOR1_IO_NUM`, default: 4)
|
||||
- LED indicator pin (`EXAMPLE_RLCHN_LED_INDICATOR2_IO_NUM`, default: 10)
|
||||
- LED indicator pin (`EXAMPLE_RLCHN_LED_INDICATOR3_IO_NUM`, default: 9)
|
||||
|
||||
3. Long press timing:
|
||||
- `EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS`: Duration for long press actions (1500-3000ms, default: 2000ms)
|
||||
|
||||
### Button Operations
|
||||
|
||||
The example uses esp-iot-solution's `button` component to handle the following operations:
|
||||
|
||||
- **UP button**:
|
||||
* Short press: Start forward movement
|
||||
* Long press: Start forward tilt (stops on release)
|
||||
|
||||
- **DOWN button**:
|
||||
* Short press: Start reverse movement
|
||||
* Long press: Start reverse tilt (stops on release)
|
||||
|
||||
- **STOP button**:
|
||||
* Short press: Stop movement
|
||||
* Long press: Flip movement direction
|
||||
|
||||
- **SELECT button**:
|
||||
* Short press: Selects a channel to operate
|
||||
* Long press: Selects all channels to operate in batch
|
||||
|
||||
### LED Indicator States
|
||||
|
||||
The example uses esp-iot-solution's `led_indicator` component to show different states:
|
||||
|
||||
- **Running**: LED blinks at 300ms on, 100ms off
|
||||
- **Tilting**: Fast blink at 100ms on, 50ms off
|
||||
- **Operation Success**: Two quick blinks
|
||||
- **Operation Fail**: One long blink
|
||||
|
||||
### Dependencies
|
||||
|
||||
This example requires:
|
||||
- ESP-IDF v4.1 or later
|
||||
- esp-iot-solution components:
|
||||
* button v4.1.1 or later
|
||||
* led_indicator v1.1.1 or later
|
||||
- relay_chn component
|
||||
|
||||
## Example Output
|
||||
|
||||
When the application boots, it will wait for a button event. Then ta state listener will print state changes.
|
||||
|
||||
```log
|
||||
I (269) main_task: Calling app_main()
|
||||
I (269) RELAY_CHN_MULTI_EXAMPLE: Initializing relay channel
|
||||
I (279) gpio: GPIO[18]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (279) gpio: GPIO[19]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (289) gpio: GPIO[5]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (299) gpio: GPIO[6]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (309) gpio: GPIO[7]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (319) gpio: GPIO[8]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (329) RELAY_CHN_MULTI_EXAMPLE: Initializing buttons
|
||||
I (329) RELAY_CHN_MULTI_EXAMPLE: Initializing buttons with active level: 0
|
||||
I (339) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (339) button: IoT Button Version: 4.1.3
|
||||
I (349) gpio: GPIO[1]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (359) gpio: GPIO[2]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (359) gpio: GPIO[3]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (369) RELAY_CHN_MULTI_EXAMPLE: Setting up button callbacks. Configured long press time: 2000 ms
|
||||
I (379) RELAY_CHN_MULTI_EXAMPLE: Initializing LED indicator
|
||||
I (389) gpio: GPIO[4]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (389) led_indicator: LED Indicator Version: 1.1.1
|
||||
I (399) gpio: GPIO[4]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (409) led_indicator: Indicator create successfully. type:GPIO mode, hardware_data:0x3fc96498, blink_lists:custom
|
||||
I (419) gpio: GPIO[10]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (429) led_indicator: LED Indicator Version: 1.1.1
|
||||
I (429) gpio: GPIO[10]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (439) led_indicator: Indicator create successfully. type:GPIO mode, hardware_data:0x3fc965a4, blink_lists:custom
|
||||
I (449) gpio: GPIO[9]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (459) led_indicator: LED Indicator Version: 1.1.1
|
||||
I (459) gpio: GPIO[9]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (469) led_indicator: Indicator create successfully. type:GPIO mode, hardware_data:0x3fc966b0, blink_lists:custom
|
||||
I (479) RELAY_CHN_MULTI_EXAMPLE: Relay Channel Multi Example is ready to operate
|
||||
I (489) main_task: Returned from app_main()
|
||||
I (3759) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from IDLE to FORWARD
|
||||
I (6639) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from FORWARD to STOPPED
|
||||
I (7439) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from STOPPED to IDLE
|
||||
I (7439) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from IDLE to TILT_FORWARD
|
||||
I (8119) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from TILT_FORWARD to IDLE
|
||||
I (13579) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from IDLE to TILT_REVERSE
|
||||
I (14419) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from TILT_REVERSE to IDLE
|
||||
I (20319) RELAY_CHN_MULTI_EXAMPLE: Selected channel: 1
|
||||
I (21479) RELAY_CHN_MULTI_EXAMPLE: Selected channel: 2
|
||||
I (22229) RELAY_CHN_MULTI_EXAMPLE: Selected channel: 0
|
||||
I (23169) RELAY_CHN_MULTI_EXAMPLE: Selected channel: 1
|
||||
I (29039) RELAY_CHN_MULTI_EXAMPLE: Selected all channels
|
||||
I (35419) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from IDLE to FORWARD
|
||||
I (35419) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from IDLE to FORWARD
|
||||
I (35419) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from IDLE to FORWARD
|
||||
I (39349) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from FORWARD to STOPPED
|
||||
I (39349) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from FORWARD to STOPPED
|
||||
I (39359) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from FORWARD to STOPPED
|
||||
I (40149) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from STOPPED to IDLE
|
||||
I (40149) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from IDLE to TILT_FORWARD
|
||||
I (40159) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from STOPPED to IDLE
|
||||
I (40169) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from IDLE to TILT_FORWARD
|
||||
I (40179) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from STOPPED to IDLE
|
||||
I (40189) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from IDLE to TILT_FORWARD
|
||||
I (41699) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from TILT_FORWARD to IDLE
|
||||
I (41699) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from TILT_FORWARD to IDLE
|
||||
I (41709) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from TILT_FORWARD to IDLE
|
||||
I (64129) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from IDLE to TILT_REVERSE
|
||||
I (64129) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from IDLE to TILT_REVERSE
|
||||
I (64139) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from IDLE to TILT_REVERSE
|
||||
I (68929) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from TILT_REVERSE to IDLE
|
||||
I (68929) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from TILT_REVERSE to IDLE
|
||||
I (68939) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from TILT_REVERSE to IDLE
|
||||
I (280109) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from IDLE to FORWARD
|
||||
I (280109) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from IDLE to FORWARD
|
||||
I (280109) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from IDLE to FORWARD
|
||||
I (283219) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from FORWARD to STOPPED
|
||||
I (283219) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from STOPPED to REVERSE_PENDING
|
||||
I (283229) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from FORWARD to STOPPED
|
||||
I (283239) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from STOPPED to REVERSE_PENDING
|
||||
I (283249) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from FORWARD to STOPPED
|
||||
I (283259) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from STOPPED to REVERSE_PENDING
|
||||
I (284019) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #0, from REVERSE_PENDING to REVERSE
|
||||
I (284019) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #1, from REVERSE_PENDING to REVERSE
|
||||
I (284029) RELAY_CHN_MULTI_EXAMPLE: example_event_listener: State change for #2, from REVERSE_PENDING to REVERSE
|
||||
```
|
||||
BIN
examples/relay_chn_multi/example_schematic.png
Normal file
BIN
examples/relay_chn_multi/example_schematic.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
2
examples/relay_chn_multi/main/CMakeLists.txt
Normal file
2
examples/relay_chn_multi/main/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "relay_chn_multi_main.c"
|
||||
PRIV_REQUIRES button led_indicator relay_chn)
|
||||
52
examples/relay_chn_multi/main/Kconfig.projbuild
Normal file
52
examples/relay_chn_multi/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,52 @@
|
||||
menu "Relay Channel Multi Example Configuration"
|
||||
|
||||
choice EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL
|
||||
prompt "Choose an active level for buttons"
|
||||
default EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_LOW
|
||||
help
|
||||
Specify the active level for buttons.
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_LOW
|
||||
bool "Active level LOW"
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_HIGH
|
||||
bool "Active level HIGH"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_UP_IO_NUM
|
||||
int "GPIO number for UP button"
|
||||
default 0
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_DOWN_IO_NUM
|
||||
int "GPIO number for DOWN button"
|
||||
default 1
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_STOP_IO_NUM
|
||||
int "GPIO number for STOP button"
|
||||
default 2
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_SELECT_IO_NUM
|
||||
int "GPIO number for STOP button"
|
||||
default 3
|
||||
|
||||
config EXAMPLE_RLCHN_LED_INDICATOR1_IO_NUM
|
||||
int "GPIO number for LED indicator output for channel 1"
|
||||
default 4
|
||||
|
||||
config EXAMPLE_RLCHN_LED_INDICATOR2_IO_NUM
|
||||
int "GPIO number for LED indicator output for channel 2"
|
||||
default 10
|
||||
|
||||
config EXAMPLE_RLCHN_LED_INDICATOR3_IO_NUM
|
||||
int "GPIO number for LED indicator output for channel 3"
|
||||
default 9
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS
|
||||
int "Long press time in ms to start secondary actions"
|
||||
range 1500 3000
|
||||
default 2000
|
||||
help
|
||||
Long press time in milliseconds is required to start secondary actions
|
||||
like tilting and flipping.
|
||||
|
||||
endmenu
|
||||
8
examples/relay_chn_multi/main/idf_component.yml
Normal file
8
examples/relay_chn_multi/main/idf_component.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=4.1.0'
|
||||
espressif/button: ^4.1.1
|
||||
espressif/led_indicator: ^1.1.1
|
||||
relay_chn:
|
||||
version: '*'
|
||||
override_path: ../../../
|
||||
427
examples/relay_chn_multi/main/relay_chn_multi_main.c
Normal file
427
examples/relay_chn_multi/main/relay_chn_multi_main.c
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_timer.h"
|
||||
#include "button_gpio.h"
|
||||
#include "iot_button.h"
|
||||
#include "led_indicator.h"
|
||||
#include "relay_chn.h"
|
||||
|
||||
static const char *TAG = "RELAY_CHN_MULTI_EXAMPLE";
|
||||
|
||||
#define EXAMPLE_CHN_INDICATOR_ON_TIME_MS 3000
|
||||
#define EXAMPLE_ALL_CHANNELS CONFIG_RELAY_CHN_COUNT
|
||||
|
||||
|
||||
/**
|
||||
* @brief LED indicator modes for different states.
|
||||
*/
|
||||
typedef enum {
|
||||
INDICATOR_MODE_SELECT, /*!< Channel select indication */
|
||||
INDICATOR_MODE_OK, /*!< OK/Success indication */
|
||||
INDICATOR_MODE_FAIL, /*!< Fail/Error indication */
|
||||
INDICATOR_MODE_TILTING, /*!< Tilting operation in progress */
|
||||
INDICATOR_MODE_RUNNING, /*!< Full run operation in progress */
|
||||
INDICATOR_MODE_MAX /*!< Maximum number of indicator modes */
|
||||
} indicator_mode_t;
|
||||
|
||||
/** @brief Blink pattern for channel select indication. */
|
||||
static const blink_step_t indc_mode_select[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, EXAMPLE_CHN_INDICATOR_ON_TIME_MS}, // step1: turn on LED 3000 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 10}, // step2: turn off LED 500 ms
|
||||
{LED_BLINK_STOP, 0, 0}, // step4: stop blink (off)
|
||||
};
|
||||
|
||||
/** @brief Blink pattern for OK/Success indication. */
|
||||
static const blink_step_t indc_mode_ok[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step1: turn on LED 100 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step2: turn off LED 50 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step3: turn on LED 100 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step4: turn off LED 50 ms
|
||||
{LED_BLINK_STOP, 0, 0}, // step5: stop blink (off)
|
||||
};
|
||||
|
||||
/** @brief Blink pattern for Fail/Error indication. */
|
||||
static const blink_step_t indc_mode_fail[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 1000}, // step1: turn on LED 1000 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 500}, // step2: turn off LED 500 ms
|
||||
{LED_BLINK_STOP, 0, 0}, // step4: stop blink (off)
|
||||
};
|
||||
|
||||
/** @brief Blink pattern for full run operation. */
|
||||
static const blink_step_t indc_mode_running[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 300}, // step1: turn on LED 300 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 100}, // step2: turn off LED 100 ms
|
||||
{LED_BLINK_LOOP, 0, 0}, // step3: loop from step1
|
||||
};
|
||||
|
||||
/** @brief Blink pattern for tilting operation. */
|
||||
static const blink_step_t indc_mode_tilting[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step1: turn on LED 100 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step2: turn off LED 50 ms
|
||||
{LED_BLINK_LOOP, 0, 0}, // step3: loop from step1
|
||||
};
|
||||
|
||||
/** @brief Array of LED indicator blink patterns. */
|
||||
blink_step_t const *led_indicator_modes[] = {
|
||||
[INDICATOR_MODE_SELECT] = indc_mode_select,
|
||||
[INDICATOR_MODE_OK] = indc_mode_ok,
|
||||
[INDICATOR_MODE_FAIL] = indc_mode_fail,
|
||||
[INDICATOR_MODE_RUNNING] = indc_mode_running,
|
||||
[INDICATOR_MODE_TILTING] = indc_mode_tilting,
|
||||
[INDICATOR_MODE_MAX] = NULL,
|
||||
};
|
||||
|
||||
/** @brief Handle for the LED indicator. */
|
||||
static led_indicator_handle_t indicators[CONFIG_RELAY_CHN_COUNT];
|
||||
static uint8_t selected_channel = 0; /*!< Currently selected channel */
|
||||
static uint8_t selected_channel_backup = 0; /*!< Backup for last selected channel */
|
||||
static int64_t last_indc_update_us = 0; /*!< Timestamp of the last channel selection */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initializes the buttons for user interaction.
|
||||
*
|
||||
* This function configures and creates GPIO buttons for UP, DOWN, and STOP
|
||||
* operations. It also registers callbacks for single-click and long-press
|
||||
* events to control the relay channel.
|
||||
*
|
||||
* @return esp_err_t
|
||||
* - ESP_OK: Success
|
||||
* - Others: Fail
|
||||
*/
|
||||
static esp_err_t init_buttons(void);
|
||||
|
||||
/**
|
||||
* @brief Initializes the LED indicator.
|
||||
*
|
||||
* This function configures and creates the LED indicator used to provide
|
||||
* visual feedback on the relay channel's status.
|
||||
*
|
||||
* @return esp_err_t
|
||||
* - ESP_OK: Success
|
||||
* - ESP_FAIL: Fail
|
||||
*/
|
||||
static esp_err_t init_led_indicators(void);
|
||||
|
||||
/**
|
||||
* @brief Starts all indicators with the specified mode.
|
||||
*
|
||||
* @param mode One of the indicator modes defined with indicator_mode_t.
|
||||
*/
|
||||
static void start_all_indicators_for_mode(indicator_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Stops all indicators with the specified mode.
|
||||
*
|
||||
* @param mode One of the indicator modes defined with indicator_mode_t.
|
||||
*/
|
||||
static void stop_all_indicators_for_mode(indicator_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Event listener for relay channel state changes to log the state transition.
|
||||
*/
|
||||
static void example_event_listener(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
const uint8_t gpio_map[] = { 18, 19, 5, 6, 7, 8 };
|
||||
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||
|
||||
ESP_LOGI(TAG, "Initializing relay channel");
|
||||
ESP_ERROR_CHECK(relay_chn_create(gpio_map, gpio_count));
|
||||
ESP_ERROR_CHECK(relay_chn_register_listener(example_event_listener));
|
||||
|
||||
ESP_LOGI(TAG, "Initializing buttons");
|
||||
ESP_ERROR_CHECK(init_buttons());
|
||||
ESP_LOGI(TAG, "Initializing LED indicator");
|
||||
ESP_ERROR_CHECK(init_led_indicators());
|
||||
|
||||
ESP_LOGI(TAG, "Relay Channel Multi Example is ready to operate");
|
||||
|
||||
// Indicate init was successful
|
||||
start_all_indicators_for_mode(INDICATOR_MODE_OK);
|
||||
}
|
||||
|
||||
static void on_click_up(void *arg, void *data)
|
||||
{
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
relay_chn_run_forward_all();
|
||||
} else {
|
||||
relay_chn_run_forward(selected_channel);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_click_down(void *arg, void *data)
|
||||
{
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
relay_chn_run_reverse_all();
|
||||
} else {
|
||||
relay_chn_run_reverse(selected_channel);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_click_stop(void *arg, void *data)
|
||||
{
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
relay_chn_stop_all();
|
||||
} else {
|
||||
relay_chn_stop(selected_channel);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_click_flip(void *arg, void *data)
|
||||
{
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
relay_chn_flip_direction_all();
|
||||
start_all_indicators_for_mode(INDICATOR_MODE_OK);
|
||||
} else {
|
||||
relay_chn_flip_direction(selected_channel);
|
||||
led_indicator_start(indicators[selected_channel], INDICATOR_MODE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_click_tilt_up(void *arg, void *data)
|
||||
{
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
relay_chn_tilt_forward_all();
|
||||
} else {
|
||||
relay_chn_tilt_forward(selected_channel);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_click_tilt_down(void *arg, void *data)
|
||||
{
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
relay_chn_tilt_reverse_all();
|
||||
} else {
|
||||
relay_chn_tilt_reverse(selected_channel);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_release_tilt(void *arg, void *data)
|
||||
{
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
relay_chn_tilt_stop_all();
|
||||
} else {
|
||||
relay_chn_tilt_stop(selected_channel);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_click_select(void *arg, void *data)
|
||||
{
|
||||
int64_t now_us = esp_timer_get_time();
|
||||
uint32_t delta_ms = (now_us - last_indc_update_us) / 1000;
|
||||
if (delta_ms >= EXAMPLE_CHN_INDICATOR_ON_TIME_MS) {
|
||||
// Channel indicator was off, turn it on first
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
start_all_indicators_for_mode(INDICATOR_MODE_SELECT);
|
||||
} else {
|
||||
led_indicator_start(indicators[selected_channel], INDICATOR_MODE_SELECT);
|
||||
}
|
||||
last_indc_update_us = esp_timer_get_time(); // Save last selection time
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
// All channels selected previously, restore the selected channel
|
||||
selected_channel = selected_channel_backup;
|
||||
ESP_LOGI(TAG, "Restored selected channel: %d", selected_channel);
|
||||
stop_all_indicators_for_mode(INDICATOR_MODE_SELECT);
|
||||
led_indicator_start(indicators[selected_channel], INDICATOR_MODE_SELECT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Channel indicator is turned on, select the next channel
|
||||
selected_channel = ((selected_channel + 1) % CONFIG_RELAY_CHN_COUNT);
|
||||
ESP_LOGI(TAG, "Selected channel: %d", selected_channel);
|
||||
// Update the indicator
|
||||
stop_all_indicators_for_mode(INDICATOR_MODE_SELECT);
|
||||
led_indicator_start(indicators[selected_channel], INDICATOR_MODE_SELECT);
|
||||
last_indc_update_us = esp_timer_get_time(); // Save last selection time
|
||||
}
|
||||
|
||||
static void on_click_select_all(void *arg, void *data)
|
||||
{
|
||||
if (selected_channel == EXAMPLE_ALL_CHANNELS) {
|
||||
ESP_LOGI(TAG, "All channels are selected already");
|
||||
int64_t now_us = esp_timer_get_time();
|
||||
uint32_t delta_ms = (now_us - last_indc_update_us) / 1000;
|
||||
// If the indicators in sleep, wake up
|
||||
if (delta_ms >= EXAMPLE_CHN_INDICATOR_ON_TIME_MS) {
|
||||
start_all_indicators_for_mode(INDICATOR_MODE_SELECT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
selected_channel_backup = selected_channel;
|
||||
selected_channel = EXAMPLE_ALL_CHANNELS;
|
||||
ESP_LOGI(TAG, "Selected all channels");
|
||||
start_all_indicators_for_mode(INDICATOR_MODE_SELECT);
|
||||
last_indc_update_us = esp_timer_get_time(); // Save last selection time
|
||||
}
|
||||
|
||||
static void start_all_indicators_for_mode(indicator_mode_t mode)
|
||||
{
|
||||
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||
led_indicator_start(indicators[i], mode);
|
||||
}
|
||||
}
|
||||
|
||||
static void stop_all_indicators_for_mode(indicator_mode_t mode)
|
||||
{
|
||||
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||
led_indicator_stop(indicators[i], mode);
|
||||
led_indicator_set_on_off(indicators[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
static void example_event_listener(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state)
|
||||
{
|
||||
ESP_LOGI(TAG, "example_event_listener: State change for #%d, from %s to %s",
|
||||
ch, relay_chn_state_to_str(old_state), relay_chn_state_to_str(new_state));
|
||||
switch (new_state) {
|
||||
case RELAY_CHN_STATE_FORWARD:
|
||||
case RELAY_CHN_STATE_REVERSE:
|
||||
led_indicator_start(indicators[ch], INDICATOR_MODE_RUNNING);
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_STOPPED:
|
||||
case RELAY_CHN_STATE_IDLE:
|
||||
if (old_state == RELAY_CHN_STATE_FORWARD || old_state == RELAY_CHN_STATE_REVERSE) {
|
||||
led_indicator_stop(indicators[ch], INDICATOR_MODE_RUNNING);
|
||||
// Make sure the indicator turned off
|
||||
led_indicator_set_on_off(indicators[ch], false);
|
||||
}
|
||||
else if (old_state == RELAY_CHN_STATE_TILT_FORWARD || old_state == RELAY_CHN_STATE_TILT_REVERSE) {
|
||||
led_indicator_stop(indicators[ch], INDICATOR_MODE_TILTING);
|
||||
// Make sure the indicator turned off
|
||||
led_indicator_set_on_off(indicators[ch], false);
|
||||
}
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_TILT_FORWARD:
|
||||
case RELAY_CHN_STATE_TILT_REVERSE:
|
||||
led_indicator_start(indicators[ch], INDICATOR_MODE_TILTING);
|
||||
break;
|
||||
|
||||
default: // No-op
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t init_buttons()
|
||||
{
|
||||
esp_err_t ret;
|
||||
button_config_t btn_cfg = {0};
|
||||
|
||||
uint8_t active_level = CONFIG_EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_LOW ? 0 : 1;
|
||||
|
||||
button_gpio_config_t btn_gpio_ccfg = {
|
||||
.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_UP_IO_NUM,
|
||||
.active_level = active_level
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Initializing buttons with active level: %u", active_level);
|
||||
button_handle_t btn_up = NULL, btn_down = NULL, btn_stop = NULL, btn_select = NULL;
|
||||
// --- Create buttons ---
|
||||
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_up);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create UP button");
|
||||
ESP_RETURN_ON_FALSE(btn_up != NULL, ret, TAG, "Failed to create UP button");
|
||||
|
||||
btn_gpio_ccfg.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_DOWN_IO_NUM;
|
||||
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_down);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create DOWN button");
|
||||
ESP_RETURN_ON_FALSE(btn_down != NULL, ret, TAG, "Failed to create DOWN button");
|
||||
|
||||
btn_gpio_ccfg.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_STOP_IO_NUM;
|
||||
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_stop);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create STOP button");
|
||||
ESP_RETURN_ON_FALSE(btn_stop != NULL, ret, TAG, "Failed to create STOP button");
|
||||
|
||||
btn_gpio_ccfg.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_SELECT_IO_NUM;
|
||||
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_select);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create SELECT button");
|
||||
ESP_RETURN_ON_FALSE(btn_select != NULL, ret, TAG, "Failed to create SELECT button");
|
||||
// --- Create buttons ---
|
||||
|
||||
// --- Register button callbacks ---
|
||||
ESP_LOGI(TAG, "Setting up button callbacks. Configured long press time: %d ms", CONFIG_EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS);
|
||||
button_event_args_t btn_event_args = {
|
||||
.long_press.press_time = CONFIG_EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS
|
||||
};
|
||||
// --- Register UP and TILT_UP operations on UP button ---
|
||||
ret = iot_button_register_cb(btn_up, BUTTON_SINGLE_CLICK, NULL, on_click_up, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register UP button click callback");
|
||||
ret = iot_button_register_cb(btn_up, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_tilt_up, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_UP button press callback");
|
||||
ret = iot_button_register_cb(btn_up, BUTTON_LONG_PRESS_UP, NULL, on_release_tilt, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_UP button release callback");
|
||||
|
||||
// --- Register DOWN and TILT_DOWN operations on DOWN button ---
|
||||
ret = iot_button_register_cb(btn_down, BUTTON_SINGLE_CLICK, NULL, on_click_down, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register DOWN button click callback");
|
||||
ret = iot_button_register_cb(btn_down, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_tilt_down, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_DOWN button press callback");
|
||||
ret = iot_button_register_cb(btn_down, BUTTON_LONG_PRESS_UP, NULL, on_release_tilt, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_DOWN button release callback");
|
||||
|
||||
// --- Register STOP and FLIP operations on STOP ---
|
||||
ret = iot_button_register_cb(btn_stop, BUTTON_SINGLE_CLICK, NULL, on_click_stop, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register STOP button click callback");
|
||||
ret = iot_button_register_cb(btn_stop, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_flip, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register FLIP button press callback");
|
||||
|
||||
// --- Register channel SELECT and SELECT_ALL ---
|
||||
ret = iot_button_register_cb(btn_select, BUTTON_SINGLE_CLICK, NULL, on_click_select, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register SELECT button click callback");
|
||||
ret = iot_button_register_cb(btn_select, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_select_all, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register SELECT_ALL press callback");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t init_led_indicators()
|
||||
{
|
||||
const int indicator_io_nums[CONFIG_RELAY_CHN_COUNT] = {
|
||||
CONFIG_EXAMPLE_RLCHN_LED_INDICATOR1_IO_NUM,
|
||||
CONFIG_EXAMPLE_RLCHN_LED_INDICATOR2_IO_NUM,
|
||||
CONFIG_EXAMPLE_RLCHN_LED_INDICATOR3_IO_NUM
|
||||
};
|
||||
|
||||
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||
gpio_num_t indicator_io_num = (gpio_num_t) indicator_io_nums[i];
|
||||
gpio_reset_pin(indicator_io_num); // Clear the output buffers
|
||||
|
||||
led_indicator_gpio_config_t led_indicator_gpio_cfg = {
|
||||
.gpio_num = indicator_io_num,
|
||||
.is_active_level_high = true
|
||||
};
|
||||
|
||||
led_indicator_config_t led_indicator_cfg = {
|
||||
.mode = LED_GPIO_MODE,
|
||||
.led_indicator_gpio_config = &led_indicator_gpio_cfg,
|
||||
.blink_lists = led_indicator_modes,
|
||||
.blink_list_num = INDICATOR_MODE_MAX
|
||||
};
|
||||
|
||||
indicators[i] = led_indicator_create(&led_indicator_cfg);
|
||||
if (!indicators[i]) {
|
||||
ESP_LOGE(TAG, "Failed to create LED indicator");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
10
examples/relay_chn_multi/sdkconfig.defaults
Normal file
10
examples/relay_chn_multi/sdkconfig.defaults
Normal file
@@ -0,0 +1,10 @@
|
||||
# Halt on panic
|
||||
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
|
||||
|
||||
# Relay Channel Configs
|
||||
CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT=y
|
||||
CONFIG_RELAY_CHN_COUNT=3
|
||||
# Keep this as short as possible for example purposes
|
||||
CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC=5
|
||||
CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC=20
|
||||
CONFIG_RELAY_CHN_ENABLE_TILTING=y
|
||||
6
examples/relay_chn_single/.gitignore
vendored
Normal file
6
examples/relay_chn_single/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
build/
|
||||
sdkconfig
|
||||
sdkconfig.old
|
||||
|
||||
# Exclude auto-populated settings file
|
||||
settings.json
|
||||
23
examples/relay_chn_single/.vscode/c_cpp_properties.json
vendored
Normal file
23
examples/relay_chn_single/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ESP-IDF",
|
||||
"compilerPath": "${config:idf.toolsPath}/tools/riscv32-esp-elf/esp-14.2.0_20241119/riscv32-esp-elf/bin/riscv32-esp-elf-gcc",
|
||||
"compileCommands": "/disk/Projeler/ESP-Components/relay_chn/examples/relay_chn_single/build/compile_commands.json",
|
||||
"includePath": [
|
||||
"${config:idf.espIdfPath}/components/**",
|
||||
"${config:idf.espIdfPathWin}/components/**",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${config:idf.espIdfPath}/components",
|
||||
"${config:idf.espIdfPathWin}/components",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
15
examples/relay_chn_single/.vscode/launch.json
vendored
Normal file
15
examples/relay_chn_single/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "gdbtarget",
|
||||
"request": "attach",
|
||||
"name": "Eclipse CDT GDB Adapter"
|
||||
},
|
||||
{
|
||||
"type": "espidf",
|
||||
"name": "Launch",
|
||||
"request": "launch"
|
||||
}
|
||||
]
|
||||
}
|
||||
10
examples/relay_chn_single/CMakeLists.txt
Normal file
10
examples/relay_chn_single/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five 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(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(relay_chn_single)
|
||||
126
examples/relay_chn_single/README.md
Normal file
126
examples/relay_chn_single/README.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Relay Channel Single Example
|
||||
|
||||
## Introduction
|
||||
|
||||
This example demonstrates how to use the relay channel component to control a 2-relay setup with button inputs and LED status indication. It showcases:
|
||||
|
||||
- Basic relay channel operations (forward/reverse running, stopping)
|
||||
- Secondary operations (tilting, direction flipping)
|
||||
- State change event handling with multiple listeners
|
||||
- Relay channel run limit
|
||||
- Button event handling using esp-iot-solution's button component
|
||||
- Visual feedback using esp-iot-solution's LED indicator component
|
||||
|
||||
## How to Use Example
|
||||
|
||||
This example has been tested on an `ESP32-C3-DevKitM-1U` board. However, it can be adapted to any ESP32-based board with at least six available GPIO pins by adjusting the configuration options.
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* An ESP32-based development board
|
||||
* 2 relays connected to GPIO pins (default: GPIO4, GPIO5)
|
||||
* 3 buttons connected to GPIO pins:
|
||||
- UP button (default: GPIO0)
|
||||
- DOWN button (default: GPIO1)
|
||||
- STOP button (default: GPIO2)
|
||||
* 1 LED for status indication (default: GPIO3)
|
||||
|
||||
#### Hardware Schematic
|
||||
|
||||

|
||||
|
||||
### Configuration
|
||||
|
||||
The example can be configured through `menuconfig` under "Relay Channel Single Example Configuration":
|
||||
|
||||
1. Button active level (`EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL`)
|
||||
- Select between active LOW or HIGH logic level for buttons
|
||||
|
||||
2. GPIO assignments:
|
||||
- UP button pin (`EXAMPLE_RLCHN_BTN_UP_IO_NUM`, default: 0)
|
||||
- DOWN button pin (`EXAMPLE_RLCHN_BTN_DOWN_IO_NUM`, default: 1)
|
||||
- STOP button pin (`EXAMPLE_RLCHN_BTN_STOP_IO_NUM`, default: 2)
|
||||
- LED indicator pin (`EXAMPLE_RLCHN_LED_INDICATOR_IO_NUM`, default: 3)
|
||||
|
||||
3. Long press timing:
|
||||
- `EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS`: Duration for long press actions (1500-3000ms, default: 2000ms)
|
||||
|
||||
### Button Operations
|
||||
|
||||
The example uses esp-iot-solution's `button` component to handle the following operations:
|
||||
|
||||
- **UP button**:
|
||||
* Short press: Start forward movement
|
||||
* Long press: Start forward tilt (stops on release)
|
||||
|
||||
- **DOWN button**:
|
||||
* Short press: Start reverse movement
|
||||
* Long press: Start reverse tilt (stops on release)
|
||||
|
||||
- **STOP button**:
|
||||
* Short press: Stop movement
|
||||
* Long press: Flip movement direction
|
||||
|
||||
### LED Indicator States
|
||||
|
||||
The example uses esp-iot-solution's `led_indicator` component to show different states:
|
||||
|
||||
- **Running**: LED blinks at 300ms on, 100ms off
|
||||
- **Tilting**: Fast blink at 100ms on, 50ms off
|
||||
- **Operation Success**: Two quick blinks
|
||||
- **Operation Fail**: One long blink
|
||||
|
||||
### Dependencies
|
||||
|
||||
This example requires:
|
||||
- ESP-IDF v4.1 or later
|
||||
- esp-iot-solution components:
|
||||
* button v4.1.1 or later
|
||||
* led_indicator v1.1.1 or later
|
||||
- relay_chn component
|
||||
|
||||
## Example Output
|
||||
When the application boots, it will wait for a button event. Then the two state listeners will print state changes.
|
||||
|
||||
```log
|
||||
I (273) main_task: Calling app_main()
|
||||
I (273) RELAY_CHN_SINGLE_EXAMPLE: Initializing default NVS storage
|
||||
I (283) RELAY_CHN_SINGLE_EXAMPLE: nvs_flash_init: NVS flash init return: ESP_OK
|
||||
I (283) RELAY_CHN_SINGLE_EXAMPLE: Initializing relay channel
|
||||
I (293) gpio: GPIO[4]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (303) gpio: GPIO[5]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (313) RELAY_CHN_SINGLE_EXAMPLE: Initializing buttons
|
||||
I (313) RELAY_CHN_SINGLE_EXAMPLE: Initializing buttons with active level: 0
|
||||
I (323) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (323) button: IoT Button Version: 4.1.3
|
||||
I (333) gpio: GPIO[1]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (343) gpio: GPIO[2]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (343) RELAY_CHN_SINGLE_EXAMPLE: Setting up button callbacks. Configured long press time: 2000 ms
|
||||
I (353) RELAY_CHN_SINGLE_EXAMPLE: Initializing LED indicator
|
||||
I (363) gpio: GPIO[3]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (373) led_indicator: LED Indicator Version: 1.1.1
|
||||
I (373) gpio: GPIO[3]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (383) led_indicator: Indicator create successfully. type:GPIO mode, hardware_data:0x3fc97be4, blink_lists:custom
|
||||
I (393) RELAY_CHN_SINGLE_EXAMPLE: Relay Channel Single Example is ready to operate
|
||||
I (403) main_task: Returned from app_main()
|
||||
I (3683) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 1 to 3
|
||||
I (3683) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from IDLE to FORWARD
|
||||
I (9513) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 3 to 2
|
||||
I (9513) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from FORWARD to STOPPED
|
||||
I (9523) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 2 to 6
|
||||
I (9533) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from STOPPED to REVERSE_PENDING
|
||||
I (10313) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 6 to 4
|
||||
I (10313) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from REVERSE_PENDING to REVERSE
|
||||
I (32173) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 4 to 2
|
||||
I (32173) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from REVERSE to STOPPED
|
||||
I (32973) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 2 to 1
|
||||
I (32973) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from STOPPED to IDLE
|
||||
I (36423) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 1 to 8
|
||||
I (36423) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from IDLE to TILT_REVERSE
|
||||
I (41153) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 8 to 1
|
||||
I (41153) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from TILT_REVERSE to IDLE
|
||||
I (47113) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 1 to 7
|
||||
I (47113) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from IDLE to TILT_FORWARD
|
||||
I (51913) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_1: Defining new indicator mode for #0 and state change from 7 to 1
|
||||
I (51913) RELAY_CHN_SINGLE_EXAMPLE: example_event_listener_2: State change for #0, from TILT_FORWARD to IDLE
|
||||
```
|
||||
BIN
examples/relay_chn_single/example_schematic.png
Normal file
BIN
examples/relay_chn_single/example_schematic.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
2
examples/relay_chn_single/main/CMakeLists.txt
Normal file
2
examples/relay_chn_single/main/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "relay_chn_single_main.c"
|
||||
PRIV_REQUIRES button led_indicator relay_chn)
|
||||
40
examples/relay_chn_single/main/Kconfig.projbuild
Normal file
40
examples/relay_chn_single/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,40 @@
|
||||
menu "Relay Channel Single Example Configuration"
|
||||
|
||||
choice EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL
|
||||
prompt "Choose an active level for buttons"
|
||||
default EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_LOW
|
||||
help
|
||||
Specify the active level for buttons.
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_LOW
|
||||
bool "Active level LOW"
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_HIGH
|
||||
bool "Active level HIGH"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_UP_IO_NUM
|
||||
int "GPIO number for UP button"
|
||||
default 0
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_DOWN_IO_NUM
|
||||
int "GPIO number for DOWN button"
|
||||
default 1
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_STOP_IO_NUM
|
||||
int "GPIO number for STOP button"
|
||||
default 2
|
||||
|
||||
config EXAMPLE_RLCHN_LED_INDICATOR_IO_NUM
|
||||
int "GPIO number for LED indicator output"
|
||||
default 3
|
||||
|
||||
config EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS
|
||||
int "Long press time in ms to start secondary actions"
|
||||
range 1500 3000
|
||||
default 2000
|
||||
help
|
||||
Long press time in milliseconds is required to start secondary actions
|
||||
like tilting and flipping.
|
||||
|
||||
endmenu
|
||||
8
examples/relay_chn_single/main/idf_component.yml
Normal file
8
examples/relay_chn_single/main/idf_component.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=4.1.0'
|
||||
espressif/button: ^4.1.1
|
||||
espressif/led_indicator: ^1.1.1
|
||||
relay_chn:
|
||||
version: '*'
|
||||
override_path: ../../../
|
||||
290
examples/relay_chn_single/main/relay_chn_single_main.c
Normal file
290
examples/relay_chn_single/main/relay_chn_single_main.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "button_gpio.h"
|
||||
#include "iot_button.h"
|
||||
#include "led_indicator.h"
|
||||
#include "relay_chn.h"
|
||||
|
||||
static const char *TAG = "RELAY_CHN_SINGLE_EXAMPLE";
|
||||
|
||||
/**
|
||||
* @brief LED indicator modes for different states.
|
||||
*/
|
||||
typedef enum {
|
||||
INDICATOR_MODE_OK, /*!< OK/Success indication */
|
||||
INDICATOR_MODE_FAIL, /*!< Fail/Error indication */
|
||||
INDICATOR_MODE_TILTING, /*!< Tilting operation in progress */
|
||||
INDICATOR_MODE_RUNNING, /*!< Full run operation in progress */
|
||||
INDICATOR_MODE_MAX /*!< Maximum number of indicator modes */
|
||||
} indicator_mode_t;
|
||||
|
||||
/** @brief Blink pattern for OK/Success indication. */
|
||||
static const blink_step_t indc_mode_ok[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step1: turn on LED 100 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step2: turn off LED 50 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step3: turn on LED 100 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step4: turn off LED 50 ms
|
||||
{LED_BLINK_STOP, 0, 0}, // step5: stop blink (off)
|
||||
};
|
||||
|
||||
/** @brief Blink pattern for Fail/Error indication. */
|
||||
static const blink_step_t indc_mode_fail[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 1000}, // step1: turn on LED 1000 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 500}, // step2: turn off LED 500 ms
|
||||
{LED_BLINK_STOP, 0, 0}, // step4: stop blink (off)
|
||||
};
|
||||
|
||||
/** @brief Blink pattern for full run operation. */
|
||||
static const blink_step_t indc_mode_running[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 300}, // step1: turn on LED 300 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 100}, // step2: turn off LED 100 ms
|
||||
{LED_BLINK_LOOP, 0, 0}, // step3: loop from step1
|
||||
};
|
||||
|
||||
/** @brief Blink pattern for tilting operation. */
|
||||
static const blink_step_t indc_mode_tilting[] = {
|
||||
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step1: turn on LED 100 ms
|
||||
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step2: turn off LED 50 ms
|
||||
{LED_BLINK_LOOP, 0, 0}, // step3: loop from step1
|
||||
};
|
||||
|
||||
/** @brief Array of LED indicator blink patterns. */
|
||||
blink_step_t const *led_indicator_modes[] = {
|
||||
[INDICATOR_MODE_OK] = indc_mode_ok,
|
||||
[INDICATOR_MODE_FAIL] = indc_mode_fail,
|
||||
[INDICATOR_MODE_RUNNING] = indc_mode_running,
|
||||
[INDICATOR_MODE_TILTING] = indc_mode_tilting,
|
||||
[INDICATOR_MODE_MAX] = NULL,
|
||||
};
|
||||
|
||||
/** @brief Handle for the LED indicator. */
|
||||
static led_indicator_handle_t indicator = NULL;
|
||||
|
||||
/**
|
||||
* @brief Initializes the buttons for user interaction.
|
||||
*
|
||||
* This function configures and creates GPIO buttons for UP, DOWN, and STOP
|
||||
* operations. It also registers callbacks for single-click and long-press
|
||||
* events to control the relay channel.
|
||||
*
|
||||
* @return esp_err_t
|
||||
* - ESP_OK: Success
|
||||
* - Others: Fail
|
||||
*/
|
||||
static esp_err_t init_buttons(void);
|
||||
|
||||
/**
|
||||
* @brief Initializes the LED indicator.
|
||||
*
|
||||
* This function configures and creates the LED indicator used to provide
|
||||
* visual feedback on the relay channel's status.
|
||||
*
|
||||
* @return esp_err_t
|
||||
* - ESP_OK: Success
|
||||
* - ESP_FAIL: Fail
|
||||
*/
|
||||
static esp_err_t init_led_indicator(void);
|
||||
|
||||
/**
|
||||
* @brief Event listener for relay channel state changes to control the LED indicator.
|
||||
*/
|
||||
static void example_event_listener_1(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||
|
||||
/**
|
||||
* @brief Event listener for relay channel state changes to log the state transition.
|
||||
*/
|
||||
static void example_event_listener_2(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
const uint8_t gpio_map[] = { 4, 5 };
|
||||
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||
|
||||
ESP_LOGI(TAG, "Initializing relay channel");
|
||||
ESP_ERROR_CHECK(relay_chn_create(gpio_map, gpio_count));
|
||||
ESP_ERROR_CHECK(relay_chn_register_listener(example_event_listener_1));
|
||||
ESP_ERROR_CHECK(relay_chn_register_listener(example_event_listener_2));
|
||||
|
||||
ESP_LOGI(TAG, "Initializing buttons");
|
||||
ESP_ERROR_CHECK(init_buttons());
|
||||
ESP_LOGI(TAG, "Initializing LED indicator");
|
||||
ESP_ERROR_CHECK(init_led_indicator());
|
||||
|
||||
ESP_LOGI(TAG, "Relay Channel Single Example is ready to operate");
|
||||
|
||||
// Indicate init was successful
|
||||
led_indicator_start(indicator, INDICATOR_MODE_OK);
|
||||
}
|
||||
|
||||
static void on_click_up(void *arg, void *data)
|
||||
{
|
||||
relay_chn_run_forward();
|
||||
}
|
||||
|
||||
static void on_click_down(void *arg, void *data)
|
||||
{
|
||||
relay_chn_run_reverse();
|
||||
}
|
||||
|
||||
static void on_click_stop(void *arg, void *data)
|
||||
{
|
||||
relay_chn_stop();
|
||||
}
|
||||
|
||||
static void on_click_flip(void *arg, void *data)
|
||||
{
|
||||
relay_chn_flip_direction();
|
||||
led_indicator_start(indicator, INDICATOR_MODE_OK);
|
||||
}
|
||||
|
||||
static void on_click_tilt_up(void *arg, void *data)
|
||||
{
|
||||
relay_chn_tilt_forward();
|
||||
}
|
||||
|
||||
static void on_click_tilt_down(void *arg, void *data)
|
||||
{
|
||||
relay_chn_tilt_reverse();
|
||||
}
|
||||
|
||||
static void on_release_tilt(void *arg, void *data)
|
||||
{
|
||||
relay_chn_tilt_stop();
|
||||
}
|
||||
|
||||
static void example_event_listener_1(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state)
|
||||
{
|
||||
ESP_LOGI(TAG, "example_event_listener_1: Defining new indicator mode for #%d and state change from %d to %d", ch, old_state, new_state);
|
||||
switch (new_state) {
|
||||
case RELAY_CHN_STATE_FORWARD:
|
||||
case RELAY_CHN_STATE_REVERSE:
|
||||
led_indicator_start(indicator, INDICATOR_MODE_RUNNING);
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_STOPPED:
|
||||
case RELAY_CHN_STATE_IDLE:
|
||||
if (old_state == RELAY_CHN_STATE_FORWARD || old_state == RELAY_CHN_STATE_REVERSE) {
|
||||
led_indicator_stop(indicator, INDICATOR_MODE_RUNNING);
|
||||
// Make sure the indicator turned off
|
||||
led_indicator_set_on_off(indicator, false);
|
||||
}
|
||||
else if (old_state == RELAY_CHN_STATE_TILT_FORWARD || old_state == RELAY_CHN_STATE_TILT_REVERSE) {
|
||||
led_indicator_stop(indicator, INDICATOR_MODE_TILTING);
|
||||
// Make sure the indicator turned off
|
||||
led_indicator_set_on_off(indicator, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_TILT_FORWARD:
|
||||
case RELAY_CHN_STATE_TILT_REVERSE:
|
||||
led_indicator_start(indicator, INDICATOR_MODE_TILTING);
|
||||
break;
|
||||
|
||||
default: // No-op
|
||||
}
|
||||
}
|
||||
|
||||
static void example_event_listener_2(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state)
|
||||
{
|
||||
ESP_LOGI(TAG, "example_event_listener_2: State change for #%d, from %s to %s",
|
||||
ch, relay_chn_state_to_str(old_state), relay_chn_state_to_str(new_state));
|
||||
}
|
||||
|
||||
static esp_err_t init_buttons()
|
||||
{
|
||||
esp_err_t ret;
|
||||
button_config_t btn_cfg = {0};
|
||||
|
||||
uint8_t active_level = CONFIG_EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_LOW ? 0 : 1;
|
||||
|
||||
button_gpio_config_t btn_gpio_ccfg = {
|
||||
.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_UP_IO_NUM,
|
||||
.active_level = active_level
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Initializing buttons with active level: %u", active_level);
|
||||
button_handle_t btn_up = NULL, btn_down = NULL, btn_stop = NULL;
|
||||
// --- Create buttons ---
|
||||
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_up);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create UP button");
|
||||
ESP_RETURN_ON_FALSE(btn_up != NULL, ret, TAG, "Failed to create UP button");
|
||||
|
||||
btn_gpio_ccfg.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_DOWN_IO_NUM;
|
||||
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_down);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create DOWN button");
|
||||
ESP_RETURN_ON_FALSE(btn_down != NULL, ret, TAG, "Failed to create DOWN button");
|
||||
|
||||
btn_gpio_ccfg.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_STOP_IO_NUM;
|
||||
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_stop);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create STOP button");
|
||||
ESP_RETURN_ON_FALSE(btn_stop != NULL, ret, TAG, "Failed to create STOP button");
|
||||
// --- Create buttons ---
|
||||
|
||||
// --- Register button callbacks ---
|
||||
ESP_LOGI(TAG, "Setting up button callbacks. Configured long press time: %d ms", CONFIG_EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS);
|
||||
button_event_args_t btn_event_args = {
|
||||
.long_press.press_time = CONFIG_EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS
|
||||
};
|
||||
// --- Register UP and TILT_UP operations on UP button ---
|
||||
ret = iot_button_register_cb(btn_up, BUTTON_SINGLE_CLICK, NULL, on_click_up, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register UP button click callback");
|
||||
ret = iot_button_register_cb(btn_up, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_tilt_up, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_UP button press callback");
|
||||
ret = iot_button_register_cb(btn_up, BUTTON_LONG_PRESS_UP, NULL, on_release_tilt, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_UP button release callback");
|
||||
|
||||
// --- Register DOWN and TILT_DOWN operations on DOWN button ---
|
||||
ret = iot_button_register_cb(btn_down, BUTTON_SINGLE_CLICK, NULL, on_click_down, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register DOWN button click callback");
|
||||
ret = iot_button_register_cb(btn_down, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_tilt_down, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_DOWN button press callback");
|
||||
ret = iot_button_register_cb(btn_down, BUTTON_LONG_PRESS_UP, NULL, on_release_tilt, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_DOWN button release callback");
|
||||
|
||||
// --- Register STOP and FLIP operations on STOP ---
|
||||
ret = iot_button_register_cb(btn_stop, BUTTON_SINGLE_CLICK, NULL, on_click_stop, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register STOP button click callback");
|
||||
ret = iot_button_register_cb(btn_stop, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_flip, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register FLIP button press callback");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t init_led_indicator()
|
||||
{
|
||||
const gpio_num_t indicator_io_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_LED_INDICATOR_IO_NUM;
|
||||
gpio_reset_pin(indicator_io_num); // Clear the output buffers
|
||||
|
||||
led_indicator_gpio_config_t led_indicator_gpio_cfg = {
|
||||
.gpio_num = indicator_io_num,
|
||||
.is_active_level_high = true
|
||||
};
|
||||
|
||||
led_indicator_config_t led_indicator_cfg = {
|
||||
.mode = LED_GPIO_MODE,
|
||||
.led_indicator_gpio_config = &led_indicator_gpio_cfg,
|
||||
.blink_lists = led_indicator_modes,
|
||||
.blink_list_num = INDICATOR_MODE_MAX
|
||||
};
|
||||
|
||||
indicator = led_indicator_create(&led_indicator_cfg);
|
||||
if (!indicator) {
|
||||
ESP_LOGE(TAG, "Failed to create LED indicator");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
9
examples/relay_chn_single/sdkconfig.defaults
Normal file
9
examples/relay_chn_single/sdkconfig.defaults
Normal file
@@ -0,0 +1,9 @@
|
||||
# Halt on panic
|
||||
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
|
||||
|
||||
# Relay Channel Configs
|
||||
CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT=y
|
||||
# Keep this as short as possible for example purposes
|
||||
CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC=5
|
||||
CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC=20
|
||||
CONFIG_RELAY_CHN_ENABLE_TILTING=y
|
||||
@@ -1,6 +1,12 @@
|
||||
name: relay_chn
|
||||
version: "0.5.0"
|
||||
description: "Custom component for relay channel control"
|
||||
version: "1.0.0"
|
||||
description: "Relay channel driver for bipolar motors."
|
||||
license: "MIT"
|
||||
url: "https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn"
|
||||
repository: "https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn.git"
|
||||
repository: "https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn.git"
|
||||
dependencies:
|
||||
idf: ">=5.0"
|
||||
examples:
|
||||
- path: examples/relay_chn_single
|
||||
- path: examples/relay_chn_multi
|
||||
files:
|
||||
use_gitignore: true
|
||||
@@ -63,6 +63,14 @@ esp_err_t relay_chn_register_listener(relay_chn_state_listener_t listener);
|
||||
*/
|
||||
void relay_chn_unregister_listener(relay_chn_state_listener_t listener);
|
||||
|
||||
/**
|
||||
* @brief Return the text presentation of an state.
|
||||
*
|
||||
* @param state A state with type of relay_chn_state_t.
|
||||
* @return char* The text presentation of the state. "UNKNOWN" if the state is not known.
|
||||
*/
|
||||
char *relay_chn_state_to_str(relay_chn_state_t state);
|
||||
|
||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||
/**
|
||||
* @brief Get the default tilting sensitivity for the relay channel.
|
||||
|
||||
@@ -93,14 +93,6 @@ esp_err_t relay_chn_start_esp_timer_once(esp_timer_handle_t esp_timer, uint32_t
|
||||
*/
|
||||
void relay_chn_update_state(relay_chn_ctl_t *chn_ctl, relay_chn_state_t new_state);
|
||||
|
||||
/**
|
||||
* @brief Return the text presentation of an state.
|
||||
*
|
||||
* @param state A state with type of relay_chn_state_t.
|
||||
* @return char* The text presentation of the state. "UNKNOWN" if the state is not known.
|
||||
*/
|
||||
char *relay_chn_state_str(relay_chn_state_t state);
|
||||
|
||||
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||
/**
|
||||
* @brief Check if the provided channel ID is valid.
|
||||
|
||||
@@ -98,8 +98,7 @@ fi
|
||||
script_dir=$(dirname "$(readlink -f "$0")")
|
||||
project_root=$(dirname "$script_dir")
|
||||
|
||||
echo "🔍 Searching for 'test_apps' directory in '$project_root'..."
|
||||
test_apps_dir=$(find "$project_root" -type d -name "test_apps" | head -n 1)
|
||||
test_apps_dir="${project_root}/test_apps"
|
||||
|
||||
if [[ -z "$test_apps_dir" || ! -d "$test_apps_dir" ]]; then
|
||||
echo "❌ 'test_apps' directory not found within the project root: '$project_root'"
|
||||
@@ -107,7 +106,7 @@ if [[ -z "$test_apps_dir" || ! -d "$test_apps_dir" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Found 'test_apps' at: $test_apps_dir"
|
||||
echo "⏳ Current time is: $(date +"%Y-%m-%d %H:%M:%S")"
|
||||
echo "🧪 Test mode: $arg_tag | Profile: $arg_profile"
|
||||
echo "🧹 Clean: $arg_clean | 📄 Log: $arg_log"
|
||||
|
||||
|
||||
@@ -14,10 +14,15 @@ project_root=$(dirname "$script_dir")
|
||||
echo "Script dir: ${script_dir}"
|
||||
echo "Project root: ${project_root}"
|
||||
|
||||
echo "🔍 Searching for 'test_apps' directory in '$project_root'..."
|
||||
test_apps_dir=$(find "$project_root" -type d -name "test_apps" | head -n 1)
|
||||
test_apps_dir="${project_root}/test_apps"
|
||||
echo "test_apps dir: ${test_apps_dir}"
|
||||
|
||||
if [[ -z "$test_apps_dir" || ! -d "$test_apps_dir" ]]; then
|
||||
echo "❌ 'test_apps' directory not found within the project root: '$project_root'"
|
||||
echo " Please ensure the script is in a 'scripts' directory and 'test_apps' is a sibling."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Execute tests for all profiles
|
||||
mapfile -t profiles < <(find "${test_apps_dir}/profiles" -maxdepth 1 -type f)
|
||||
|
||||
|
||||
@@ -216,8 +216,8 @@ void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd)
|
||||
}
|
||||
|
||||
if (cmd == RELAY_CHN_CMD_STOP) {
|
||||
if (chn_ctl->state == RELAY_CHN_STATE_STOPPED) {
|
||||
return; // Do nothing if already stopped
|
||||
if (chn_ctl->state == RELAY_CHN_STATE_STOPPED || chn_ctl->state == RELAY_CHN_STATE_IDLE) {
|
||||
return; // Do nothing if already stopped or idle
|
||||
}
|
||||
// If the command is STOP, issue it immediately
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
@@ -471,7 +471,7 @@ char *relay_chn_cmd_str(relay_chn_cmd_t cmd)
|
||||
}
|
||||
}
|
||||
|
||||
char *relay_chn_state_str(relay_chn_state_t state)
|
||||
char *relay_chn_state_to_str(relay_chn_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case RELAY_CHN_STATE_IDLE:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "relay_chn.h"
|
||||
#include "relay_chn_priv_types.h"
|
||||
#include "relay_chn_core.h"
|
||||
#include "relay_chn_ctl.h"
|
||||
@@ -92,8 +93,8 @@ esp_err_t relay_chn_ctl_get_state_all(relay_chn_state_t *states)
|
||||
char *relay_chn_ctl_get_state_str(uint8_t chn_id)
|
||||
{
|
||||
return relay_chn_is_channel_id_valid(chn_id)
|
||||
? relay_chn_state_str(s_chn_ctls[chn_id].state)
|
||||
: relay_chn_state_str(RELAY_CHN_STATE_UNDEFINED);
|
||||
? relay_chn_state_to_str(s_chn_ctls[chn_id].state)
|
||||
: relay_chn_state_to_str(RELAY_CHN_STATE_UNDEFINED);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "relay_chn.h"
|
||||
#include "relay_chn_priv_types.h"
|
||||
#include "relay_chn_core.h"
|
||||
#include "relay_chn_ctl.h"
|
||||
@@ -14,7 +15,7 @@
|
||||
#include "relay_chn_nvs.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "RELAY_CHN_CTL";
|
||||
static const char *TAG __attribute__((unused)) = "RELAY_CHN_CTL";
|
||||
|
||||
static relay_chn_ctl_t s_chn_ctl;
|
||||
|
||||
@@ -65,7 +66,7 @@ relay_chn_state_t relay_chn_ctl_get_state()
|
||||
|
||||
char *relay_chn_ctl_get_state_str()
|
||||
{
|
||||
return relay_chn_state_str(s_chn_ctl.state);
|
||||
return relay_chn_state_to_str(s_chn_ctl.state);
|
||||
}
|
||||
|
||||
void relay_chn_ctl_run_forward()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "relay_chn.h"
|
||||
#include "relay_chn_core.h"
|
||||
#include "relay_chn_output.h"
|
||||
#include "relay_chn_run_info.h"
|
||||
@@ -103,16 +104,47 @@ static void relay_chn_tilt_start_timer_or_stop(relay_chn_tilt_ctl_t *tilt_ctl, e
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the relay channel can perform the current tilt command.
|
||||
*
|
||||
* This function evaluates whether a tilt command can be executed based on the
|
||||
* channel's history. The rules are as follows:
|
||||
* - Tilting in the same direction as the last full run command (e.g., TILT_FORWARD
|
||||
* after a FORWARD run) is always allowed.
|
||||
* - Tilting in the opposite direction of the last full run (e.g., TILT_REVERSE
|
||||
* after a FORWARD run) is only allowed if the tilt counter is greater than zero,
|
||||
* which indicates that the channel has previously tilted in the primary direction.
|
||||
* - If the channel has not been run before, tilting is not allowed.
|
||||
*
|
||||
* @param tilt_ctl Pointer to the tilt control structure for the channel.
|
||||
* @param tilt_cmd The tilt command to check against.
|
||||
*
|
||||
* @return true if the tilt command is allowed, false otherwise.
|
||||
*/
|
||||
static bool relay_chn_can_perform_tilt_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t tilt_cmd)
|
||||
{
|
||||
relay_chn_cmd_t last_run_cmd = relay_chn_run_info_get_last_run_cmd(tilt_ctl->chn_ctl->run_info);
|
||||
if (last_run_cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
return (tilt_cmd == RELAY_CHN_TILT_CMD_FORWARD) ||
|
||||
(tilt_cmd == RELAY_CHN_TILT_CMD_REVERSE && tilt_ctl->tilt_count > 0);
|
||||
} else if (last_run_cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
return (tilt_cmd == RELAY_CHN_TILT_CMD_REVERSE) ||
|
||||
(tilt_cmd == RELAY_CHN_TILT_CMD_FORWARD && tilt_ctl->tilt_count > 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Issue a tilt command to a specific relay channel.
|
||||
static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd)
|
||||
{
|
||||
// TILT_STOP is safe and high priority
|
||||
if (cmd == RELAY_CHN_TILT_CMD_STOP) {
|
||||
if (tilt_ctl->chn_ctl->state == RELAY_CHN_STATE_STOPPED) {
|
||||
return; // Do nothing if already stopped
|
||||
relay_chn_state_t state = tilt_ctl->chn_ctl->state;
|
||||
if (state == RELAY_CHN_STATE_TILT_FORWARD || state == RELAY_CHN_STATE_TILT_REVERSE) {
|
||||
// If the command is TILT_STOP, issue it immediately
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, cmd);
|
||||
}
|
||||
// If the command is TILT_STOP, issue it immediately
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -127,6 +159,11 @@ static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_t
|
||||
return;
|
||||
}
|
||||
|
||||
if (!relay_chn_can_perform_tilt_cmd(tilt_ctl, cmd)) {
|
||||
ESP_LOGD(TAG, "Cannot perform tilt command: %d for #%d", cmd, tilt_ctl->chn_ctl->id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the command that will be processed
|
||||
tilt_ctl->cmd = cmd;
|
||||
switch (tilt_ctl->chn_ctl->state) {
|
||||
@@ -184,7 +221,7 @@ static void relay_chn_tilt_issue_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_t
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_issue_cmd: Unexpected relay channel state: %s!", relay_chn_state_str(tilt_ctl->chn_ctl->state));
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_issue_cmd: Unexpected relay channel state: %s!", relay_chn_state_to_str(tilt_ctl->chn_ctl->state));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +291,7 @@ void relay_chn_tilt_reverse_all()
|
||||
|
||||
void relay_chn_tilt_stop(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
if (relay_chn_is_channel_id_valid(chn_id)) {
|
||||
relay_chn_tilt_dispatch_cmd(&s_tilt_ctls[chn_id], RELAY_CHN_TILT_CMD_STOP);
|
||||
}
|
||||
}
|
||||
@@ -283,7 +320,7 @@ void relay_chn_tilt_reverse()
|
||||
|
||||
void relay_chn_tilt_stop()
|
||||
{
|
||||
relay_chn_tilt_dispatch_cmd(&s_tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
relay_chn_tilt_issue_cmd(&s_tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
}
|
||||
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
||||
|
||||
|
||||
@@ -21,14 +21,13 @@
|
||||
void check_all_channels_for_state(relay_chn_state_t state)
|
||||
{
|
||||
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||
// ESP_LOGI(TEST_TAG, "Checking channel %d for state %d", i, state);
|
||||
TEST_ASSERT_EQUAL(state, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to prepare channel for tilt tests
|
||||
void prepare_channels_for_tilt_with_mixed_runs() {
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
|
||||
// Ensure the channel has had a 'last_run_cmd'
|
||||
@@ -40,16 +39,19 @@ void prepare_channels_for_tilt_with_mixed_runs() {
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow command to process
|
||||
relay_chn_stop_all(); // Stop it to set last_run_cmd but return to FREE for next test
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_state_t expect_state;
|
||||
if (i % 2 == 0) {
|
||||
expect_state = RELAY_CHN_STATE_FORWARD;
|
||||
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
||||
expect_state = RELAY_CHN_STATE_REVERSE;
|
||||
}
|
||||
TEST_ASSERT_EQUAL(expect_state, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to prepare channel for tilt tests
|
||||
void prepare_all_channels_for_tilt(int initial_cmd) {
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
|
||||
// If the channels are not IDLE yet, wait more
|
||||
@@ -64,6 +66,8 @@ void prepare_all_channels_for_tilt(int initial_cmd) {
|
||||
if (not_idle) {
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS));
|
||||
}
|
||||
// Ensure all channels are IDLE
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||
|
||||
// Ensure the channel has had a 'last_run_cmd'
|
||||
if (initial_cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
@@ -71,20 +75,17 @@ void prepare_all_channels_for_tilt(int initial_cmd) {
|
||||
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
||||
relay_chn_run_reverse_all();
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow command to process
|
||||
relay_chn_stop_all(); // Stop all to set last_run_cmd but return to FREE for next test
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||
relay_chn_state_t expect_state = initial_cmd == RELAY_CHN_CMD_FORWARD
|
||||
? RELAY_CHN_STATE_FORWARD : RELAY_CHN_STATE_REVERSE;
|
||||
check_all_channels_for_state(expect_state);
|
||||
ESP_LOGI(TEST_TAG, "All channels prepared for tilt test");
|
||||
}
|
||||
|
||||
// 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]")
|
||||
{
|
||||
// Prepare channel by running forward first to set last_run_cmd
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
|
||||
// 1. Start in forward direction
|
||||
relay_chn_run_forward_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
@@ -99,15 +100,15 @@ TEST_CASE("Run Forward to Tilt Forward transition with inertia", "[relay_chn][ti
|
||||
// Wait for the inertia period (after which the tilt command will be dispatched)
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// 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]")
|
||||
{
|
||||
// Prepare channel by running reverse first to set last_run_cmd
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
|
||||
// 1. Start in reverse direction
|
||||
relay_chn_run_reverse_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
@@ -120,6 +121,9 @@ TEST_CASE("Run Reverse to Tilt Reverse transition with inertia", "[relay_chn][ti
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from FREE state to tilt forward (now with preparation)
|
||||
@@ -128,12 +132,19 @@ TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn
|
||||
{
|
||||
// Prepare channel by running forward first to set last_run_cmd
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_stop_all(); // Stop to trigger IDLE
|
||||
// Wait for the channel to transition to IDLE
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_IDLE); // Ensure we are back to IDLE
|
||||
|
||||
// Issue tilt forward command
|
||||
relay_chn_tilt_forward_all();
|
||||
// From FREE state, tilt command should still incur the inertia due to the internal timer logic
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from FREE state to tilt reverse (now with preparation)
|
||||
@@ -142,11 +153,18 @@ TEST_CASE("FREE to Tilt Reverse transition with inertia (prepared)", "[relay_chn
|
||||
{
|
||||
// Prepare channel by running reverse first to set last_run_cmd
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
relay_chn_stop_all(); // Stop to trigger IDLE
|
||||
// Wait for the channel to transition to IDLE
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_IDLE); // Ensure we are back to IDLE
|
||||
|
||||
// Issue tilt reverse command
|
||||
relay_chn_tilt_reverse_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from tilt forward to run forward (inertia expected for run)
|
||||
@@ -165,6 +183,9 @@ TEST_CASE("Tilt Forward to Run Forward transition with inertia", "[relay_chn][ti
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_FORWARD_PENDING);
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_FORWARD);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from tilt reverse to run reverse (no inertia expected for run)
|
||||
@@ -182,6 +203,9 @@ TEST_CASE("Tilt Reverse to Run Reverse transition with inertia", "[relay_chn][ti
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE_PENDING);
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from tilt forward to run reverse (without inertia)
|
||||
@@ -198,6 +222,9 @@ TEST_CASE("Tilt Forward to Run Reverse transition without inertia", "[relay_chn]
|
||||
relay_chn_run_reverse_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// TEST_CASE: Test stopping from a tilt state (no inertia for stop command itself)
|
||||
@@ -228,10 +255,14 @@ TEST_CASE("tilt_forward_all sets all channels to TILT_FORWARD", "[relay_chn][til
|
||||
|
||||
// 2. Issue tilt forward to all channels
|
||||
relay_chn_tilt_forward_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Tilt from FREE doesn't have stop-inertia
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
|
||||
// 3. Verify all channels are tilting forward
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
TEST_CASE("tilt_reverse_all sets all channels to TILT_REVERSE", "[relay_chn][tilt][batch]")
|
||||
@@ -241,10 +272,14 @@ TEST_CASE("tilt_reverse_all sets all channels to TILT_REVERSE", "[relay_chn][til
|
||||
|
||||
// 2. Issue tilt reverse to all channels
|
||||
relay_chn_tilt_reverse_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
|
||||
// 3. Verify all channels are tilting reverse
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
TEST_CASE("tilt_stop_all stops all tilting channels", "[relay_chn][tilt][batch]")
|
||||
@@ -253,7 +288,10 @@ TEST_CASE("tilt_stop_all stops all tilting channels", "[relay_chn][tilt][batch]"
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
|
||||
relay_chn_tilt_forward_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
// 3. Verify all channels are tilting forward
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||
|
||||
// 2. Stop tilting on all channels
|
||||
relay_chn_tilt_stop_all();
|
||||
@@ -265,15 +303,13 @@ TEST_CASE("tilt_stop_all stops all tilting channels", "[relay_chn][tilt][batch]"
|
||||
|
||||
TEST_CASE("tilt_auto_all tilts channels based on last run direction", "[relay_chn][tilt][batch]")
|
||||
{
|
||||
// This test requires at least 2 channels to demonstrate different behaviors
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(2, CONFIG_RELAY_CHN_COUNT, "Test requires at least 2 channels");
|
||||
|
||||
// 1. Prepare channel 0 with last run FORWARD and channel 1 with last run REVERSE
|
||||
prepare_channels_for_tilt_with_mixed_runs();
|
||||
|
||||
// 2. Issue auto tilt command to all channels
|
||||
relay_chn_tilt_auto_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Tilt from FREE state is dispatched immediately
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
|
||||
// 3. Verify even channels tilt forward (last run was forward) and odd channels tilt reverse (last run was reverse)
|
||||
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
||||
@@ -282,6 +318,9 @@ TEST_CASE("tilt_auto_all tilts channels based on last run direction", "[relay_ch
|
||||
|
||||
TEST_ASSERT_EQUAL(state, relay_chn_get_state(i));
|
||||
}
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// Test relay_chn_tilt_auto() chooses correct tilt direction
|
||||
@@ -290,19 +329,24 @@ TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][au
|
||||
// Prepare FORWARD
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_auto_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
// Verify all tilt forward
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
|
||||
// Prepare REVERSE
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
relay_chn_tilt_auto_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
// Verify all tilt reverse
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||
|
||||
// Ensure the channel reset tilt control
|
||||
relay_chn_tilt_stop_all();
|
||||
}
|
||||
|
||||
// Test sensitivity set/get
|
||||
@@ -375,7 +419,14 @@ TEST_CASE("tilt counter logic: forward and reverse consumption", "[relay_chn][ti
|
||||
#define TEST_TILT_EXECUTION_TIME_MS 100
|
||||
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
|
||||
relay_chn_tilt_set_sensitivity_all_with(100); // Set sentivity to max for fastest execution
|
||||
// Ensure sensitivities are set correctly
|
||||
uint8_t sensitivities[CONFIG_RELAY_CHN_COUNT];
|
||||
uint8_t expect[CONFIG_RELAY_CHN_COUNT];
|
||||
memset(expect, 100, CONFIG_RELAY_CHN_COUNT);
|
||||
relay_chn_tilt_get_sensitivity_all(sensitivities);
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(expect, sensitivities, CONFIG_RELAY_CHN_COUNT);
|
||||
|
||||
// Tilt forward 3 times
|
||||
relay_chn_tilt_forward_all();
|
||||
@@ -393,12 +444,12 @@ TEST_CASE("tilt counter logic: forward and reverse consumption", "[relay_chn][ti
|
||||
|
||||
// Now tilt reverse 3 times (should succeed)
|
||||
relay_chn_tilt_reverse_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS * 3 + TEST_DELAY_MARGIN_MS));
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_REVERSE);
|
||||
|
||||
// One more reverse tilt should fail (counter exhausted)
|
||||
// Let it execute 2 at least, or more
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS * 3));
|
||||
// Should not enter TILT_REVERSE, should remain IDLE
|
||||
|
||||
// More reverse tilt should fail (counter exhausted)
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_IDLE);
|
||||
}
|
||||
|
||||
@@ -423,12 +474,12 @@ TEST_CASE("run_all command during active tilt cycle stops tilt", "[relay_chn][ti
|
||||
// Set a known sensitivity for predictable timing.
|
||||
// For sensitivity=50, move_time=30ms, pause_time=270ms.
|
||||
relay_chn_tilt_set_sensitivity_all_with(50);
|
||||
const uint32_t move_time_ms = 30;
|
||||
|
||||
// --- Test interrupting during MOVE step ---
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_forward_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(move_time_ms / 2)); // Wait for half of the move time
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||
|
||||
// Interrupt with run_reverse_all while in the MOVE part of the cycle
|
||||
@@ -438,9 +489,12 @@ TEST_CASE("run_all command during active tilt cycle stops tilt", "[relay_chn][ti
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_REVERSE);
|
||||
|
||||
// --- Test interrupting during PAUSE step ---
|
||||
relay_chn_stop_all(); // Stop the reverse runs
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
prepare_all_channels_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_forward_all();
|
||||
vTaskDelay(pdMS_TO_TICKS(move_time_ms + TEST_DELAY_MARGIN_MS)); // Wait past MOVE, into PAUSE
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS)); // Wait past MOVE, into PAUSE
|
||||
check_all_channels_for_state(RELAY_CHN_STATE_TILT_FORWARD);
|
||||
|
||||
// Interrupt with run_forward_all while in the PAUSE part of the cycle
|
||||
|
||||
@@ -30,19 +30,15 @@ void prepare_channel_for_tilt(int initial_cmd) {
|
||||
} else { // Assuming initial_cmd is RELAY_CHN_CMD_REVERSE
|
||||
relay_chn_run_reverse();
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS)); // Allow command to process
|
||||
relay_chn_stop(); // Stop it to set last_run_cmd but return to FREE for next test
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||
relay_chn_state_t expect_state = initial_cmd == RELAY_CHN_CMD_FORWARD ? RELAY_CHN_STATE_FORWARD : RELAY_CHN_STATE_REVERSE;
|
||||
TEST_ASSERT_EQUAL(expect_state, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// 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]")
|
||||
{
|
||||
// Prepare channel by running forward first to set last_run_cmd
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
|
||||
// 1. Start in forward direction
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
@@ -63,9 +59,6 @@ TEST_CASE("Run Forward to Tilt Forward transition with inertia", "[relay_chn][ti
|
||||
// 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]")
|
||||
{
|
||||
// Prepare channel by running reverse first to set last_run_cmd
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
|
||||
// 1. Start in reverse direction
|
||||
relay_chn_run_reverse();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
@@ -86,6 +79,9 @@ TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn
|
||||
{
|
||||
// Prepare channel by running forward first to set last_run_cmd
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_stop(); // Stop to trigger IDLE
|
||||
// Wait for the channel to transition to IDLE
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); // Ensure we are back to FREE
|
||||
|
||||
// Issue tilt forward command
|
||||
@@ -101,6 +97,9 @@ TEST_CASE("FREE to Tilt Reverse transition with inertia (prepared)", "[relay_chn
|
||||
{
|
||||
// Prepare channel by running reverse first to set last_run_cmd
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
relay_chn_stop(); // Stop to trigger IDLE
|
||||
// Wait for the channel to transition to IDLE
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); // Ensure we are back to FREE
|
||||
|
||||
// Issue tilt reverse command
|
||||
@@ -183,7 +182,8 @@ TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][au
|
||||
// Prepare FORWARD
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_auto();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
relay_chn_tilt_stop();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
@@ -191,7 +191,8 @@ TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][au
|
||||
// Prepare REVERSE
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
relay_chn_tilt_auto();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
@@ -237,31 +238,25 @@ TEST_CASE("relay_chn_tilt_set_sensitivity handles upper boundary", "[relay_chn][
|
||||
// Test tilt counter logic: forward x3, reverse x3, extra reverse fails
|
||||
TEST_CASE("tilt counter logic: forward and reverse consumption", "[relay_chn][tilt][counter]")
|
||||
{
|
||||
// Tilt execution time at 100% sensitivity in milliseconds (10 + 90)
|
||||
#define TEST_TILT_EXECUTION_TIME_MS 100
|
||||
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
|
||||
// Tilt forward 3 times
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
relay_chn_tilt_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
relay_chn_tilt_stop();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
}
|
||||
relay_chn_tilt_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS * 3 + TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
relay_chn_tilt_stop();
|
||||
|
||||
// Now tilt reverse 3 times (should succeed)
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
relay_chn_tilt_reverse();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
if (i < 3) {
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||
relay_chn_tilt_stop();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
}
|
||||
}
|
||||
|
||||
// Extra reverse tilt should fail (counter exhausted)
|
||||
relay_chn_tilt_reverse();
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_MARGIN_MS));
|
||||
// Let it execute one time
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||
// Let it execute 2 at least, or more
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_TILT_EXECUTION_TIME_MS * 3));
|
||||
|
||||
// Should not enter TILT_REVERSE, should remain FREE or STOPPED
|
||||
relay_chn_state_t state = relay_chn_get_state();
|
||||
TEST_ASSERT(state != RELAY_CHN_STATE_TILT_REVERSE);
|
||||
@@ -289,12 +284,12 @@ TEST_CASE("run command during active tilt cycle stops tilt", "[relay_chn][tilt][
|
||||
// Set a known sensitivity for predictable timing.
|
||||
// For sensitivity=50, move_time=30ms, pause_time=270ms.
|
||||
relay_chn_tilt_set_sensitivity(50);
|
||||
const uint32_t move_time_ms = 30;
|
||||
|
||||
// --- Test interrupting during MOVE step ---
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(move_time_ms / 2)); // Wait for half of the move time
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
|
||||
// Interrupt with run_reverse while in the MOVE part of the cycle
|
||||
@@ -304,9 +299,14 @@ TEST_CASE("run command during active tilt cycle stops tilt", "[relay_chn][tilt][
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||
|
||||
// --- Test interrupting during PAUSE step ---
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_stop(); // Stop the reverse run
|
||||
// Wait the channel to be IDLE
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD); // Prepare channel again
|
||||
relay_chn_tilt_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(move_time_ms + TEST_DELAY_MARGIN_MS)); // Wait past MOVE, into PAUSE
|
||||
// Should incur inertia timer
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS + TEST_DELAY_MARGIN_MS));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
|
||||
// Interrupt with run_forward while in the PAUSE part of the cycle
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Disable task WDT for tests
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
|
||||
CONFIG_LOG_MAXIMUM_LEVEL_DEBUG=y
|
||||
CONFIG_LOG_MAXIMUM_LEVEL=4
|
||||
|
||||
# Relay Channel Driver Default Configuration for Testing
|
||||
# Keep this as short as possible for tests
|
||||
CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user