Compare commits
8 Commits
22668b6759
...
b29768edad
| Author | SHA1 | Date | |
|---|---|---|---|
| b29768edad | |||
|
f1cda4531d
|
|||
|
f8d6e74f23
|
|||
|
9f1134763e
|
|||
|
61f8ed440e
|
|||
| 1776c81c8d | |||
| 2165e9d571 | |||
| c0c7fbf3df |
21
.vscode/settings.json
vendored
21
.vscode/settings.json
vendored
@@ -1,6 +1,23 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"relay_chn.h": "c"
|
||||
"relay_chn.h": "c",
|
||||
"stdlib.h": "c",
|
||||
"cstdint": "c",
|
||||
"relay_chn_run_info.h": "c",
|
||||
"esp_err.h": "c",
|
||||
"relay_chn_output.h": "c",
|
||||
"relay_chn_core.h": "c",
|
||||
"relay_chn_ctl.h": "c",
|
||||
"relay_chn_tilt.h": "c",
|
||||
"relay_chn_defs.h": "c",
|
||||
"esp_check.h": "c",
|
||||
"esp_event_base.h": "c",
|
||||
"esp_event.h": "c",
|
||||
"queue.h": "c",
|
||||
"relay_chn_priv_types.h": "c",
|
||||
"relay_chn_adapter.h": "c",
|
||||
"relay_chn_types.h": "c"
|
||||
},
|
||||
"idf.port": "/dev/ttyUSB0"
|
||||
"idf.port": "/dev/ttyUSB0",
|
||||
"idf.pythonInstallPath": "/usr/bin/python"
|
||||
}
|
||||
@@ -1,4 +1,21 @@
|
||||
idf_component_register(SRCS "src/relay_chn.c"
|
||||
INCLUDE_DIRS include
|
||||
REQUIRES driver
|
||||
PRIV_REQUIRES esp_timer esp_event)
|
||||
set(include_dirs "include")
|
||||
set(priv_include_dirs "private_include")
|
||||
|
||||
set(srcs "src/relay_chn_core.c"
|
||||
"src/relay_chn_output.c"
|
||||
"src/relay_chn_run_info.c")
|
||||
|
||||
if(CONFIG_RELAY_CHN_ENABLE_TILTING)
|
||||
list(APPEND srcs "src/relay_chn_tilt.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_RELAY_CHN_COUNT GREATER 1)
|
||||
list(APPEND srcs "src/relay_chn_ctl_multi.c")
|
||||
else()
|
||||
list(APPEND srcs "src/relay_chn_ctl_single.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${include_dirs}
|
||||
PRIV_INCLUDE_DIRS ${priv_include_dirs}
|
||||
REQUIRES driver esp_timer esp_event)
|
||||
|
||||
138
README.md
138
README.md
@@ -43,11 +43,28 @@ dependencies:
|
||||
|
||||
## Usage
|
||||
|
||||
The `relay_chn` component can be used in two different modes, which are determined by the 'CONFIG_RELAY_CHN_COUNT' configuration:
|
||||
|
||||
- Single channel mode (`CONFIG_RELAY_CHN_COUNT == 1`)
|
||||
- Multi channel mode (`CONFIG_RELAY_CHN_COUNT > 1`)
|
||||
|
||||
Depending on the mode, the component will be built selectively, so the signatures of some available API functions may vary, either including or excluding a channel ID parameter:
|
||||
|
||||
```c
|
||||
relay_chn_run_forward(); // No channel ID parameter for single channel mode
|
||||
// or
|
||||
relay_chn_run_forward(2); // Channel ID parameters will be needed in multi channel mode
|
||||
```
|
||||
|
||||
See the examples for further reference
|
||||
|
||||
### 1. Initialize relay channels
|
||||
|
||||
```c
|
||||
// Define GPIO pins for relay channels
|
||||
const gpio_num_t gpio_map[] = {GPIO_NUM_4, GPIO_NUM_5}; // One channel example
|
||||
const uint8_t gpio_map[] = {4, 5}; // One channel example
|
||||
/*------------------------------------------------------------------------*/
|
||||
const uint8_t gpio_map[] = {4, 5, 9, 10, 18, 19}; // Or a 3 channel example
|
||||
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||
|
||||
// Create and initialize relay channels
|
||||
@@ -59,53 +76,138 @@ if (ret != ESP_OK) {
|
||||
|
||||
### 2. Control relay channels
|
||||
|
||||
For single mode:
|
||||
|
||||
```c
|
||||
// Run channel 0 forward
|
||||
// Run the channel forward
|
||||
relay_chn_run_forward();
|
||||
|
||||
// Run the channel reverse
|
||||
relay_chn_run_reverse();
|
||||
|
||||
// Stop the channel
|
||||
relay_chn_stop();
|
||||
|
||||
// Flip the direction of the channel
|
||||
relay_chn_flip_direction();
|
||||
```
|
||||
|
||||
For multi mode
|
||||
|
||||
```c
|
||||
// Run channel #0 forward
|
||||
relay_chn_run_forward(0);
|
||||
// Run all channels forward
|
||||
relay_chn_run_forward(RELAY_CHN_ID_ALL);
|
||||
|
||||
// Run channel 0 reverse
|
||||
relay_chn_run_reverse(0);
|
||||
// Run channel #1 reverse
|
||||
relay_chn_run_reverse(1);
|
||||
// Run all channels reverse
|
||||
relay_chn_run_reverse(RELAY_CHN_ID_ALL);
|
||||
|
||||
// Stop channel 0
|
||||
relay_chn_stop(0);
|
||||
// Stop channel #1
|
||||
relay_chn_stop(1);
|
||||
// Stop all channels
|
||||
relay_chn_stop(RELAY_CHN_ID_ALL);
|
||||
|
||||
// Flip direction of channel 0
|
||||
// Flip direction of channel #0
|
||||
relay_chn_flip_direction(0);
|
||||
// Flip direction of all channels
|
||||
relay_chn_flip_direction(RELAY_CHN_ID_ALL);
|
||||
```
|
||||
|
||||
### 3. Monitor channel state
|
||||
|
||||
For single mode:
|
||||
|
||||
```c
|
||||
// Get channel state
|
||||
relay_chn_state_t state = relay_chn_get_state(0);
|
||||
char *state_str = relay_chn_get_state_str(0);
|
||||
relay_chn_state_t state = relay_chn_get_state();
|
||||
// Get the string representation of the state of the channel
|
||||
char *state_str = relay_chn_get_state_str();
|
||||
|
||||
// Get channel direction
|
||||
relay_chn_direction_t direction = relay_chn_get_direction();
|
||||
|
||||
// Listen to relay channel state changes
|
||||
static void relay_chn_listener(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
||||
/* The channel id can be ignored in single mode */
|
||||
/* Handle state changes */
|
||||
}
|
||||
// Register the listener callback
|
||||
relay_chn_register_listener(relay_chn_listener);
|
||||
// Unregister the listener when it is not needed anymore
|
||||
relay_chn_unregister_listener(relay_chn_listener);
|
||||
```
|
||||
|
||||
For multi mode:
|
||||
|
||||
```c
|
||||
// Get channel #0 state
|
||||
relay_chn_state_t state = relay_chn_get_state(0);
|
||||
// Get the string representation of the state of the channel #0
|
||||
char *state_str = relay_chn_get_state_str(0);
|
||||
|
||||
// Get channel #0 direction
|
||||
relay_chn_direction_t direction = relay_chn_get_direction(0);
|
||||
|
||||
/* The listener is same for multi mode */
|
||||
```
|
||||
|
||||
### 4. Tilting Interface (if enabled)
|
||||
|
||||
For single mode:
|
||||
|
||||
```c
|
||||
// Assuming CONFIG_RELAY_CHN_ENABLE_TILTING is enabled
|
||||
|
||||
// Start tilting automatically (channel 0)
|
||||
// Start tilting automatically
|
||||
relay_chn_tilt_auto();
|
||||
|
||||
// Tilt forward
|
||||
relay_chn_tilt_forward();
|
||||
|
||||
// Tilt reverse
|
||||
relay_chn_tilt_reverse();
|
||||
|
||||
// Stop tilting
|
||||
relay_chn_tilt_stop();
|
||||
|
||||
// Set tilting sensitivity (sensitivity as percentage)
|
||||
relay_chn_tilt_sensitivity_set(90);
|
||||
|
||||
// Get tilting sensitivity (sensitivty as percentage)
|
||||
uint8_t sensitivity = relay_chn_tilt_get_sensitivity();
|
||||
```
|
||||
|
||||
For multi mode:
|
||||
|
||||
```c
|
||||
// Assuming CONFIG_RELAY_CHN_ENABLE_TILTING is enabled
|
||||
|
||||
// Start tilting automatically on channel #0
|
||||
relay_chn_tilt_auto(0);
|
||||
relay_chn_tilt_auto(RELAY_CHN_ID_ALL); // on all channels
|
||||
|
||||
// Tilt forward (channel 0)
|
||||
relay_chn_tilt_forward(0);
|
||||
// Tilt forward on channel #1
|
||||
relay_chn_tilt_forward(1);
|
||||
relay_chn_tilt_forward(RELAY_CHN_ID_ALL);
|
||||
|
||||
// Tilt reverse (channel 0)
|
||||
relay_chn_tilt_reverse(0);
|
||||
// Tilt reverse on channel #2
|
||||
relay_chn_tilt_reverse(2);
|
||||
relay_chn_tilt_reverse(RELAY_CHN_ID_ALL);
|
||||
|
||||
// Stop tilting (channel 0)
|
||||
// Stop tilting on channel #0
|
||||
relay_chn_tilt_stop(0);
|
||||
relay_chn_tilt_stop(RELAY_CHN_ID_ALL);
|
||||
|
||||
// Set tilting sensitivity (channel 0, sensitivity as percentage)
|
||||
// Set tilting sensitivity (sensitivity as percentage) for channel #0
|
||||
relay_chn_tilt_sensitivity_set(0, 90);
|
||||
relay_chn_tilt_sensitivity_set(RELAY_CHN_ID_ALL, 90);
|
||||
|
||||
// Get tilting sensitivity (channel 0, sensitivty as percentage)
|
||||
uint8_t sensitivity = relay_chn_tilt_sensitivity_get(0);
|
||||
// Get tilting sensitivity (sensitivty as percentage)
|
||||
uint8_t sensitivity;
|
||||
relay_chn_tilt_get_sensitivity(0, &sensitivity, sizeof(sensitivity));
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
#ifndef RELAY_CHN_H
|
||||
#define RELAY_CHN_H
|
||||
/**
|
||||
* @file relay_chn.h
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* @author
|
||||
* Ismail Sahillioglu <ismailsahillioglu@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* @date 2025.02.08
|
||||
*
|
||||
* @defgroup relay_chn Relay Channel Controller
|
||||
* @ingroup components
|
||||
* @{
|
||||
* One relay channel consists of 2 output relays, hence 2 GPIO pins are required for each relay channel.
|
||||
* This module provides an API to control the relay channels, specifically to drive bipolar motors.
|
||||
* It also provides APIs to control the direction of the relay channel, bipolar motors in mind.
|
||||
@@ -22,66 +14,17 @@
|
||||
* reliability and prevent conflict operations. Also, the esp timer is used to manage the direction change inertia.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include <stdint.h>
|
||||
#include "relay_chn_defs.h"
|
||||
#include "relay_chn_types.h"
|
||||
#include "relay_chn_adapter.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RELAY_CHN_ID_ALL CONFIG_RELAY_CHN_COUNT ///< Special ID to address all channels
|
||||
|
||||
/**
|
||||
* @brief Enumeration for relay channel direction.
|
||||
*/
|
||||
enum relay_chn_direction_enum {
|
||||
RELAY_CHN_DIRECTION_DEFAULT, ///< Default direction of the relay channel.
|
||||
RELAY_CHN_DIRECTION_FLIPPED ///< Flipped direction of the relay channel.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Alias for the enum type relay_chn_direction_enum.
|
||||
*/
|
||||
typedef enum relay_chn_direction_enum relay_chn_direction_t;
|
||||
|
||||
/**
|
||||
* @brief Enums that represent the state of a relay channel.
|
||||
*/
|
||||
enum relay_chn_state_enum {
|
||||
RELAY_CHN_STATE_UNDEFINED, ///< The relay channel state is undefined.
|
||||
RELAY_CHN_STATE_FREE, ///< The relay channel is free to run or execute commands.
|
||||
RELAY_CHN_STATE_STOPPED, ///< The relay channel is stopped and not running.
|
||||
RELAY_CHN_STATE_FORWARD, ///< The relay channel is running in the forward direction.
|
||||
RELAY_CHN_STATE_REVERSE, ///< The relay channel is running in the reverse direction.
|
||||
RELAY_CHN_STATE_FORWARD_PENDING, ///< The relay channel is pending to run in the forward direction.
|
||||
RELAY_CHN_STATE_REVERSE_PENDING, ///< The relay channel is pending to run in the reverse direction.
|
||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
||||
RELAY_CHN_STATE_TILT_FORWARD, ///< The relay channel is tilting for forward.
|
||||
RELAY_CHN_STATE_TILT_REVERSE, ///< The relay channel is tilting for reverse.
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Alias for the enum type relay_chn_state_enum.
|
||||
*/
|
||||
typedef enum relay_chn_state_enum relay_chn_state_t;
|
||||
|
||||
/**
|
||||
* @brief Relay channel state change listener.
|
||||
*
|
||||
* An optional interface to listen to the channel state change events.
|
||||
* The listeners SHOULD be implemented as light functions and SHOULD NOT contain
|
||||
* any blocking calls. Otherwise the relay_chn module would not function properly
|
||||
* since it is designed as event driven.
|
||||
*
|
||||
* @param chn_id The ID of the channel whose state has changed.
|
||||
* @param old_state The old state of the channel.
|
||||
* @param new_state The new state of the channel.
|
||||
*/
|
||||
typedef void (*relay_chn_state_listener_t)(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create and initialize relay channels.
|
||||
*
|
||||
@@ -95,7 +38,7 @@ typedef void (*relay_chn_state_listener_t)(uint8_t chn_id, relay_chn_state_t old
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_FAIL: General failure
|
||||
*/
|
||||
esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count);
|
||||
esp_err_t relay_chn_create(const uint8_t* gpio_map, uint8_t gpio_count);
|
||||
|
||||
/**
|
||||
* @brief Destroy the relay channels and free resources.
|
||||
@@ -124,6 +67,7 @@ esp_err_t relay_chn_register_listener(relay_chn_state_listener_t listener);
|
||||
*/
|
||||
void relay_chn_unregister_listener(relay_chn_state_listener_t listener);
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
/**
|
||||
* @brief Get the state of the specified relay channel.
|
||||
*
|
||||
@@ -150,14 +94,6 @@ relay_chn_state_t relay_chn_get_state(uint8_t chn_id);
|
||||
*/
|
||||
char *relay_chn_get_state_str(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Runs the relay channel in the forward direction.
|
||||
*
|
||||
@@ -191,8 +127,7 @@ void relay_chn_stop(uint8_t chn_id);
|
||||
* @brief Flips the direction of the specified relay channel.
|
||||
*
|
||||
* This function toggles the direction of the relay channel identified by the
|
||||
* given channel ID. It is typically used to change the state of the relay
|
||||
* from its current direction to the opposite direction.
|
||||
* given channel ID.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to flip. This should be a valid
|
||||
* channel ID within the range of available relay channels.
|
||||
@@ -217,9 +152,9 @@ relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id);
|
||||
/**
|
||||
* @brief Enables automatic tilting for the specified relay channel.
|
||||
*
|
||||
* This function enables automatic tilting mode for the given relay channel. The channel will automatically
|
||||
* switch between forward and reverse tilting based on some internal sensing mechanism (not detailed here).
|
||||
* Requires appropriate hardware support and configuration.
|
||||
* This function enables automatic tilting mode for the given relay channel.
|
||||
* The channel will automatically switch between forward and reverse tilting
|
||||
* based on the last movement of the channel
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to enable automatic tilting.
|
||||
*/
|
||||
@@ -228,8 +163,7 @@ void relay_chn_tilt_auto(uint8_t chn_id);
|
||||
/**
|
||||
* @brief Tilts the specified relay channel forward.
|
||||
*
|
||||
* This function initiates a forward tilting action for the specified relay channel. This is a manual tilting
|
||||
* operation, unlike `relay_chn_tilt_auto()`.
|
||||
* This function initiates a forward tilting action for the specified relay channel.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to tilt forward.
|
||||
*/
|
||||
@@ -238,8 +172,7 @@ void relay_chn_tilt_forward(uint8_t chn_id);
|
||||
/**
|
||||
* @brief Tilts the specified relay channel reverse.
|
||||
*
|
||||
* This function initiates a reverse tilting action for the specified relay channel. This is a manual tilting
|
||||
* operation, unlike `relay_chn_tilt_auto()`.
|
||||
* This function initiates a reverse tilting action for the specified relay channel.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to tilt reverse.
|
||||
*/
|
||||
@@ -263,7 +196,7 @@ void relay_chn_tilt_stop(uint8_t chn_id);
|
||||
* @param chn_id The ID of the relay channel to set the sensitivity for.
|
||||
* @param sensitivity The sensitivity in percentage: 0 - 100%.
|
||||
*/
|
||||
void relay_chn_tilt_sensitivity_set(uint8_t chn_id, uint8_t sensitivity);
|
||||
void relay_chn_tilt_set_sensitivity(uint8_t chn_id, uint8_t sensitivity);
|
||||
|
||||
/**
|
||||
* @brief Gets the tilting sensitivity for the specified relay channel.
|
||||
@@ -278,14 +211,127 @@ void relay_chn_tilt_sensitivity_set(uint8_t chn_id, uint8_t sensitivity);
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
*/
|
||||
esp_err_t relay_chn_tilt_sensitivity_get(uint8_t chn_id, uint8_t *sensitivity, size_t length);
|
||||
esp_err_t relay_chn_tilt_get_sensitivity(uint8_t chn_id, uint8_t *sensitivity, size_t length);
|
||||
|
||||
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||
|
||||
#else // RELAY_CHN_COUNT > 1
|
||||
|
||||
/**
|
||||
* @brief Get the state of the relay channel.
|
||||
*
|
||||
* This function retrieves the current state of the relay channel.
|
||||
*
|
||||
* @return The current state of the relay channel.
|
||||
*/
|
||||
relay_chn_state_t relay_chn_get_state(void);
|
||||
|
||||
/**
|
||||
* @brief Get the state string of the relay channel.
|
||||
*
|
||||
* This function returns a string representation of the state of the relay channel.
|
||||
*
|
||||
* @return A pointer to a string representing the state of the relay
|
||||
* channel. The returned string is managed internally and should not be
|
||||
* modified or freed by the caller.
|
||||
*/
|
||||
char *relay_chn_get_state_str(void);
|
||||
|
||||
/**
|
||||
* @brief Runs the relay channel in the forward direction.
|
||||
*
|
||||
* This function activates the relay channel to run in the forward direction.
|
||||
*/
|
||||
void relay_chn_run_forward(void);
|
||||
|
||||
/**
|
||||
* @brief Runs the relay channel in reverse.
|
||||
*
|
||||
* This function activates the relay channel to run in reverse.
|
||||
*/
|
||||
void relay_chn_run_reverse(void);
|
||||
|
||||
/**
|
||||
* @brief Stops the relay channel.
|
||||
*
|
||||
* This function stops the operation of the relay channel.
|
||||
*/
|
||||
void relay_chn_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Flips the direction of the relay channel.
|
||||
*
|
||||
* This function toggles the direction of the relay channel.
|
||||
*/
|
||||
void relay_chn_flip_direction(void);
|
||||
|
||||
/**
|
||||
* @brief Get the direction of the relay channel.
|
||||
*
|
||||
* This function retrieves the direction configuration of a relay channel.
|
||||
*
|
||||
* @return The direction of the relay channel as a value of type
|
||||
* relay_chn_direction_t.
|
||||
*/
|
||||
relay_chn_direction_t relay_chn_get_direction(void);
|
||||
|
||||
|
||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
||||
|
||||
/**
|
||||
* @brief Enables automatic tilting for the relay channel.
|
||||
*
|
||||
* This function enables automatic tilting mode for the given relay channel.
|
||||
* The channel will automatically switch between forward and reverse tilting
|
||||
* based on the last movement of the channel
|
||||
*/
|
||||
void relay_chn_tilt_auto(void);
|
||||
|
||||
/**
|
||||
* @brief Tilts the relay channel forward.
|
||||
*
|
||||
* This function initiates a forward tilting action for the relay channel.
|
||||
*/
|
||||
void relay_chn_tilt_forward(void);
|
||||
|
||||
/**
|
||||
* @brief Tilts the relay channel reverse.
|
||||
*
|
||||
* This function initiates a reverse tilting action for the relay channel.
|
||||
*/
|
||||
void relay_chn_tilt_reverse(void);
|
||||
|
||||
/**
|
||||
* @brief Stops the tilting action on the relay channel.
|
||||
*
|
||||
* This function stops any ongoing tilting action (automatic or manual) on the relay channel.
|
||||
*/
|
||||
void relay_chn_tilt_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Sets the tilting sensitivity for the relay channel.
|
||||
*
|
||||
* This function sets the sensitivity for the automatic tilting mechanism. A higher sensitivity value
|
||||
* typically means the channel will react more readily to tilting events.
|
||||
*
|
||||
* @param sensitivity The sensitivity in percentage: 0 - 100%.
|
||||
*/
|
||||
void relay_chn_tilt_set_sensitivity(uint8_t sensitivity);
|
||||
|
||||
/**
|
||||
* @brief Gets the tilting sensitivity for the relay channel.
|
||||
*
|
||||
* This function retrieves the currently set sensitivity for the relay channel's automatic
|
||||
* tilting mechanism.
|
||||
*
|
||||
* @return Sensitivity value in percentage: 0 - 100%.
|
||||
*/
|
||||
uint8_t relay_chn_tilt_get_sensitivity(void);
|
||||
|
||||
#endif // CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
|
||||
#endif // RELAY_CHN_H
|
||||
186
include/relay_chn_adapter.h
Normal file
186
include/relay_chn_adapter.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* An adapter header to expose the appropriate API functions to the public API
|
||||
* depending on the RELAY_CHN_COUNT value which determines single or multi mode.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
/**
|
||||
* @brief Get the current state of a relay channel.
|
||||
*
|
||||
* @param[in] chn_id Channel ID to get state for.
|
||||
* @return Current state of the specified channel, or RELAY_CHN_STATE_UNDEFINED if invalid.
|
||||
*/
|
||||
extern relay_chn_state_t relay_chn_ctl_get_state(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Get string representation of a relay channel's state.
|
||||
*
|
||||
* @param[in] chn_id Channel ID to get state string for.
|
||||
* @return String representation of channel state, or "UNDEFINED" if invalid.
|
||||
*/
|
||||
extern char *relay_chn_ctl_get_state_str(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Run a relay channel in forward direction.
|
||||
*
|
||||
* @param[in] chn_id Channel ID to run forward, or RELAY_CHN_ID_ALL for all channels.
|
||||
*/
|
||||
extern void relay_chn_ctl_run_forward(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Run a relay channel in reverse direction.
|
||||
*
|
||||
* @param[in] chn_id Channel ID to run reverse, or RELAY_CHN_ID_ALL for all channels.
|
||||
*/
|
||||
extern void relay_chn_ctl_run_reverse(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Stop a relay channel.
|
||||
*
|
||||
* @param[in] chn_id Channel ID to stop, or RELAY_CHN_ID_ALL for all channels.
|
||||
*/
|
||||
extern void relay_chn_ctl_stop(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Flip the running direction of a relay channel.
|
||||
*
|
||||
* @param[in] chn_id Channel ID to flip direction for, or RELAY_CHN_ID_ALL for all channels.
|
||||
*/
|
||||
extern void relay_chn_ctl_flip_direction(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Get the current direction of a relay channel.
|
||||
*
|
||||
* @param[in] chn_id Channel ID to get direction for.
|
||||
* @return Current direction of the specified channel, or RELAY_CHN_DIRECTION_DEFAULT if invalid.
|
||||
*/
|
||||
extern relay_chn_direction_t relay_chn_ctl_get_direction(uint8_t chn_id);
|
||||
|
||||
static inline relay_chn_state_t relay_chn_get_state(uint8_t chn_id)
|
||||
{
|
||||
return relay_chn_ctl_get_state(chn_id);
|
||||
}
|
||||
|
||||
static inline char *relay_chn_get_state_str(uint8_t chn_id)
|
||||
{
|
||||
return relay_chn_ctl_get_state_str(chn_id);
|
||||
}
|
||||
|
||||
static inline void relay_chn_run_forward(uint8_t chn_id)
|
||||
{
|
||||
relay_chn_ctl_run_forward(chn_id);
|
||||
}
|
||||
|
||||
static inline void relay_chn_run_reverse(uint8_t chn_id)
|
||||
{
|
||||
relay_chn_ctl_run_reverse(chn_id);
|
||||
}
|
||||
|
||||
static inline void relay_chn_stop(uint8_t chn_id)
|
||||
{
|
||||
relay_chn_ctl_stop(chn_id);
|
||||
}
|
||||
|
||||
static inline void relay_chn_flip_direction(uint8_t chn_id)
|
||||
{
|
||||
relay_chn_ctl_flip_direction(chn_id);
|
||||
}
|
||||
|
||||
static inline relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id)
|
||||
{
|
||||
return relay_chn_ctl_get_direction(chn_id);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* @brief Get the current state of the relay channel.
|
||||
*
|
||||
* @return Current state of the channel.
|
||||
*/
|
||||
extern relay_chn_state_t relay_chn_ctl_get_state(void);
|
||||
|
||||
/**
|
||||
* @brief Get string representation of the relay channel's state.
|
||||
*
|
||||
* @return String representation of channel state.
|
||||
*/
|
||||
extern char *relay_chn_ctl_get_state_str(void);
|
||||
|
||||
/**
|
||||
* @brief Run the relay channel in forward direction.
|
||||
*/
|
||||
extern void relay_chn_ctl_run_forward(void);
|
||||
|
||||
/**
|
||||
* @brief Run the relay channel in reverse direction.
|
||||
*/
|
||||
extern void relay_chn_ctl_run_reverse(void);
|
||||
|
||||
/**
|
||||
* @brief Stop the relay channel.
|
||||
*/
|
||||
extern void relay_chn_ctl_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Flip the running direction of the relay channel.
|
||||
*/
|
||||
extern void relay_chn_ctl_flip_direction(void);
|
||||
|
||||
/**
|
||||
* @brief Get the current direction of the relay channel.
|
||||
*
|
||||
* @return Current direction of the channel.
|
||||
*/
|
||||
extern relay_chn_direction_t relay_chn_ctl_get_direction(void);
|
||||
|
||||
static inline relay_chn_state_t relay_chn_get_state(void)
|
||||
{
|
||||
return relay_chn_ctl_get_state();
|
||||
}
|
||||
|
||||
static inline char *relay_chn_get_state_str(void)
|
||||
{
|
||||
return relay_chn_ctl_get_state_str();
|
||||
}
|
||||
|
||||
static inline void relay_chn_run_forward(void)
|
||||
{
|
||||
relay_chn_ctl_run_forward();
|
||||
}
|
||||
|
||||
static inline void relay_chn_run_reverse(void)
|
||||
{
|
||||
relay_chn_ctl_run_reverse();
|
||||
}
|
||||
|
||||
static inline void relay_chn_stop(void)
|
||||
{
|
||||
relay_chn_ctl_stop();
|
||||
}
|
||||
|
||||
static inline void relay_chn_flip_direction(void)
|
||||
{
|
||||
relay_chn_ctl_flip_direction();
|
||||
}
|
||||
|
||||
static inline relay_chn_direction_t relay_chn_get_direction(void)
|
||||
{
|
||||
return relay_chn_ctl_get_direction();
|
||||
}
|
||||
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
24
include/relay_chn_defs.h
Normal file
24
include/relay_chn_defs.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Config defines for covenient writing */
|
||||
#define RELAY_CHN_OPPOSITE_INERTIA_MS CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS
|
||||
#define RELAY_CHN_COUNT CONFIG_RELAY_CHN_COUNT
|
||||
#define RELAY_CHN_ENABLE_TILTING CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
#define RELAY_CHN_ID_ALL RELAY_CHN_COUNT /*!< Special ID to address all channels */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
58
include/relay_chn_types.h
Normal file
58
include/relay_chn_types.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "relay_chn_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enumeration for relay channel direction.
|
||||
*/
|
||||
typedef enum relay_chn_direction_enum {
|
||||
RELAY_CHN_DIRECTION_DEFAULT, /*!< Default direction of the relay channel */
|
||||
RELAY_CHN_DIRECTION_FLIPPED /*!< Flipped direction of the relay channel */
|
||||
} relay_chn_direction_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enums that represent the state of a relay channel.
|
||||
*/
|
||||
typedef enum relay_chn_state_enum {
|
||||
RELAY_CHN_STATE_UNDEFINED, /*!< The relay channel state is undefined */
|
||||
RELAY_CHN_STATE_IDLE, /*!< The relay channel is free to run or execute commands */
|
||||
RELAY_CHN_STATE_STOPPED, /*!< The relay channel is stopped and not running */
|
||||
RELAY_CHN_STATE_FORWARD, /*!< The relay channel is running in the forward direction */
|
||||
RELAY_CHN_STATE_REVERSE, /*!< The relay channel is running in the reverse direction */
|
||||
RELAY_CHN_STATE_FORWARD_PENDING, /*!< The relay channel is pending to run in the forward direction */
|
||||
RELAY_CHN_STATE_REVERSE_PENDING, /*!< The relay channel is pending to run in the reverse direction */
|
||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
||||
RELAY_CHN_STATE_TILT_FORWARD, /*!< The relay channel is tilting for forward */
|
||||
RELAY_CHN_STATE_TILT_REVERSE, /*!< The relay channel is tilting for reverse */
|
||||
#endif
|
||||
} relay_chn_state_t;
|
||||
|
||||
/**
|
||||
* @brief Relay channel state change listener.
|
||||
*
|
||||
* An optional interface to listen to the channel state change events.
|
||||
* The listeners SHOULD be implemented as light functions and SHOULD NOT contain
|
||||
* any blocking calls. Otherwise the relay_chn module would not function properly
|
||||
* since it is designed as event driven.
|
||||
*
|
||||
* @param chn_id The ID of the channel whose state has changed.
|
||||
* @param old_state The old state of the channel.
|
||||
* @param new_state The new state of the channel.
|
||||
*/
|
||||
typedef void (*relay_chn_state_listener_t)(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
114
private_include/relay_chn_core.h
Normal file
114
private_include/relay_chn_core.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_event_base.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_timer.h"
|
||||
#include "relay_chn_defs.h"
|
||||
#include "relay_chn_types.h"
|
||||
#include "relay_chn_priv_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Event base used by *_core, *_ctl, and *_tilt modules.
|
||||
ESP_EVENT_DECLARE_BASE(RELAY_CHN_CMD_EVENT);
|
||||
|
||||
/**
|
||||
* @brief Initializes the relay channel timer.
|
||||
*
|
||||
* This function creates a timer for the relay channel to handle direction change inertia.
|
||||
* Required by *_ctl_* module.
|
||||
*
|
||||
* @param chn_ctl Pointer to the relay channel control structure.
|
||||
* @return esp_err_t ESP_OK on success, or an error code on failure.
|
||||
*/
|
||||
esp_err_t relay_chn_init_timer(relay_chn_ctl_t *chn_ctl);
|
||||
|
||||
/**
|
||||
* @brief Issues a command to the relay channel.
|
||||
*
|
||||
* Evaluates the current state of the relay channel and issues the command accordingly.
|
||||
* Required by *_core, *_ctl_* and *_tilt modules.
|
||||
*
|
||||
* @param chn_ctl Pointer to the relay channel control structure.
|
||||
* @param cmd The command to issue.
|
||||
*/
|
||||
void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd);
|
||||
|
||||
/**
|
||||
* @brief Dispatches a relay channel command to the event loop.
|
||||
*
|
||||
* @param chn_ctl Pointer to the relay channel control structure.
|
||||
* @param cmd The command to dispatch.
|
||||
*/
|
||||
void relay_chn_dispatch_cmd(relay_chn_ctl_t *chn_ctl, relay_chn_cmd_t cmd);
|
||||
|
||||
/**
|
||||
* @brief Returns the string representation of a relay channel command.
|
||||
*
|
||||
* @param cmd The relay channel command.
|
||||
* @return char* The string representation of the command.
|
||||
*/
|
||||
char *relay_chn_cmd_str(relay_chn_cmd_t cmd);
|
||||
|
||||
/**
|
||||
* @brief Starts the ESP timer once with the specified time in milliseconds.
|
||||
*
|
||||
* Starts the ESP timer to run once after the specified time.
|
||||
* If the timer is already running, it stops it first and then starts it again.
|
||||
* Required by *_ctl_* and *_tilt modules.
|
||||
*
|
||||
* @param esp_timer The ESP timer handle.
|
||||
* @param time_ms The time in milliseconds to wait before the timer expires.
|
||||
* @return esp_err_t ESP_OK on success, or an error code on failure.
|
||||
*/
|
||||
esp_err_t relay_chn_start_esp_timer_once(esp_timer_handle_t esp_timer, uint32_t time_ms);
|
||||
|
||||
/**
|
||||
* @brief Updates the state of the relay channel and notifies listeners.
|
||||
*
|
||||
* This function updates the state of the relay channel and notifies all registered listeners
|
||||
* about the state change.
|
||||
* Required by *_ctl_* and *_tilt modules.
|
||||
*
|
||||
* @param chn_ctl Pointer to the relay channel control structure.
|
||||
* @param new_state The new state to set for the relay channel.
|
||||
*/
|
||||
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 RELAY_CHN_COUNT > 1
|
||||
/**
|
||||
* @brief Check if the provided channel ID is valid.
|
||||
*
|
||||
* @param chn_id Channel ID to check.
|
||||
* @return true Channel ID is valid.
|
||||
* @return false Channel ID is invalid.
|
||||
*/
|
||||
bool relay_chn_is_channel_id_valid(uint8_t chn_id);
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
/// Relay channel event loop handle declaration for *_tilt module.
|
||||
extern esp_event_loop_handle_t relay_chn_event_loop;
|
||||
#endif // RELAY_CHN_ENABLE_TILTING
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
56
private_include/relay_chn_ctl.h
Normal file
56
private_include/relay_chn_ctl.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech developer@kozmotronik.com.tr
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Expose the *_ctl functions required by *_core.c file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "relay_chn_priv_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize the relay channel control.
|
||||
*
|
||||
* @param output Pointer to the output object(s).
|
||||
* @param run_info Pointer to the runtime information object(s).
|
||||
*
|
||||
* @return esp_err_t Returns ESP_OK on success, or an error code on failure.
|
||||
*/
|
||||
esp_err_t relay_chn_ctl_init(relay_chn_output_t *output, relay_chn_run_info_t *run_info);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the relay channel control.
|
||||
*
|
||||
* This function cleans up resources used by the relay channel control.
|
||||
*/
|
||||
void relay_chn_ctl_deinit(void);
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
/**
|
||||
* @brief Get the control structure for a specific relay channel.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to retrieve.
|
||||
*
|
||||
* @return relay_chn_ctl_t* Pointer to the control structure for the specified channel, or NULL if not found.
|
||||
*/
|
||||
relay_chn_ctl_t *relay_chn_ctl_get(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Get the control structures for all relay channels.
|
||||
*
|
||||
* @return relay_chn_ctl_t* Pointer to the array of control structures for all channels.
|
||||
*/
|
||||
relay_chn_ctl_t *relay_chn_ctl_get_all(void);
|
||||
#else
|
||||
relay_chn_ctl_t *relay_chn_ctl_get(void);
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
113
private_include/relay_chn_output.h
Normal file
113
private_include/relay_chn_output.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Abstraction layer for controlling relay channel outputs. This is the layer
|
||||
* that interacts with the GPIO pins to control the relay channels.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "relay_chn_priv_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize relay channel outputs.
|
||||
*
|
||||
* Maps relay channels to GPIO pins and prepares them for operation.
|
||||
*
|
||||
* @param[in] gpio_map Array of GPIO pin numbers for each relay channel.
|
||||
* @param[in] gpio_count Number of GPIO pins (relay channels).
|
||||
*
|
||||
* @return ESP_OK on success, error code otherwise.
|
||||
*/
|
||||
esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize relay channel outputs.
|
||||
*
|
||||
* Releases resources and resets GPIO pins used for relay channels.
|
||||
*/
|
||||
void relay_chn_output_deinit(void);
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
/**
|
||||
* @brief Get the relay channel output object for a specific channel.
|
||||
*
|
||||
* @param[in] chn_id Channel ID.
|
||||
*
|
||||
* @return Pointer to relay channel output object, or NULL if invalid.
|
||||
*/
|
||||
relay_chn_output_t *relay_chn_output_get(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Get all relay channel output objects.
|
||||
*
|
||||
* @return Pointer to array of relay channel output objects.
|
||||
*/
|
||||
relay_chn_output_t *relay_chn_output_get_all(void);
|
||||
#else
|
||||
/**
|
||||
* @brief Get the relay channel output object.
|
||||
*
|
||||
* @return Pointer to relay channel output object.
|
||||
*/
|
||||
relay_chn_output_t *relay_chn_output_get(void);
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
/**
|
||||
* @brief Stop the relay channel output.
|
||||
*
|
||||
* Sets the relay channel to the stop state.
|
||||
*
|
||||
* @param[in] output Pointer to relay channel output object.
|
||||
*
|
||||
* @return ESP_OK on success, error code otherwise.
|
||||
*/
|
||||
esp_err_t relay_chn_output_stop(relay_chn_output_t *output);
|
||||
|
||||
/**
|
||||
* @brief Set relay channel output to forward direction.
|
||||
*
|
||||
* @param[in] output Pointer to relay channel output object.
|
||||
*
|
||||
* @return ESP_OK on success, error code otherwise.
|
||||
*/
|
||||
esp_err_t relay_chn_output_forward(relay_chn_output_t *output);
|
||||
|
||||
/**
|
||||
* @brief Set relay channel output to reverse direction.
|
||||
*
|
||||
* @param[in] output Pointer to relay channel output object.
|
||||
*
|
||||
* @return ESP_OK on success, error code otherwise.
|
||||
*/
|
||||
esp_err_t relay_chn_output_reverse(relay_chn_output_t *output);
|
||||
|
||||
/**
|
||||
* @brief Flip the direction of the relay channel output.
|
||||
*
|
||||
* Changes the direction from forward to reverse or vice versa.
|
||||
*
|
||||
* @param[in] output Pointer to relay channel output object.
|
||||
*/
|
||||
void relay_chn_output_flip(relay_chn_output_t *output);
|
||||
|
||||
/**
|
||||
* @brief Get the current direction of the relay channel output.
|
||||
*
|
||||
* @param[in] output Pointer to relay channel output object.
|
||||
*
|
||||
* @return Current direction of the relay channel.
|
||||
*/
|
||||
relay_chn_direction_t relay_chn_output_get_direction(relay_chn_output_t *output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
78
private_include/relay_chn_priv_types.h
Normal file
78
private_include/relay_chn_priv_types.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_timer.h"
|
||||
#include "relay_chn_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enumeration for relay channel commands.
|
||||
*/
|
||||
typedef enum {
|
||||
RELAY_CHN_CMD_NONE, /*!< No command */
|
||||
RELAY_CHN_CMD_STOP, /*!< Stop the relay channel */
|
||||
RELAY_CHN_CMD_FORWARD, /*!< Run the relay channel in the forward direction */
|
||||
RELAY_CHN_CMD_REVERSE, /*!< Run the relay channel in the reverse direction */
|
||||
RELAY_CHN_CMD_FLIP, /*!< Flip the direction of the relay channel */
|
||||
RELAY_CHN_CMD_IDLE /*!< Free the relay channel */
|
||||
} relay_chn_cmd_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Structure to hold the output configuration of a relay channel.
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_num_t forward_pin; /*!< GPIO pin number for the forward direction */
|
||||
gpio_num_t reverse_pin; /*!< GPIO pin number for the reverse direction */
|
||||
relay_chn_direction_t direction; /*!< The current direction of the relay channel */
|
||||
} relay_chn_output_t;
|
||||
|
||||
/**
|
||||
* @brief Structure to hold runtime information for a relay channel.
|
||||
*/
|
||||
typedef struct {
|
||||
relay_chn_cmd_t last_run_cmd; /*!< The last run command issued on the relay channel; forward or reverse */
|
||||
uint32_t last_run_cmd_time_ms; /*!< The time in milliseconds when the last run command was issued */
|
||||
} relay_chn_run_info_t;
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
/// @brief Tilt commands.
|
||||
typedef enum {
|
||||
RELAY_CHN_TILT_CMD_NONE, /*!< No command */
|
||||
RELAY_CHN_TILT_CMD_STOP, /*!< Tilt command stop */
|
||||
RELAY_CHN_TILT_CMD_FORWARD, /*!< Tilt command for forward */
|
||||
RELAY_CHN_TILT_CMD_REVERSE /*!< Tilt command for reverse */
|
||||
} relay_chn_tilt_cmd_t;
|
||||
|
||||
/// Forward declaration for relay_chn_tilt_ctl
|
||||
typedef struct relay_chn_tilt_ctl relay_chn_tilt_ctl_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Structure to hold the state and configuration of a relay channel.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t id; /*!< The ID of the relay channel */
|
||||
relay_chn_state_t state; /*!< The current state of the relay channel */
|
||||
relay_chn_run_info_t *run_info; /*!< Runtime information of the relay channel */
|
||||
relay_chn_output_t *output; /*!< Output configuration of the relay channel */
|
||||
relay_chn_cmd_t pending_cmd; /*!< The command that is pending to be issued */
|
||||
esp_timer_handle_t inertia_timer; /*!< Timer to handle the opposite direction inertia time */
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
relay_chn_tilt_ctl_t *tilt_ctl; /*!< Pointer to the tilt control structure if tilting is enabled */
|
||||
#endif
|
||||
} relay_chn_ctl_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
84
private_include/relay_chn_run_info.h
Normal file
84
private_include/relay_chn_run_info.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* This is for managing the run information of relay channels.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "relay_chn_priv_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize relay channel run information.
|
||||
*
|
||||
* Initializes the run information for all relay channels with default values.
|
||||
*/
|
||||
void relay_chn_run_info_init(void);
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
/**
|
||||
* @brief Get run information object for a specific relay channel.
|
||||
*
|
||||
* @param[in] chn_id Channel ID to get run information for.
|
||||
* @return Pointer to run information structure, or NULL if channel ID is invalid.
|
||||
*/
|
||||
relay_chn_run_info_t *relay_chn_run_info_get(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Get run information objects for all relay channels.
|
||||
*
|
||||
* @return Pointer to array of run information structures.
|
||||
*/
|
||||
relay_chn_run_info_t *relay_chn_run_info_get_all(void);
|
||||
#else
|
||||
/**
|
||||
* @brief Get run information object for the single relay channel.
|
||||
*
|
||||
* @return Pointer to run information structure.
|
||||
*/
|
||||
relay_chn_run_info_t *relay_chn_run_info_get(void);
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
/**
|
||||
* @brief Get the last run command for a relay channel.
|
||||
*
|
||||
* @param[in] run_info Pointer to run information structure.
|
||||
*
|
||||
* @return Last command that was executed, or RELAY_CHN_CMD_NONE if invalid.
|
||||
*/
|
||||
relay_chn_cmd_t relay_chn_run_info_get_last_run_cmd(relay_chn_run_info_t *run_info);
|
||||
|
||||
/**
|
||||
* @brief Set the last run command for a relay channel.
|
||||
*
|
||||
* @param[in] run_info Pointer to run information structure.
|
||||
* @param[in] cmd Command to set as last run command.
|
||||
*/
|
||||
void relay_chn_run_info_set_last_run_cmd(relay_chn_run_info_t *run_info, relay_chn_cmd_t cmd);
|
||||
|
||||
/**
|
||||
* @brief Get the timestamp of the last run command.
|
||||
*
|
||||
* @param[in] run_info Pointer to run information structure.
|
||||
*
|
||||
* @return Timestamp in milliseconds of last command, or 0 if invalid.
|
||||
*/
|
||||
uint32_t relay_chn_run_info_get_last_run_cmd_time_ms(relay_chn_run_info_t *run_info);
|
||||
|
||||
/**
|
||||
* @brief Set the timestamp for the last run command.
|
||||
*
|
||||
* @param[in] run_info Pointer to run information structure.
|
||||
* @param[in] time_ms Timestamp in milliseconds to set.
|
||||
*/
|
||||
void relay_chn_run_info_set_last_run_cmd_time_ms(relay_chn_run_info_t *run_info, uint32_t time_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
58
private_include/relay_chn_tilt.h
Normal file
58
private_include/relay_chn_tilt.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "relay_chn_priv_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize relay channel tilt controls.
|
||||
*
|
||||
* Sets up tilt functionality for relay channels including timers and event handlers.
|
||||
* Must be called before using any other tilt functions.
|
||||
*
|
||||
* @param[in] chn_ctls Array of relay channel control structures.
|
||||
*
|
||||
* @return ESP_OK on success, error code otherwise.
|
||||
*/
|
||||
esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize relay channel tilt controls.
|
||||
*
|
||||
* Cleans up tilt resources including timers and event handlers.
|
||||
* Should be called when tilt functionality is no longer needed.
|
||||
*/
|
||||
void relay_chn_tilt_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Dispatch a tilt command to a relay channel.
|
||||
*
|
||||
* Queues a tilt command for execution on the specified channel.
|
||||
*
|
||||
* @param[in] tilt_ctl Pointer to tilt control structure.
|
||||
* @param[in] cmd Tilt command to execute.
|
||||
*
|
||||
* @return ESP_OK on success, error code otherwise.
|
||||
*/
|
||||
esp_err_t relay_chn_tilt_dispatch_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd);
|
||||
|
||||
/**
|
||||
* @brief Reset tilt counters for a relay channel.
|
||||
*
|
||||
* Resets both forward and reverse tilt counters to zero.
|
||||
*
|
||||
* @param[in] tilt_ctl Pointer to tilt control structure.
|
||||
*/
|
||||
void relay_chn_tilt_reset_count(relay_chn_tilt_ctl_t *tilt_ctl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
1470
src/relay_chn.c
1470
src/relay_chn.c
File diff suppressed because it is too large
Load Diff
574
src/relay_chn_core.c
Normal file
574
src/relay_chn_core.c
Normal file
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_check.h"
|
||||
#include "esp_task.h"
|
||||
#include "relay_chn_output.h"
|
||||
#include "relay_chn_run_info.h"
|
||||
#include "relay_chn_ctl.h"
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
#include "relay_chn_tilt.h"
|
||||
#endif
|
||||
#include "relay_chn_core.h"
|
||||
|
||||
|
||||
static const char *TAG = "RELAY_CHN_CORE";
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(RELAY_CHN_CMD_EVENT);
|
||||
|
||||
|
||||
// Structure to hold a listener entry in the linked list.
|
||||
typedef struct relay_chn_listener_entry_type {
|
||||
relay_chn_state_listener_t listener; /*!< The listener function pointer */
|
||||
ListItem_t list_item; /*!< FreeRTOS list item */
|
||||
} relay_chn_listener_entry_t;
|
||||
|
||||
// The list that holds references to the registered listeners.
|
||||
static List_t relay_chn_listener_list;
|
||||
|
||||
// Define the event loop for global access both for this module and tilt module.
|
||||
esp_event_loop_handle_t relay_chn_event_loop = NULL;
|
||||
|
||||
|
||||
// Private function declarations
|
||||
// Event handler for the relay channel command event
|
||||
static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
|
||||
|
||||
|
||||
// Timer callback function for relay channel direction change inertia.
|
||||
static void relay_chn_timer_cb(void* arg)
|
||||
{
|
||||
relay_chn_ctl_t* chn_ctl = (relay_chn_ctl_t*) arg;
|
||||
// Does channel have a pending command?
|
||||
if (chn_ctl->pending_cmd != RELAY_CHN_CMD_NONE) {
|
||||
relay_chn_dispatch_cmd(chn_ctl, chn_ctl->pending_cmd);
|
||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(TAG, "relay_chn_timer_cb: No pending cmd for relay channel %d!", chn_ctl->id);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_init_timer(relay_chn_ctl_t *chn_ctl)
|
||||
{
|
||||
char timer_name[32];
|
||||
snprintf(timer_name, sizeof(timer_name), "relay_chn_%d_timer", chn_ctl->id);
|
||||
esp_timer_create_args_t timer_args = {
|
||||
.callback = relay_chn_timer_cb,
|
||||
.arg = chn_ctl,
|
||||
.name = timer_name
|
||||
};
|
||||
return esp_timer_create(&timer_args, &chn_ctl->inertia_timer);
|
||||
}
|
||||
|
||||
static esp_err_t relay_chn_create_event_loop()
|
||||
{
|
||||
esp_event_loop_args_t loop_args = {
|
||||
.queue_size = RELAY_CHN_COUNT * 8,
|
||||
.task_name = "relay_chn_event_loop",
|
||||
.task_priority = ESP_TASKD_EVENT_PRIO - 1,
|
||||
.task_stack_size = 2048,
|
||||
.task_core_id = tskNO_AFFINITY
|
||||
};
|
||||
esp_err_t ret = esp_event_loop_create(&loop_args, &relay_chn_event_loop);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create event loop for relay channel");
|
||||
ret = esp_event_handler_register_with(relay_chn_event_loop,
|
||||
RELAY_CHN_CMD_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
relay_chn_event_handler, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_create(const uint8_t* gpio_map, uint8_t gpio_count)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(gpio_map != NULL, ESP_ERR_INVALID_ARG, TAG, "gpio_map cannot be NULL");
|
||||
|
||||
esp_err_t ret;
|
||||
// Initialize the output
|
||||
ret = relay_chn_output_init(gpio_map, gpio_count);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel outputs");
|
||||
|
||||
// Initialize the run info
|
||||
relay_chn_run_info_init();
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
relay_chn_output_t *outputs = relay_chn_output_get_all();
|
||||
relay_chn_run_info_t *run_infos = relay_chn_run_info_get_all();
|
||||
#else
|
||||
relay_chn_output_t *outputs = relay_chn_output_get();
|
||||
relay_chn_run_info_t *run_infos = relay_chn_run_info_get();
|
||||
#endif
|
||||
|
||||
// Initialize the relay channel controls
|
||||
ret = relay_chn_ctl_init(outputs, run_infos);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel control");
|
||||
|
||||
// Create relay channel command event loop
|
||||
ret = relay_chn_create_event_loop();
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create relay channel event loop");
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
// Initialize the tilt feature
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
relay_chn_ctl_t *chn_ctls = relay_chn_ctl_get_all();
|
||||
#else
|
||||
relay_chn_ctl_t *chn_ctls = relay_chn_ctl_get();
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
ret = relay_chn_tilt_init(chn_ctls); // Initialize tilt feature
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize tilt feature");
|
||||
#endif
|
||||
|
||||
// Init the state listener list
|
||||
vListInitialise(&relay_chn_listener_list);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relay_chn_destroy(void)
|
||||
{
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
relay_chn_tilt_deinit();
|
||||
#endif
|
||||
relay_chn_ctl_deinit();
|
||||
relay_chn_output_deinit();
|
||||
|
||||
// Destroy the event loop
|
||||
esp_event_loop_delete(relay_chn_event_loop);
|
||||
relay_chn_event_loop = NULL;
|
||||
|
||||
// Free the listeners
|
||||
while (listCURRENT_LIST_LENGTH(&relay_chn_listener_list) > 0) {
|
||||
ListItem_t *pxItem = listGET_HEAD_ENTRY(&relay_chn_listener_list);
|
||||
relay_chn_listener_entry_t *entry = listGET_LIST_ITEM_OWNER(pxItem);
|
||||
uxListRemove(pxItem);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find a listener entry in the list by its function pointer.
|
||||
*
|
||||
* This function replaces the old index-based search and is used to check
|
||||
* for the existence of a listener before registration or for finding it
|
||||
* during unregistration.
|
||||
*
|
||||
* @param listener The listener function pointer to find.
|
||||
* @return Pointer to the listener entry if found, otherwise NULL.
|
||||
*/
|
||||
static relay_chn_listener_entry_t* find_listener_entry(relay_chn_state_listener_t listener)
|
||||
{
|
||||
// Iterate through the linked list of listeners
|
||||
for (ListItem_t *pxListItem = listGET_HEAD_ENTRY(&relay_chn_listener_list);
|
||||
pxListItem != listGET_END_MARKER(&relay_chn_listener_list);
|
||||
pxListItem = listGET_NEXT(pxListItem)) {
|
||||
|
||||
relay_chn_listener_entry_t *entry = (relay_chn_listener_entry_t *) listGET_LIST_ITEM_OWNER(pxListItem);
|
||||
if (entry->listener == listener) {
|
||||
// Found the listener, return the entry
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
// Listener was not found in the list
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_register_listener(relay_chn_state_listener_t listener)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(listener, ESP_ERR_INVALID_ARG, TAG, "Listener cannot be NULL");
|
||||
|
||||
// Check for duplicates
|
||||
if (find_listener_entry(listener) != NULL) {
|
||||
ESP_LOGD(TAG, "Listener %p already registered", listener);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Allocate memory for the new listener entry
|
||||
relay_chn_listener_entry_t *entry = malloc(sizeof(relay_chn_listener_entry_t));
|
||||
ESP_RETURN_ON_FALSE(entry, ESP_ERR_NO_MEM, TAG, "Failed to allocate memory for listener");
|
||||
|
||||
// Initialize and insert the new listener
|
||||
entry->listener = listener;
|
||||
vListInitialiseItem(&(entry->list_item));
|
||||
listSET_LIST_ITEM_OWNER(&(entry->list_item), (void *)entry);
|
||||
vListInsertEnd(&relay_chn_listener_list, &(entry->list_item));
|
||||
|
||||
ESP_LOGD(TAG, "Registered listener %p", listener);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void relay_chn_unregister_listener(relay_chn_state_listener_t listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
{
|
||||
ESP_LOGD(TAG, "Cannot unregister a NULL listener.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the listener entry in the list
|
||||
relay_chn_listener_entry_t *entry = find_listener_entry(listener);
|
||||
|
||||
if (entry != NULL) {
|
||||
// Remove the item from the list and free the allocated memory
|
||||
uxListRemove(&(entry->list_item));
|
||||
free(entry);
|
||||
ESP_LOGD(TAG, "Unregistered listener %p", listener);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Listener %p not found for unregistration.", listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Dispatch relay channel command to its event loop
|
||||
void relay_chn_dispatch_cmd(relay_chn_ctl_t *chn_ctl, relay_chn_cmd_t cmd) {
|
||||
if (cmd == RELAY_CHN_CMD_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since the event_loop library creates a deep copy of the event data,
|
||||
// and we need to pass the pointer of the relevant channel, here we need
|
||||
// to pass the pointer to the pointer of the channel (&chn_ctl) so that
|
||||
// the pointer value is preserved in the event data.
|
||||
esp_event_post_to(relay_chn_event_loop,
|
||||
RELAY_CHN_CMD_EVENT,
|
||||
cmd,
|
||||
&chn_ctl,
|
||||
sizeof(chn_ctl),
|
||||
portMAX_DELAY);
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
// Reset the tilt counter when the command is either FORWARD or REVERSE
|
||||
if (cmd == RELAY_CHN_CMD_FORWARD || cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
relay_chn_tilt_reset_count(chn_ctl->tilt_ctl);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_start_esp_timer_once(esp_timer_handle_t esp_timer, uint32_t time_ms)
|
||||
{
|
||||
esp_err_t ret = esp_timer_start_once(esp_timer, time_ms * 1000);
|
||||
if (ret == ESP_ERR_INVALID_STATE) {
|
||||
// This timer is already running, stop the timer first
|
||||
ret = esp_timer_stop(esp_timer);
|
||||
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
|
||||
return ret;
|
||||
}
|
||||
ret = esp_timer_start_once(esp_timer, time_ms * 1000);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relay_chn_update_state(relay_chn_ctl_t *chn_ctl, relay_chn_state_t new_state)
|
||||
{
|
||||
relay_chn_state_t old_state = chn_ctl->state;
|
||||
|
||||
// Only update and notify if the state has actually changed.
|
||||
if (old_state == new_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
chn_ctl->state = new_state;
|
||||
|
||||
// Iterate through the linked list of listeners and notify them.
|
||||
for (ListItem_t *pxListItem = listGET_HEAD_ENTRY(&relay_chn_listener_list);
|
||||
pxListItem != listGET_END_MARKER(&relay_chn_listener_list);
|
||||
pxListItem = listGET_NEXT(pxListItem)) {
|
||||
relay_chn_listener_entry_t *entry = (relay_chn_listener_entry_t *) listGET_LIST_ITEM_OWNER(pxListItem);
|
||||
if (entry && entry->listener) {
|
||||
// Emit the state change to the listeners
|
||||
entry->listener(chn_ctl->id, old_state, new_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The command issuer function.
|
||||
*
|
||||
* This function is the deciding logic for issuing a command to a relay channel. It evaluates
|
||||
* the current state of the channel before issuing the command. Then it decides whether to run
|
||||
* the command immediately or wait for the opposite inertia time.
|
||||
*
|
||||
* The STOP command is an exception, it is always run immediately since it is safe in any case.
|
||||
*
|
||||
* Another special consideration is the FLIP command. If the channel is running, the FLIP command
|
||||
* is issued after the channel is stopped. If the channel is stopped, the FLIP command is issued
|
||||
* immediately.
|
||||
*
|
||||
* @param chn_ctl The relay channel to issue the command to.
|
||||
* @param cmd The command to issue.
|
||||
*/
|
||||
void relay_chn_issue_cmd(relay_chn_ctl_t* chn_ctl, relay_chn_cmd_t cmd)
|
||||
{
|
||||
if (cmd == RELAY_CHN_CMD_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == RELAY_CHN_CMD_STOP) {
|
||||
if (chn_ctl->state == RELAY_CHN_STATE_STOPPED) {
|
||||
return; // Do nothing if already stopped
|
||||
}
|
||||
// If the command is STOP, issue it immediately
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
relay_chn_cmd_t last_run_cmd = relay_chn_run_info_get_last_run_cmd(chn_ctl->run_info);
|
||||
// Evaluate the channel's next move depending on its status
|
||||
switch (chn_ctl->state)
|
||||
{
|
||||
case RELAY_CHN_STATE_IDLE:
|
||||
// If the channel is idle, run the command immediately
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_FORWARD_PENDING:
|
||||
case RELAY_CHN_STATE_REVERSE_PENDING:
|
||||
// The channel is already waiting for the opposite inertia time,
|
||||
// so do nothing unless the command is STOP
|
||||
if (cmd == RELAY_CHN_CMD_STOP) {
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
}
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_STOPPED:
|
||||
if (last_run_cmd == cmd || last_run_cmd == RELAY_CHN_CMD_NONE) {
|
||||
// Since the state is STOPPED, the inertia timer should be running and must be invalidated
|
||||
// with the pending FREE command
|
||||
esp_timer_stop(chn_ctl->inertia_timer);
|
||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||
|
||||
// If this is the first run or the last run command is the same as the current command,
|
||||
// run the command immediately
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
}
|
||||
else {
|
||||
// If the last run command is different from the current command, calculate the time passed
|
||||
// since the last run command stopped and decide whether to run the command immediately or wait
|
||||
uint32_t last_run_cmd_time_ms = relay_chn_run_info_get_last_run_cmd_time_ms(chn_ctl->run_info);
|
||||
uint32_t inertia_time_passed_ms = (uint32_t) (esp_timer_get_time() / 1000) - last_run_cmd_time_ms;
|
||||
uint32_t inertia_time_ms = RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
||||
if (inertia_time_ms > 0) {
|
||||
chn_ctl->pending_cmd = cmd;
|
||||
relay_chn_state_t new_state = cmd == RELAY_CHN_CMD_FORWARD
|
||||
? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
||||
relay_chn_update_state(chn_ctl, new_state);
|
||||
// If the time passed is less than the opposite inertia time, wait for the remaining time
|
||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, inertia_time_ms);
|
||||
}
|
||||
else {
|
||||
// If the time passed is more than the opposite inertia time, run the command immediately
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_FORWARD:
|
||||
case RELAY_CHN_STATE_REVERSE:
|
||||
if (cmd == RELAY_CHN_CMD_FLIP) {
|
||||
// If the command is FLIP, stop the running channel first, then issue the FLIP command
|
||||
relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_run_cmd == cmd) {
|
||||
// If the last run command is the same as the current command, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop the channel first before the schedule
|
||||
relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
|
||||
// If the last run command is different from the current command, wait for the opposite inertia time
|
||||
chn_ctl->pending_cmd = cmd;
|
||||
relay_chn_state_t new_state = cmd == RELAY_CHN_CMD_FORWARD
|
||||
? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
||||
relay_chn_update_state(chn_ctl, new_state);
|
||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
break;
|
||||
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
case RELAY_CHN_STATE_TILT_FORWARD:
|
||||
// Terminate tilting first
|
||||
relay_chn_tilt_dispatch_cmd(chn_ctl->tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
if (cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
// Schedule for running forward
|
||||
chn_ctl->pending_cmd = cmd;
|
||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_FORWARD_PENDING);
|
||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
} else if (cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
// Run directly since it is the same direction
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_REVERSE);
|
||||
}
|
||||
break;
|
||||
case RELAY_CHN_STATE_TILT_REVERSE:
|
||||
// Terminate tilting first
|
||||
relay_chn_tilt_dispatch_cmd(chn_ctl->tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
if (cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
// Run directly since it is the same direction
|
||||
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_FORWARD);
|
||||
} else if (cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
// Schedule for running reverse
|
||||
chn_ctl->pending_cmd = cmd;
|
||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_REVERSE_PENDING);
|
||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default: ESP_LOGD(TAG, "relay_chn_evaluate: Unknown relay channel state!");
|
||||
}
|
||||
}
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
bool relay_chn_is_channel_id_valid(uint8_t chn_id)
|
||||
{
|
||||
bool valid = (chn_id < RELAY_CHN_COUNT) || chn_id == RELAY_CHN_ID_ALL;
|
||||
if (!valid) {
|
||||
ESP_LOGE(TAG, "Invalid channel ID: %d", chn_id);
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
|
||||
static void relay_chn_execute_stop(relay_chn_ctl_t *chn_ctl)
|
||||
{
|
||||
if (relay_chn_output_stop(chn_ctl->output) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_execute_stop: Failed to output stop for relay channel #%d!", chn_ctl->id);
|
||||
}
|
||||
relay_chn_state_t previous_state = chn_ctl->state;
|
||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_STOPPED);
|
||||
|
||||
// If there is any pending command, cancel it since the STOP command is issued right after it
|
||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||
// Invalidate the channel's timer if it is active
|
||||
esp_timer_stop(chn_ctl->inertia_timer);
|
||||
|
||||
// Save the last run time only if the previous state was either STATE FORWARD
|
||||
// or STATE_REVERSE. Then schedule a free command.
|
||||
if (previous_state == RELAY_CHN_STATE_FORWARD || previous_state == RELAY_CHN_STATE_REVERSE) {
|
||||
// Record the command's last run time
|
||||
relay_chn_run_info_set_last_run_cmd_time_ms(chn_ctl->run_info, (uint32_t)(esp_timer_get_time() / 1000));
|
||||
// Schedule a free command for the channel
|
||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_IDLE;
|
||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
} else {
|
||||
// If the channel was not running one of the run or fwd, issue a free command immediately
|
||||
relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void relay_chn_execute_forward(relay_chn_ctl_t *chn_ctl)
|
||||
{
|
||||
if (relay_chn_output_forward(chn_ctl->output) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_execute_forward: Failed to output forward for relay channel #%d!", chn_ctl->id);
|
||||
return;
|
||||
}
|
||||
relay_chn_run_info_set_last_run_cmd(chn_ctl->run_info, RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_FORWARD);
|
||||
}
|
||||
|
||||
static void relay_chn_execute_reverse(relay_chn_ctl_t *chn_ctl)
|
||||
{
|
||||
if (relay_chn_output_reverse(chn_ctl->output) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_execute_reverse: Failed to output reverse for relay channel #%d!", chn_ctl->id);
|
||||
return;
|
||||
}
|
||||
relay_chn_run_info_set_last_run_cmd(chn_ctl->run_info, RELAY_CHN_CMD_REVERSE);
|
||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_REVERSE);
|
||||
}
|
||||
|
||||
static void relay_chn_execute_flip(relay_chn_ctl_t *chn_ctl)
|
||||
{
|
||||
relay_chn_output_flip(chn_ctl->output);
|
||||
// Set an inertia on the channel to prevent any immediate movement
|
||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_IDLE;
|
||||
relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
}
|
||||
|
||||
void relay_chn_execute_idle(relay_chn_ctl_t *chn_ctl)
|
||||
{
|
||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||
// Invalidate the channel's timer if it is active
|
||||
esp_timer_stop(chn_ctl->inertia_timer);
|
||||
relay_chn_update_state(chn_ctl, RELAY_CHN_STATE_IDLE);
|
||||
}
|
||||
|
||||
static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
|
||||
{
|
||||
relay_chn_ctl_t* chn_ctl = *(relay_chn_ctl_t**) event_data;
|
||||
ESP_RETURN_VOID_ON_FALSE(chn_ctl != NULL, TAG, "event_data is NULL");
|
||||
ESP_LOGD(TAG, "relay_chn_event_handler: Command: %s", relay_chn_cmd_str(event_id));
|
||||
|
||||
switch (event_id) {
|
||||
case RELAY_CHN_CMD_STOP:
|
||||
relay_chn_execute_stop(chn_ctl);
|
||||
break;
|
||||
case RELAY_CHN_CMD_FORWARD:
|
||||
relay_chn_execute_forward(chn_ctl);
|
||||
break;
|
||||
case RELAY_CHN_CMD_REVERSE:
|
||||
relay_chn_execute_reverse(chn_ctl);
|
||||
break;
|
||||
case RELAY_CHN_CMD_FLIP:
|
||||
relay_chn_execute_flip(chn_ctl);
|
||||
break;
|
||||
case RELAY_CHN_CMD_IDLE:
|
||||
relay_chn_execute_idle(chn_ctl);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGD(TAG, "Unknown relay channel command!");
|
||||
}
|
||||
}
|
||||
|
||||
char *relay_chn_cmd_str(relay_chn_cmd_t cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case RELAY_CHN_CMD_STOP:
|
||||
return "STOP";
|
||||
case RELAY_CHN_CMD_FORWARD:
|
||||
return "FORWARD";
|
||||
case RELAY_CHN_CMD_REVERSE:
|
||||
return "REVERSE";
|
||||
case RELAY_CHN_CMD_FLIP:
|
||||
return "FLIP";
|
||||
case RELAY_CHN_CMD_IDLE:
|
||||
return "IDLE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
char *relay_chn_state_str(relay_chn_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case RELAY_CHN_STATE_IDLE:
|
||||
return "IDLE";
|
||||
case RELAY_CHN_STATE_STOPPED:
|
||||
return "STOPPED";
|
||||
case RELAY_CHN_STATE_FORWARD:
|
||||
return "FORWARD";
|
||||
case RELAY_CHN_STATE_REVERSE:
|
||||
return "REVERSE";
|
||||
case RELAY_CHN_STATE_FORWARD_PENDING:
|
||||
return "FORWARD_PENDING";
|
||||
case RELAY_CHN_STATE_REVERSE_PENDING:
|
||||
return "REVERSE_PENDING";
|
||||
#if RELAY_CHN_ENABLE_TILTING == 1
|
||||
case RELAY_CHN_STATE_TILT_FORWARD:
|
||||
return "TILT_FORWARD";
|
||||
case RELAY_CHN_STATE_TILT_REVERSE:
|
||||
return "TILT_REVERSE";
|
||||
#endif
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
137
src/relay_chn_ctl_multi.c
Normal file
137
src/relay_chn_ctl_multi.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "relay_chn_priv_types.h"
|
||||
#include "relay_chn_core.h"
|
||||
#include "relay_chn_ctl.h"
|
||||
#include "relay_chn_output.h"
|
||||
|
||||
static const char *TAG = "RELAY_CHN_CTL";
|
||||
|
||||
static relay_chn_ctl_t chn_ctls[RELAY_CHN_COUNT];
|
||||
|
||||
|
||||
esp_err_t relay_chn_ctl_init(relay_chn_output_t *outputs, relay_chn_run_info_t *run_infos)
|
||||
{
|
||||
// Initialize all relay channels
|
||||
esp_err_t ret;
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_ctl_t* chn_ctl = &chn_ctls[i];
|
||||
relay_chn_output_t* output = &outputs[i];
|
||||
relay_chn_run_info_t* run_info = &run_infos[i];
|
||||
|
||||
chn_ctl->id = i;
|
||||
chn_ctl->state = RELAY_CHN_STATE_IDLE;
|
||||
chn_ctl->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||
|
||||
chn_ctl->output = output;
|
||||
chn_ctl->run_info = run_info;
|
||||
ret = relay_chn_init_timer(chn_ctl); // Create direction change inertia timer
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create relay channel timer for channel %d", i);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void relay_chn_ctl_deinit()
|
||||
{
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_ctl_t* chn_ctl = &chn_ctls[i];
|
||||
if (chn_ctl->inertia_timer != NULL) {
|
||||
esp_timer_delete(chn_ctl->inertia_timer);
|
||||
chn_ctl->inertia_timer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relay_chn_state_t relay_chn_ctl_get_state(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) {
|
||||
return RELAY_CHN_STATE_UNDEFINED;
|
||||
}
|
||||
return chn_ctls[chn_id].state;
|
||||
}
|
||||
|
||||
char *relay_chn_ctl_get_state_str(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) {
|
||||
return relay_chn_state_str(RELAY_CHN_STATE_UNDEFINED);
|
||||
}
|
||||
return relay_chn_state_str(chn_ctls[chn_id].state);
|
||||
}
|
||||
|
||||
static void relay_chn_ctl_issue_cmd_on_all_channels(relay_chn_cmd_t cmd)
|
||||
{
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_issue_cmd(&chn_ctls[i], cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void relay_chn_ctl_run_forward(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_FORWARD);
|
||||
return;
|
||||
}
|
||||
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_FORWARD);
|
||||
}
|
||||
|
||||
void relay_chn_ctl_run_reverse(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_REVERSE);
|
||||
return;
|
||||
}
|
||||
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_REVERSE);
|
||||
}
|
||||
|
||||
void relay_chn_ctl_stop(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_STOP);
|
||||
}
|
||||
|
||||
void relay_chn_ctl_flip_direction(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_FLIP);
|
||||
return;
|
||||
}
|
||||
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_FLIP);
|
||||
}
|
||||
|
||||
relay_chn_direction_t relay_chn_ctl_get_direction(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return RELAY_CHN_DIRECTION_DEFAULT;
|
||||
}
|
||||
relay_chn_ctl_t *chn_ctl = &chn_ctls[chn_id];
|
||||
return relay_chn_output_get_direction(chn_ctl->output);
|
||||
}
|
||||
|
||||
relay_chn_ctl_t *relay_chn_ctl_get(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return NULL;
|
||||
}
|
||||
return &chn_ctls[chn_id];
|
||||
}
|
||||
|
||||
relay_chn_ctl_t *relay_chn_ctl_get_all(void)
|
||||
{
|
||||
return chn_ctls;
|
||||
}
|
||||
76
src/relay_chn_ctl_single.c
Normal file
76
src/relay_chn_ctl_single.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "relay_chn_priv_types.h"
|
||||
#include "relay_chn_core.h"
|
||||
#include "relay_chn_ctl.h"
|
||||
#include "relay_chn_output.h"
|
||||
|
||||
|
||||
static relay_chn_ctl_t chn_ctl;
|
||||
|
||||
|
||||
esp_err_t relay_chn_ctl_init(relay_chn_output_t *output, relay_chn_run_info_t *run_info)
|
||||
{
|
||||
// Initialize the relay channel
|
||||
chn_ctl.id = 0; // Single channel, so ID is 0
|
||||
chn_ctl.state = RELAY_CHN_STATE_IDLE;
|
||||
chn_ctl.pending_cmd = RELAY_CHN_CMD_NONE;
|
||||
chn_ctl.output = output;
|
||||
chn_ctl.run_info = run_info;
|
||||
return relay_chn_init_timer(&chn_ctl); // Create direction change inertia timer
|
||||
}
|
||||
|
||||
|
||||
void relay_chn_ctl_deinit()
|
||||
{
|
||||
if (chn_ctl.inertia_timer != NULL) {
|
||||
esp_timer_delete(chn_ctl.inertia_timer);
|
||||
chn_ctl.inertia_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* relay_chn APIs */
|
||||
relay_chn_state_t relay_chn_ctl_get_state()
|
||||
{
|
||||
return chn_ctl.state;
|
||||
}
|
||||
|
||||
char *relay_chn_ctl_get_state_str()
|
||||
{
|
||||
return relay_chn_state_str(chn_ctl.state);
|
||||
}
|
||||
|
||||
void relay_chn_ctl_run_forward()
|
||||
{
|
||||
relay_chn_issue_cmd(&chn_ctl, RELAY_CHN_CMD_FORWARD);
|
||||
}
|
||||
|
||||
void relay_chn_ctl_run_reverse()
|
||||
{
|
||||
relay_chn_issue_cmd(&chn_ctl, RELAY_CHN_CMD_REVERSE);
|
||||
}
|
||||
|
||||
void relay_chn_ctl_stop()
|
||||
{
|
||||
relay_chn_issue_cmd(&chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
}
|
||||
|
||||
void relay_chn_ctl_flip_direction()
|
||||
{
|
||||
relay_chn_issue_cmd(&chn_ctl, RELAY_CHN_CMD_FLIP);
|
||||
}
|
||||
|
||||
relay_chn_direction_t relay_chn_ctl_get_direction()
|
||||
{
|
||||
return relay_chn_output_get_direction(chn_ctl.output);
|
||||
}
|
||||
/* relay_chn APIs */
|
||||
|
||||
relay_chn_ctl_t *relay_chn_ctl_get()
|
||||
{
|
||||
return &chn_ctl;
|
||||
}
|
||||
168
src/relay_chn_output.c
Normal file
168
src/relay_chn_output.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "relay_chn_defs.h"
|
||||
#include "relay_chn_output.h"
|
||||
#include "relay_chn_core.h"
|
||||
|
||||
|
||||
static const char *TAG = "RELAY_CHN_OUTPUT";
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
static relay_chn_output_t outputs[RELAY_CHN_COUNT];
|
||||
#else
|
||||
static relay_chn_output_t output;
|
||||
#endif
|
||||
|
||||
|
||||
static esp_err_t relay_chn_output_check_gpio_capabilities(uint8_t gpio_count)
|
||||
{
|
||||
// Check if the device's GPIOs are enough for the number of channels
|
||||
if (RELAY_CHN_COUNT > (GPIO_PIN_COUNT / 2)) {
|
||||
ESP_LOGE(TAG, "Not enough GPIOs for the number of channels!");
|
||||
ESP_LOGE(TAG, "Max available num of channels: %d, requested channels: %d", GPIO_PIN_COUNT / 2, RELAY_CHN_COUNT);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Check if the provided GPIOs correspond to the number of channels
|
||||
if (gpio_count != RELAY_CHN_COUNT * 2) {
|
||||
ESP_LOGE(TAG, "Invalid number of GPIOs provided: %d", gpio_count);
|
||||
ESP_LOGE(TAG, "Expected number of GPIOs: %d", RELAY_CHN_COUNT * 2);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t relay_chn_output_ctl_init(relay_chn_output_t *output, gpio_num_t forward_pin, gpio_num_t reverse_pin)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(forward_pin), ESP_ERR_INVALID_ARG, TAG,
|
||||
"Invalid GPIO pin number for forward_pin: %d", forward_pin);
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(reverse_pin), ESP_ERR_INVALID_ARG, TAG,
|
||||
"Invalid GPIO pin number for reverse_pin: %d", reverse_pin);
|
||||
|
||||
// Check if the GPIOs are valid
|
||||
esp_err_t ret;
|
||||
// Initialize the GPIOs
|
||||
ret = gpio_reset_pin(forward_pin);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to reset GPIO forward pin: %d", forward_pin);
|
||||
ret = gpio_set_direction(forward_pin, GPIO_MODE_OUTPUT);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set GPIO direction for forward pin: %d", forward_pin);
|
||||
|
||||
ret = gpio_reset_pin(reverse_pin);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to reset GPIO reverse pin: %d", reverse_pin);
|
||||
ret = gpio_set_direction(reverse_pin, GPIO_MODE_OUTPUT);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set GPIO direction for reverse pin: %d", reverse_pin);
|
||||
// Initialize the GPIOs
|
||||
|
||||
// Initialize the relay channel output
|
||||
output->forward_pin = forward_pin;
|
||||
output->reverse_pin = reverse_pin;
|
||||
output->direction = RELAY_CHN_DIRECTION_DEFAULT;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = relay_chn_output_check_gpio_capabilities(gpio_count);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Device does not support the provided GPIOs");
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_output_t* output = &outputs[i];
|
||||
int gpio_index = i << 1; // gpio_index = i * 2
|
||||
gpio_num_t forward_pin = (gpio_num_t) gpio_map[gpio_index];
|
||||
gpio_num_t reverse_pin = (gpio_num_t) gpio_map[gpio_index + 1];
|
||||
|
||||
ret = relay_chn_output_ctl_init(output, forward_pin, reverse_pin);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel %d", i);
|
||||
}
|
||||
#else
|
||||
ret = relay_chn_output_ctl_init(&output, gpio_map[0], gpio_map[1]);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel");
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void relay_chn_output_ctl_deinit(relay_chn_output_t *output)
|
||||
{
|
||||
gpio_reset_pin(output->forward_pin);
|
||||
gpio_reset_pin(output->reverse_pin);
|
||||
}
|
||||
|
||||
void relay_chn_output_deinit()
|
||||
{
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_output_ctl_deinit(&outputs[i]);
|
||||
}
|
||||
#else
|
||||
relay_chn_output_ctl_deinit(&output);
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
}
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
relay_chn_output_t *relay_chn_output_get(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return NULL;
|
||||
}
|
||||
return &outputs[chn_id];
|
||||
}
|
||||
|
||||
relay_chn_output_t *relay_chn_output_get_all(void)
|
||||
{
|
||||
return outputs;
|
||||
}
|
||||
#else
|
||||
relay_chn_output_t *relay_chn_output_get(void)
|
||||
{
|
||||
return &output;
|
||||
}
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
esp_err_t relay_chn_output_stop(relay_chn_output_t *output)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = gpio_set_level(output->forward_pin, 0);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to LOW");
|
||||
return gpio_set_level(output->reverse_pin, 0);
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_output_forward(relay_chn_output_t *output)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = gpio_set_level(output->forward_pin, 1);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to HIGH");
|
||||
return gpio_set_level(output->reverse_pin, 0);
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_output_reverse(relay_chn_output_t *output)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = gpio_set_level(output->forward_pin, 0);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to LOW");
|
||||
return gpio_set_level(output->reverse_pin, 1);
|
||||
}
|
||||
|
||||
void relay_chn_output_flip(relay_chn_output_t *output)
|
||||
{
|
||||
// Flip the output GPIO pins
|
||||
gpio_num_t temp = output->forward_pin;
|
||||
output->forward_pin = output->reverse_pin;
|
||||
output->reverse_pin = temp;
|
||||
// Flip the direction
|
||||
output->direction = (output->direction == RELAY_CHN_DIRECTION_DEFAULT)
|
||||
? RELAY_CHN_DIRECTION_FLIPPED
|
||||
: RELAY_CHN_DIRECTION_DEFAULT;
|
||||
}
|
||||
|
||||
relay_chn_direction_t relay_chn_output_get_direction(relay_chn_output_t *output)
|
||||
{
|
||||
return output->direction;
|
||||
}
|
||||
74
src/relay_chn_run_info.c
Normal file
74
src/relay_chn_run_info.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "relay_chn_core.h"
|
||||
#include "relay_chn_run_info.h"
|
||||
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
static relay_chn_run_info_t run_infos[RELAY_CHN_COUNT];
|
||||
#else
|
||||
static relay_chn_run_info_t run_info;
|
||||
#endif
|
||||
|
||||
void relay_chn_run_info_init()
|
||||
{
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
run_infos[i].last_run_cmd = RELAY_CHN_CMD_NONE;
|
||||
run_infos[i].last_run_cmd_time_ms = 0;
|
||||
}
|
||||
#else
|
||||
run_info.last_run_cmd = RELAY_CHN_CMD_NONE;
|
||||
run_info.last_run_cmd_time_ms = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
relay_chn_run_info_t *relay_chn_run_info_get(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return NULL;
|
||||
}
|
||||
return &run_infos[chn_id];
|
||||
}
|
||||
|
||||
relay_chn_run_info_t *relay_chn_run_info_get_all()
|
||||
{
|
||||
return run_infos;
|
||||
}
|
||||
#else
|
||||
relay_chn_run_info_t *relay_chn_run_info_get()
|
||||
{
|
||||
return &run_info;
|
||||
}
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
relay_chn_cmd_t relay_chn_run_info_get_last_run_cmd(relay_chn_run_info_t *run_info)
|
||||
{
|
||||
return run_info == NULL ? RELAY_CHN_CMD_NONE : run_info->last_run_cmd;
|
||||
}
|
||||
|
||||
void relay_chn_run_info_set_last_run_cmd(relay_chn_run_info_t *run_info, relay_chn_cmd_t cmd)
|
||||
{
|
||||
if (!run_info) {
|
||||
return;
|
||||
}
|
||||
run_info->last_run_cmd = cmd;
|
||||
}
|
||||
|
||||
uint32_t relay_chn_run_info_get_last_run_cmd_time_ms(relay_chn_run_info_t *run_info)
|
||||
{
|
||||
return run_info == NULL ? 0 : run_info->last_run_cmd_time_ms;
|
||||
}
|
||||
|
||||
void relay_chn_run_info_set_last_run_cmd_time_ms(relay_chn_run_info_t *run_info, uint32_t time_ms)
|
||||
{
|
||||
if (!run_info) {
|
||||
return;
|
||||
}
|
||||
run_info->last_run_cmd_time_ms = time_ms;
|
||||
}
|
||||
634
src/relay_chn_tilt.c
Normal file
634
src/relay_chn_tilt.c
Normal file
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "relay_chn_core.h"
|
||||
#include "relay_chn_output.h"
|
||||
#include "relay_chn_run_info.h"
|
||||
#include "relay_chn_tilt.h"
|
||||
|
||||
|
||||
static const char *TAG = "RELAY_CHN_TILT";
|
||||
|
||||
/**@{*/
|
||||
/*
|
||||
* Tilt Pattern Timing Definitions
|
||||
*
|
||||
* The min and max timing definitions as well as the default timing definitions.
|
||||
* These definitions are used to define and adjust the tilt sensitivity.
|
||||
*/
|
||||
#define RELAY_CHN_TILT_RUN_MIN_MS 50
|
||||
#define RELAY_CHN_TILT_RUN_MAX_MS 10
|
||||
#define RELAY_CHN_TILT_PAUSE_MIN_MS 450
|
||||
#define RELAY_CHN_TILT_PAUSE_MAX_MS 90
|
||||
|
||||
#define RELAY_CHN_TILT_DEFAULT_RUN_MS 15
|
||||
#define RELAY_CHN_TILT_DEFAULT_PAUSE_MS 150
|
||||
|
||||
#define RELAY_CHN_TILT_DEFAULT_SENSITIVITY \
|
||||
( (RELAY_CHN_TILT_DEFAULT_RUN_MS - RELAY_CHN_TILT_RUN_MIN_MS) \
|
||||
* 100 / (RELAY_CHN_TILT_RUN_MAX_MS - RELAY_CHN_TILT_RUN_MIN_MS) )
|
||||
/**@}*/
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(RELAY_CHN_TILT_CMD_EVENT_BASE);
|
||||
|
||||
|
||||
/// @brief Tilt steps.
|
||||
typedef enum {
|
||||
RELAY_CHN_TILT_STEP_NONE, /*!< No step */
|
||||
RELAY_CHN_TILT_STEP_PENDING, /*!< Pending step */
|
||||
RELAY_CHN_TILT_STEP_MOVE, /*!< Move step. Tilt is driving either for forward or reverse */
|
||||
RELAY_CHN_TILT_STEP_PAUSE /*!< Pause step. Tilt is paused */
|
||||
} relay_chn_tilt_step_t;
|
||||
|
||||
/// @brief Tilt timing structure to manage tilt pattern timing.
|
||||
typedef struct {
|
||||
uint8_t sensitivity; /*!< Tilt sensitivity in percentage (%) */
|
||||
uint32_t move_time_ms; /*!< Move time in milliseconds */
|
||||
uint32_t pause_time_ms; /*!< Pause time in milliseconds */
|
||||
} relay_chn_tilt_timing_t;
|
||||
|
||||
/// @brief Tilt counter structure to manage tilt count.
|
||||
typedef struct {
|
||||
uint32_t tilt_forward_count; /*!< Tilt forward count */
|
||||
uint32_t tilt_reverse_count; /*!< Tilt reverse count */
|
||||
} relay_chn_tilt_counter_t;
|
||||
|
||||
/// @brief Tilt control structure to manage tilt operations.
|
||||
typedef struct relay_chn_tilt_ctl {
|
||||
relay_chn_ctl_t *chn_ctl; /*!< The relay channel control structure */
|
||||
relay_chn_tilt_cmd_t cmd; /*!< The tilt command in process */
|
||||
relay_chn_tilt_step_t step; /*!< Current tilt step */
|
||||
relay_chn_tilt_timing_t tilt_timing; /*!< Tilt timing structure */
|
||||
relay_chn_tilt_counter_t tilt_counter; /*!< Tilt counter structure */
|
||||
esp_timer_handle_t tilt_timer; /*!< Tilt timer handle */
|
||||
} relay_chn_tilt_ctl_t;
|
||||
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
static relay_chn_tilt_ctl_t tilt_ctls[RELAY_CHN_COUNT];
|
||||
#else
|
||||
static relay_chn_tilt_ctl_t tilt_ctl;
|
||||
#endif
|
||||
|
||||
|
||||
esp_err_t relay_chn_tilt_dispatch_cmd(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd)
|
||||
{
|
||||
if (cmd == RELAY_CHN_TILT_CMD_NONE) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
// Since the event_loop library creates a deep copy of the event data,
|
||||
// and we need to pass the pointer of the relevant tilt control, here we need
|
||||
// to pass the pointer to the pointer of the tilt_control (&tilt_ctl) so that
|
||||
// the pointer value is preserved in the event data.
|
||||
return esp_event_post_to(relay_chn_event_loop,
|
||||
RELAY_CHN_TILT_CMD_EVENT_BASE,
|
||||
cmd,
|
||||
&tilt_ctl,
|
||||
sizeof(tilt_ctl), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Returns the required timing before tilting depending on the last run.
|
||||
static uint32_t relay_chn_tilt_get_required_timing_before_tilting(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_tilt_cmd_t cmd)
|
||||
{
|
||||
relay_chn_cmd_t last_run_cmd = relay_chn_run_info_get_last_run_cmd(tilt_ctl->chn_ctl->run_info);
|
||||
if (cmd == RELAY_CHN_TILT_CMD_FORWARD && last_run_cmd == RELAY_CHN_CMD_REVERSE)
|
||||
return 0;
|
||||
else if (cmd == RELAY_CHN_TILT_CMD_REVERSE && last_run_cmd == RELAY_CHN_CMD_FORWARD)
|
||||
return 0;
|
||||
|
||||
uint32_t last_run_cmd_time_ms = relay_chn_run_info_get_last_run_cmd_time_ms(tilt_ctl->chn_ctl->run_info);
|
||||
uint32_t inertia_time_passed_ms = (uint32_t) (esp_timer_get_time() / 1000) - last_run_cmd_time_ms;
|
||||
return RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (relay_chn_run_info_get_last_run_cmd(tilt_ctl->chn_ctl->run_info) == RELAY_CHN_CMD_NONE) {
|
||||
// Do not tilt if the channel hasn't been run before
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_issue_cmd: Tilt will not be executed since the channel hasn't been run yet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tilt_ctl->cmd == cmd) {
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_issue_cmd: There is already a tilt command in progress!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the command that will be processed
|
||||
tilt_ctl->cmd = cmd;
|
||||
switch (tilt_ctl->chn_ctl->state) {
|
||||
case RELAY_CHN_STATE_IDLE:
|
||||
// Relay channel is free, tilt can be issued immediately
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, cmd);
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_FORWARD_PENDING:
|
||||
case RELAY_CHN_STATE_REVERSE_PENDING:
|
||||
// Issue a stop command first so that the timer and pending cmd get cleared
|
||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
// break not put intentionally
|
||||
case RELAY_CHN_STATE_STOPPED: {
|
||||
// Check if channel needs timing before tilting
|
||||
uint32_t req_timing_ms = relay_chn_tilt_get_required_timing_before_tilting(tilt_ctl, cmd);
|
||||
if (req_timing_ms == 0) {
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, cmd);
|
||||
} else {
|
||||
// Channel needs timing before running tilting action, schedule it
|
||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, req_timing_ms);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RELAY_CHN_STATE_FORWARD:
|
||||
if (cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
// Stop the running channel first
|
||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
// Schedule for tilting
|
||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
} else if (cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
// Stop the running channel first
|
||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
// If the tilt cmd is TILT_REVERSE then dispatch it immediately
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, cmd);
|
||||
}
|
||||
break;
|
||||
|
||||
case RELAY_CHN_STATE_REVERSE:
|
||||
if (cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
// Stop the running channel first
|
||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
// Schedule for tilting
|
||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PENDING;
|
||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||
} else if (cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
// Stop the running channel first
|
||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
// If the tilt cmd is TILT_FORWARD then dispatch it immediately
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, cmd);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_issue_cmd: Unexpected relay channel state: %s!", relay_chn_state_str(tilt_ctl->chn_ctl->state));
|
||||
}
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_issue_auto(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||
{
|
||||
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 || tilt_ctl->chn_ctl->state == RELAY_CHN_STATE_FORWARD) {
|
||||
relay_chn_tilt_issue_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_FORWARD);
|
||||
}
|
||||
else if (last_run_cmd == RELAY_CHN_CMD_REVERSE || tilt_ctl->chn_ctl->state == RELAY_CHN_STATE_REVERSE) {
|
||||
relay_chn_tilt_issue_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_REVERSE);
|
||||
}
|
||||
}
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
void relay_chn_tilt_auto(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute for all channels
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_tilt_issue_auto(&tilt_ctls[i]);
|
||||
}
|
||||
}
|
||||
// Execute for a single channel
|
||||
else {
|
||||
relay_chn_tilt_ctl_t* tilt_ctl = &tilt_ctls[chn_id];
|
||||
relay_chn_tilt_issue_auto(tilt_ctl);
|
||||
}
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_issue_cmd_on_all_channels(relay_chn_tilt_cmd_t cmd)
|
||||
{
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_tilt_ctl_t* tilt_ctl = &tilt_ctls[i];
|
||||
relay_chn_tilt_issue_cmd(tilt_ctl, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void relay_chn_tilt_forward(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL)
|
||||
relay_chn_tilt_issue_cmd_on_all_channels(RELAY_CHN_TILT_CMD_FORWARD);
|
||||
else {
|
||||
relay_chn_tilt_ctl_t* tilt_ctl = &tilt_ctls[chn_id];
|
||||
relay_chn_tilt_issue_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_FORWARD);
|
||||
}
|
||||
}
|
||||
|
||||
void relay_chn_tilt_reverse(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL)
|
||||
relay_chn_tilt_issue_cmd_on_all_channels(RELAY_CHN_TILT_CMD_REVERSE);
|
||||
else {
|
||||
relay_chn_tilt_ctl_t* tilt_ctl = &tilt_ctls[chn_id];
|
||||
relay_chn_tilt_issue_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_REVERSE);
|
||||
}
|
||||
}
|
||||
|
||||
void relay_chn_tilt_stop(uint8_t chn_id)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_tilt_dispatch_cmd(&tilt_ctls[i], RELAY_CHN_TILT_CMD_STOP);
|
||||
}
|
||||
}
|
||||
else {
|
||||
relay_chn_tilt_dispatch_cmd(&tilt_ctls[chn_id], RELAY_CHN_TILT_CMD_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
#else // RELAY_CHN_COUNT > 1
|
||||
|
||||
void relay_chn_tilt_auto()
|
||||
{
|
||||
relay_chn_tilt_issue_auto(&tilt_ctl);
|
||||
}
|
||||
|
||||
void relay_chn_tilt_forward()
|
||||
{
|
||||
relay_chn_tilt_issue_cmd(&tilt_ctl, RELAY_CHN_TILT_CMD_FORWARD);
|
||||
}
|
||||
|
||||
void relay_chn_tilt_reverse()
|
||||
{
|
||||
relay_chn_tilt_issue_cmd(&tilt_ctl, RELAY_CHN_TILT_CMD_REVERSE);
|
||||
}
|
||||
|
||||
void relay_chn_tilt_stop()
|
||||
{
|
||||
relay_chn_tilt_dispatch_cmd(&tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
}
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
static void relay_chn_tilt_set_timing_values(relay_chn_tilt_timing_t *tilt_timing,
|
||||
uint8_t sensitivity,
|
||||
uint32_t run_time_ms,
|
||||
uint32_t pause_time_ms)
|
||||
{
|
||||
tilt_timing->sensitivity = sensitivity;
|
||||
tilt_timing->move_time_ms = run_time_ms;
|
||||
tilt_timing->pause_time_ms = pause_time_ms;
|
||||
}
|
||||
|
||||
static void _relay_chn_tilt_sensitivity_set(relay_chn_tilt_ctl_t *tilt_ctl, uint8_t sensitivity)
|
||||
{
|
||||
if (sensitivity >= 100) {
|
||||
relay_chn_tilt_set_timing_values(&tilt_ctl->tilt_timing,
|
||||
100,
|
||||
RELAY_CHN_TILT_RUN_MAX_MS,
|
||||
RELAY_CHN_TILT_PAUSE_MAX_MS);
|
||||
}
|
||||
else if (sensitivity == 0) {
|
||||
relay_chn_tilt_set_timing_values(&tilt_ctl->tilt_timing,
|
||||
0,
|
||||
RELAY_CHN_TILT_RUN_MIN_MS,
|
||||
RELAY_CHN_TILT_PAUSE_MIN_MS);
|
||||
}
|
||||
else {
|
||||
// Compute the new timing values from the sensitivity percent value by using linear interpolation
|
||||
uint32_t tilt_run_time_ms = 0, tilt_pause_time_ms = 0;
|
||||
tilt_run_time_ms = RELAY_CHN_TILT_RUN_MIN_MS + (sensitivity * (RELAY_CHN_TILT_RUN_MAX_MS - RELAY_CHN_TILT_RUN_MIN_MS) / 100);
|
||||
tilt_pause_time_ms = RELAY_CHN_TILT_PAUSE_MIN_MS + (sensitivity * (RELAY_CHN_TILT_PAUSE_MAX_MS - RELAY_CHN_TILT_PAUSE_MIN_MS) / 100);
|
||||
|
||||
relay_chn_tilt_set_timing_values(&tilt_ctl->tilt_timing,
|
||||
sensitivity,
|
||||
tilt_run_time_ms,
|
||||
tilt_pause_time_ms);
|
||||
}
|
||||
}
|
||||
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
void relay_chn_tilt_set_sensitivity(uint8_t chn_id, uint8_t sensitivity)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
_relay_chn_tilt_sensitivity_set(&tilt_ctls[i], sensitivity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_relay_chn_tilt_sensitivity_set(&tilt_ctls[chn_id], sensitivity);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_tilt_get_sensitivity(uint8_t chn_id, uint8_t *sensitivity, size_t length)
|
||||
{
|
||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (sensitivity == NULL) {
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_get_sensitivity: sensitivity is NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
||||
if (length < RELAY_CHN_COUNT) {
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_get_sensitivity: length is too short to store all sensitivity values");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
sensitivity[i] = tilt_ctls[i].tilt_timing.sensitivity;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
*sensitivity = tilt_ctls[chn_id].tilt_timing.sensitivity;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void relay_chn_tilt_set_sensitivity(uint8_t sensitivity)
|
||||
{
|
||||
_relay_chn_tilt_sensitivity_set(&tilt_ctl, sensitivity);
|
||||
}
|
||||
|
||||
uint8_t relay_chn_tilt_get_sensitivity()
|
||||
{
|
||||
return tilt_ctl.tilt_timing.sensitivity;
|
||||
}
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
void relay_chn_tilt_reset_count(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||
{
|
||||
tilt_ctl->tilt_counter.tilt_forward_count = 0;
|
||||
tilt_ctl->tilt_counter.tilt_reverse_count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update tilt count automatically and return the current value.
|
||||
*
|
||||
* This helper function updates the relevant tilt count depending on the
|
||||
* last run info and helps the tilt module in deciding whether the requested
|
||||
* tilt should execute or not.
|
||||
* This is useful to control reverse tilting particularly. For example:
|
||||
* - If the channel's last run was FORWARD and a TILT_FORWARD is requested,
|
||||
* then the tilt counter will count up on the
|
||||
* relay_chn_tilt_counter_type::tilt_forward_count and the function will
|
||||
* return the actual count.
|
||||
* - If the channel's last run was FORWARD and a TILT_REVERSE is requested,
|
||||
* then the relay_chn_tilt_counter_type::tilt_forward_count will be checked
|
||||
* against zero first, and then it will count down and return the actual count
|
||||
* if it is greater than 0, else the function will return 0.
|
||||
* - If the tilt command is irrelevant then the function will return 0.
|
||||
* - If the last run is irrelevant then the function will return 0.
|
||||
*
|
||||
* @param tilt_ctl The relay channel handle.
|
||||
* @return uint32_t The actual value of the relevant counter.
|
||||
* @return 0 if:
|
||||
* - related counter is already 0.
|
||||
* - tilt command is irrelevant.
|
||||
* - last run info is irrelevant.
|
||||
*/
|
||||
static uint32_t relay_chn_tilt_count_update(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||
{
|
||||
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) {
|
||||
if (tilt_ctl->cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
return ++tilt_ctl->tilt_counter.tilt_forward_count;
|
||||
}
|
||||
else if (tilt_ctl->cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
if (tilt_ctl->tilt_counter.tilt_forward_count > 0) {
|
||||
--tilt_ctl->tilt_counter.tilt_forward_count;
|
||||
// Still should do one more move, return non-zero value
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
relay_chn_tilt_reset_count(tilt_ctl);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (last_run_cmd == RELAY_CHN_CMD_REVERSE) {
|
||||
if (tilt_ctl->cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
return ++tilt_ctl->tilt_counter.tilt_reverse_count;
|
||||
}
|
||||
else if (tilt_ctl->cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
if (tilt_ctl->tilt_counter.tilt_reverse_count > 0) {
|
||||
--tilt_ctl->tilt_counter.tilt_reverse_count;
|
||||
// Still should do one more move, return non-zero value
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
relay_chn_tilt_reset_count(tilt_ctl);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_execute_stop(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||
{
|
||||
// Stop the channel's timer if active
|
||||
esp_timer_stop(tilt_ctl->tilt_timer);
|
||||
// Invalidate tilt cmd and step
|
||||
tilt_ctl->cmd = RELAY_CHN_TILT_CMD_NONE;
|
||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_NONE;
|
||||
// Stop the channel
|
||||
if (relay_chn_output_stop(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_stop: Failed to output stop for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
||||
}
|
||||
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_execute_forward(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||
{
|
||||
if (relay_chn_output_reverse(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_forward: Failed to output reverse for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
||||
// Stop tilting because of the error
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
// Set the move time timer
|
||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.move_time_ms);
|
||||
// Set to pause step
|
||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PAUSE;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_execute_reverse(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||
{
|
||||
if (relay_chn_output_forward(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_reverse: Failed to output forward for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
||||
// Stop tilting because of the error
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
// Set the move time timer
|
||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.move_time_ms);
|
||||
// Set to pause step
|
||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_PAUSE;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_execute_pause(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||
{
|
||||
// Pause the channel
|
||||
if (relay_chn_output_stop(tilt_ctl->chn_ctl->output) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "relay_chn_tilt_execute_pause: Failed to output stop for relay channel #%d!", tilt_ctl->chn_ctl->id);
|
||||
// Stop tilting because of the error
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the tilt counter before the next move and expect the return value to be greater than 0
|
||||
if (relay_chn_tilt_count_update(tilt_ctl) == 0) {
|
||||
ESP_LOGD(TAG, "relay_chn_tilt_execute_pause: Relay channel cannot tilt anymore");
|
||||
// Stop tilting since the tilting limit has been reached
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, RELAY_CHN_TILT_CMD_STOP);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the pause time timer
|
||||
relay_chn_start_esp_timer_once(tilt_ctl->tilt_timer, tilt_ctl->tilt_timing.pause_time_ms);
|
||||
// Set to move step
|
||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_MOVE;
|
||||
}
|
||||
|
||||
static void relay_chn_tilt_event_handler(void *handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||
{
|
||||
relay_chn_tilt_ctl_t* tilt_ctl = *(relay_chn_tilt_ctl_t**) event_data;
|
||||
ESP_RETURN_VOID_ON_FALSE(tilt_ctl != NULL, TAG, "event_data is NULL");
|
||||
ESP_LOGD(TAG, "relay_chn_event_handler: Command: %s", relay_chn_cmd_str(event_id));
|
||||
|
||||
switch(event_id) {
|
||||
case RELAY_CHN_TILT_CMD_STOP:
|
||||
relay_chn_tilt_execute_stop(tilt_ctl);
|
||||
break;
|
||||
case RELAY_CHN_TILT_CMD_FORWARD:
|
||||
relay_chn_tilt_execute_forward(tilt_ctl);
|
||||
// Update channel state
|
||||
relay_chn_update_state(tilt_ctl->chn_ctl, RELAY_CHN_STATE_TILT_FORWARD);
|
||||
break;
|
||||
case RELAY_CHN_TILT_CMD_REVERSE:
|
||||
relay_chn_tilt_execute_reverse(tilt_ctl);
|
||||
// Update channel state
|
||||
relay_chn_update_state(tilt_ctl->chn_ctl, RELAY_CHN_STATE_TILT_REVERSE);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unexpected relay channel tilt command: %ld!", event_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Timer callback for the relay_chn_tilt_control_t::tilt_timer
|
||||
static void relay_chn_tilt_timer_cb(void *arg)
|
||||
{
|
||||
relay_chn_tilt_ctl_t* tilt_ctl = (relay_chn_tilt_ctl_t*) arg;
|
||||
ESP_RETURN_VOID_ON_FALSE(tilt_ctl != NULL, TAG, "relay_chn_tilt_timer_cb: event_data is NULL");
|
||||
|
||||
switch (tilt_ctl->step)
|
||||
{
|
||||
case RELAY_CHN_TILT_STEP_MOVE:
|
||||
if (tilt_ctl->cmd == RELAY_CHN_TILT_CMD_FORWARD) {
|
||||
relay_chn_tilt_execute_forward(tilt_ctl);
|
||||
}
|
||||
else if (tilt_ctl->cmd == RELAY_CHN_TILT_CMD_REVERSE) {
|
||||
relay_chn_tilt_execute_reverse(tilt_ctl);
|
||||
}
|
||||
break;
|
||||
|
||||
case RELAY_CHN_TILT_STEP_PAUSE:
|
||||
relay_chn_tilt_execute_pause(tilt_ctl);
|
||||
break;
|
||||
|
||||
case RELAY_CHN_TILT_STEP_PENDING:
|
||||
// Just dispatch the pending tilt command
|
||||
relay_chn_tilt_dispatch_cmd(tilt_ctl, tilt_ctl->cmd);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_tilt_ctl_init(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_ctl_t *chn_ctl)
|
||||
{
|
||||
tilt_ctl->cmd = RELAY_CHN_TILT_CMD_NONE;
|
||||
tilt_ctl->step = RELAY_CHN_TILT_STEP_NONE;
|
||||
tilt_ctl->tilt_timing.sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
|
||||
tilt_ctl->tilt_timing.move_time_ms = RELAY_CHN_TILT_DEFAULT_RUN_MS;
|
||||
tilt_ctl->tilt_timing.pause_time_ms = RELAY_CHN_TILT_DEFAULT_PAUSE_MS;
|
||||
relay_chn_tilt_reset_count(tilt_ctl);
|
||||
|
||||
tilt_ctl->chn_ctl = chn_ctl;
|
||||
tilt_ctl->chn_ctl->tilt_ctl = tilt_ctl; //
|
||||
|
||||
// Create tilt timer for the channel
|
||||
char timer_name[32];
|
||||
snprintf(timer_name, sizeof(timer_name), "relay_chn_%2d_tilt_timer", chn_ctl->id);
|
||||
esp_timer_create_args_t timer_args = {
|
||||
.callback = relay_chn_tilt_timer_cb,
|
||||
.arg = tilt_ctl,
|
||||
.name = timer_name
|
||||
};
|
||||
return esp_timer_create(&timer_args, &tilt_ctl->tilt_timer);
|
||||
}
|
||||
|
||||
esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls)
|
||||
{
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_tilt_ctl_init(&tilt_ctls[i], &chn_ctls[i]);
|
||||
}
|
||||
#else
|
||||
relay_chn_tilt_ctl_init(&tilt_ctl, chn_ctls);
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
|
||||
return esp_event_handler_register_with(relay_chn_event_loop,
|
||||
RELAY_CHN_TILT_CMD_EVENT_BASE,
|
||||
ESP_EVENT_ANY_ID,
|
||||
relay_chn_tilt_event_handler, NULL);
|
||||
}
|
||||
|
||||
void relay_chn_tilt_ctl_deinit(relay_chn_tilt_ctl_t *tilt_ctl)
|
||||
{
|
||||
if (tilt_ctl->tilt_timer != NULL) {
|
||||
esp_timer_delete(tilt_ctl->tilt_timer);
|
||||
tilt_ctl->tilt_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void relay_chn_tilt_deinit()
|
||||
{
|
||||
#if RELAY_CHN_COUNT > 1
|
||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||
relay_chn_tilt_ctl_deinit(&tilt_ctls[i]);
|
||||
}
|
||||
#else
|
||||
relay_chn_tilt_ctl_deinit(&tilt_ctl);
|
||||
#endif // RELAY_CHN_COUNT > 1
|
||||
esp_event_handler_unregister_with(relay_chn_event_loop,
|
||||
RELAY_CHN_TILT_CMD_EVENT_BASE,
|
||||
ESP_EVENT_ANY_ID,
|
||||
relay_chn_tilt_event_handler);
|
||||
}
|
||||
@@ -1,14 +1,23 @@
|
||||
# === These files must be included in any case ===
|
||||
set(srcs "test_common.c"
|
||||
"test_app_main.c"
|
||||
"test_relay_chn_core.c"
|
||||
"test_relay_chn_listener.c")
|
||||
"test_app_main.c")
|
||||
|
||||
if(CONFIG_RELAY_CHN_ENABLE_TILTING)
|
||||
list(APPEND srcs "test_relay_chn_tilt.c")
|
||||
# === Selective compilation based on channel count ===
|
||||
if(CONFIG_RELAY_CHN_COUNT GREATER 1)
|
||||
list(APPEND srcs "test_relay_chn_core_multi.c"
|
||||
"test_relay_chn_listener_multi.c")
|
||||
else()
|
||||
list(APPEND srcs "test_relay_chn_core_single.c"
|
||||
"test_relay_chn_listener_single.c")
|
||||
endif()
|
||||
|
||||
message(STATUS "srcs=${srcs}")
|
||||
if(CONFIG_RELAY_CHN_ENABLE_TILTING)
|
||||
if(CONFIG_RELAY_CHN_COUNT GREATER 1)
|
||||
list(APPEND srcs "test_relay_chn_tilt_multi.c")
|
||||
else()
|
||||
list(APPEND srcs "test_relay_chn_tilt_single.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
|
||||
@@ -2,16 +2,38 @@
|
||||
|
||||
const char *TEST_TAG = "RELAY_CHN_TEST";
|
||||
|
||||
// GPIO eşlemesi (örn: GPIO_NUM_4 vs GPIO_NUM_5)
|
||||
const gpio_num_t gpio_map[] = {
|
||||
GPIO_NUM_4, GPIO_NUM_5, GPIO_NUM_18, GPIO_NUM_19
|
||||
};
|
||||
|
||||
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||
const uint8_t relay_chn_count = gpio_count / 2;
|
||||
|
||||
// Konfigürasyon tabanlı inertia süresi
|
||||
const uint8_t relay_chn_count = CONFIG_RELAY_CHN_COUNT;
|
||||
const uint32_t opposite_inertia_ms = CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS;
|
||||
const uint32_t test_delay_margin_ms = 50; // ms toleransı
|
||||
|
||||
bool g_is_component_initialized = false;
|
||||
|
||||
// Test-wide GPIO map
|
||||
#if CONFIG_RELAY_CHN_COUNT > 1
|
||||
const uint8_t gpio_map[] = {
|
||||
0, 1,
|
||||
2, 3
|
||||
#if CONFIG_RELAY_CHN_COUNT > 2
|
||||
, 4, 5
|
||||
#if CONFIG_RELAY_CHN_COUNT > 3
|
||||
, 6, 7
|
||||
#if CONFIG_RELAY_CHN_COUNT > 4
|
||||
, 8, 9
|
||||
#if CONFIG_RELAY_CHN_COUNT > 5
|
||||
, 10, 11
|
||||
#if CONFIG_RELAY_CHN_COUNT > 6
|
||||
, 12, 13
|
||||
#if CONFIG_RELAY_CHN_COUNT > 7
|
||||
, 14, 15
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
#else
|
||||
const uint8_t gpio_map[] = {4, 5};
|
||||
#endif
|
||||
|
||||
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||
@@ -3,23 +3,21 @@
|
||||
#include <string.h> // For memset
|
||||
#include "unity.h"
|
||||
#include "relay_chn.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
// Test log tag
|
||||
extern const char *TEST_TAG;
|
||||
|
||||
// GPIO konfigürasyonları
|
||||
extern const gpio_num_t gpio_map[];
|
||||
// GPIO configurations
|
||||
extern const uint8_t gpio_map[];
|
||||
extern const uint8_t gpio_count;
|
||||
extern const uint8_t relay_chn_count;
|
||||
|
||||
// Config parametreleri
|
||||
// Config variables for tests
|
||||
extern const uint32_t opposite_inertia_ms;
|
||||
extern const uint32_t test_delay_margin_ms;
|
||||
|
||||
// Init durumu
|
||||
// Init state
|
||||
extern bool g_is_component_initialized;
|
||||
|
||||
@@ -13,20 +13,20 @@ TEST_CASE("relay_chn_create handles invalid arguments", "[relay_chn][core]")
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 1));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 0));
|
||||
|
||||
// 3. Test with invalid GPIO numbers (GPIO_NUM_MAX is an invalid GPIO for output)
|
||||
gpio_num_t invalid_gpio_map[] = {GPIO_NUM_4, GPIO_NUM_MAX, GPIO_NUM_18, GPIO_NUM_19};
|
||||
// 3. Test with invalid GPIO numbers (127 is an invalid GPIO for output)
|
||||
uint8_t invalid_gpio_map[] = {4, 127, 18, 19};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(invalid_gpio_map, gpio_count));
|
||||
}
|
||||
|
||||
// --- Basic Functionality Tests ---
|
||||
|
||||
// TEST_CASE: Test that relay channels initialize correctly to RELAY_CHN_STATE_FREE
|
||||
// TEST_CASE: Test that relay channels initialize correctly to RELAY_CHN_STATE_IDLE
|
||||
TEST_CASE("Relay channels initialize correctly to FREE state", "[relay_chn][core]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ TEST_CASE("Run forward does nothing if channel id is invalid", "[relay_chn][core
|
||||
relay_chn_run_forward(invalid_id); // relay_chn_run_forward returns void
|
||||
// Short delay for state to update
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ TEST_CASE("Run reverse does nothing if channel id is invalid", "[relay_chn][core
|
||||
// Call run_reverse with an invalid ID
|
||||
relay_chn_run_reverse(invalid_id);
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,13 +127,13 @@ TEST_CASE("stop with ID_ALL stops all running channels", "[relay_chn][core][id_a
|
||||
|
||||
// 3. Verify all channels have transitioned to the FREE state
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TEST_CASE: Test that relays stop and transition to RELAY_CHN_STATE_FREE
|
||||
// TEST_CASE: Test that relays stop and transition to RELAY_CHN_STATE_IDLE
|
||||
// This test also verifies the transition to FREE state after a STOP command.
|
||||
TEST_CASE("Relay channels stop and update to FREE state", "[relay_chn][core]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
@@ -151,9 +151,9 @@ TEST_CASE("Relay channels stop and update to FREE state", "[relay_chn][core]") {
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||
|
||||
// Then, wait for the inertia period for it to transition to RELAY_CHN_STATE_FREE
|
||||
// Then, wait for the inertia period for it to transition to RELAY_CHN_STATE_IDLE
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ TEST_CASE("Multiple channels can operate independently", "[relay_chn][core]") {
|
||||
relay_chn_run_forward(0); // relay_chn_run_forward returns void
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(0));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(1)); // Other channel should not be affected
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(1)); // Other channel should not be affected
|
||||
|
||||
// Start Channel 1 in reverse direction
|
||||
relay_chn_run_reverse(1); // relay_chn_run_reverse returns void
|
||||
@@ -214,14 +214,14 @@ TEST_CASE("Multiple channels can operate independently", "[relay_chn][core]") {
|
||||
// Stop Channel 0 and wait for it to become FREE
|
||||
relay_chn_stop(0); // relay_chn_stop returns void
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(0));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(0));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(1)); // Other channel should continue running
|
||||
|
||||
// Stop Channel 1 and wait for it to become FREE
|
||||
relay_chn_stop(1); // relay_chn_stop returns void
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(0));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(1));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(0));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(1));
|
||||
} else {
|
||||
ESP_LOGW("TEST", "Skipping 'Multiple channels can operate independently' test: Not enough channels available.");
|
||||
}
|
||||
@@ -301,7 +301,7 @@ TEST_CASE("Running in same direction does not incur inertia", "[relay_chn][core]
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from FREE state to running (no inertia expected)
|
||||
// Scenario: RELAY_CHN_STATE_FREE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||
// Scenario: RELAY_CHN_STATE_IDLE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||
TEST_CASE("FREE to Running transition without inertia", "[relay_chn][core][inertia]") {
|
||||
uint8_t ch = 0;
|
||||
|
||||
@@ -309,7 +309,7 @@ TEST_CASE("FREE to Running transition without inertia", "[relay_chn][core][inert
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// setUp() should have already brought the channel to FREE state
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(ch));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch));
|
||||
|
||||
// Start in forward direction
|
||||
relay_chn_run_forward(ch); // relay_chn_run_forward returns void
|
||||
@@ -388,7 +388,7 @@ TEST_CASE("Flipping a running channel stops it and flips direction", "[relay_chn
|
||||
|
||||
// 4. Wait for the flip inertia to pass, after which it should be FREE and FLIPPED
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(ch));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(ch));
|
||||
}
|
||||
|
||||
204
test_apps/main/test_relay_chn_core_single.c
Normal file
204
test_apps/main/test_relay_chn_core_single.c
Normal file
@@ -0,0 +1,204 @@
|
||||
#include "test_common.h"
|
||||
|
||||
|
||||
// --- Initialization Tests ---
|
||||
|
||||
TEST_CASE("relay_chn_create handles invalid arguments", "[relay_chn][core]")
|
||||
{
|
||||
// 1. Test with NULL gpio_map
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(NULL, gpio_count));
|
||||
|
||||
// 2. Test with incorrect gpio_count (must be RELAY_CHN_COUNT * 2)
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, gpio_count - 1));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 1));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(gpio_map, 0));
|
||||
|
||||
// 3. Test with invalid GPIO numbers (GPIO_NUM_MAX is an invalid GPIO for output)
|
||||
uint8_t invalid_gpio_map[] = {4, 127};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_create(invalid_gpio_map, gpio_count));
|
||||
}
|
||||
|
||||
// --- Basic Functionality Tests ---
|
||||
|
||||
// TEST_CASE: Test that relay channels initialize correctly to RELAY_CHN_STATE_IDLE
|
||||
TEST_CASE("Relay channels initialize correctly to IDLE state", "[relay_chn][core]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test that relays run in the forward direction and update their state
|
||||
TEST_CASE("Relay channels run forward and update state", "[relay_chn][core]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
relay_chn_run_forward();
|
||||
// Short delay for state to update
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test that relays run in the reverse direction and update their state
|
||||
TEST_CASE("Relay channels run reverse and update state", "[relay_chn][core]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
relay_chn_run_reverse(); // relay_chn_run_reverse returns void
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
|
||||
// TEST_CASE: Test that relays stop and transition to RELAY_CHN_STATE_IDLE
|
||||
// This test also verifies the transition to IDLE state after a STOP command.
|
||||
TEST_CASE("Relay channels stop and update to IDLE state", "[relay_chn][core]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// First, run forward to test stopping and transitioning to IDLE state
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
|
||||
// Now, issue the stop command
|
||||
relay_chn_stop(); // relay_chn_stop returns void
|
||||
// Immediately after stop, state should be STOPPED
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||
|
||||
// Then, wait for the inertia period for it to transition to RELAY_CHN_STATE_IDLE
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
|
||||
// ### Inertia and State Transition Tests
|
||||
|
||||
// This section specifically targets the inertia periods and complex state transitions as per the component's logic.
|
||||
|
||||
// TEST_CASE: Test transition from forward to reverse with inertia and state checks
|
||||
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_REVERSE
|
||||
TEST_CASE("Forward to Reverse transition with opposite inertia", "[relay_chn][core][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// 1. Start in forward direction
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Short delay for state stabilization
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
|
||||
// 2. Issue reverse command
|
||||
relay_chn_run_reverse(); // relay_chn_run_reverse returns void
|
||||
// Immediately after the command, the motor should be stopped
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state());
|
||||
|
||||
// Wait for the inertia period (after which the reverse command will be dispatched)
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state()); // Should now be in reverse state
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from reverse to forward with inertia and state checks
|
||||
// Scenario: RELAY_CHN_STATE_REVERSE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_FORWARD
|
||||
TEST_CASE("Reverse to Forward transition with opposite inertia", "[relay_chn][core][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// 1. Start in reverse direction
|
||||
relay_chn_run_reverse(); // relay_chn_run_reverse returns void
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||
|
||||
// 2. Issue forward command
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state());
|
||||
|
||||
// Wait for inertia
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test issuing the same run command while already running (no inertia expected)
|
||||
// Scenario: RELAY_CHN_STATE_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||
TEST_CASE("Running in same direction does not incur inertia", "[relay_chn][core][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// 1. Start in forward direction
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
|
||||
// 2. Issue the same forward command again
|
||||
relay_chn_run_forward();
|
||||
// As per the code, is_direction_opposite_to_current_motion should return false, so no inertia.
|
||||
// Just a short delay to check state remains the same.
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from IDLE state to running (no inertia expected)
|
||||
// Scenario: RELAY_CHN_STATE_IDLE -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||
TEST_CASE("IDLE to Running transition without inertia", "[relay_chn][core][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// setUp() should have already brought the channel to IDLE state
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||
|
||||
// Start in forward direction
|
||||
relay_chn_run_forward();
|
||||
// No inertia is expected when starting from IDLE state.
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// ### Direction Flipping Tests
|
||||
|
||||
TEST_CASE("Single channel direction can be flipped", "[relay_chn][core][direction]")
|
||||
{
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// 1. Initial direction should be default
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction());
|
||||
|
||||
// 2. Flip the direction
|
||||
relay_chn_flip_direction();
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); // Wait for flip inertia
|
||||
|
||||
// 3. Verify direction is flipped
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction());
|
||||
|
||||
// 4. Flip back
|
||||
relay_chn_flip_direction();
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms)); // Wait for flip inertia
|
||||
|
||||
// 5. Verify direction is back to default
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction());
|
||||
}
|
||||
|
||||
TEST_CASE("Flipping a running channel stops it and flips direction", "[relay_chn][core][direction]")
|
||||
{
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// 1. Start channel running and verify state
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
|
||||
// 2. Flip the direction while running
|
||||
relay_chn_flip_direction();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Give time for events to process
|
||||
|
||||
// 3. The channel should stop as part of the flip process
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||
|
||||
// 4. Wait for the flip inertia to pass, after which it should be IDLE and FLIPPED
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction());
|
||||
}
|
||||
@@ -52,7 +52,7 @@ TEST_CASE("Listener is called on state change", "[relay_chn][listener]") {
|
||||
// 3. Verify the listener was called with correct parameters
|
||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
||||
TEST_ASSERT_EQUAL(ch, listener1_info.chn_id);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, listener1_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
||||
|
||||
// 4. Unregister to clean up
|
||||
@@ -96,12 +96,12 @@ TEST_CASE("Multiple listeners are called on state change", "[relay_chn][listener
|
||||
|
||||
// 3. Verify listener 1 was called correctly
|
||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, listener1_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
||||
|
||||
// 4. Verify listener 2 was also called correctly
|
||||
TEST_ASSERT_EQUAL(1, listener2_info.call_count);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, listener2_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener2_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener2_info.new_state);
|
||||
|
||||
// 5. Clean up
|
||||
130
test_apps/main/test_relay_chn_listener_single.c
Normal file
130
test_apps/main/test_relay_chn_listener_single.c
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "test_common.h"
|
||||
|
||||
|
||||
// --- Listener Test Globals ---
|
||||
typedef struct {
|
||||
relay_chn_state_t old_state;
|
||||
relay_chn_state_t new_state;
|
||||
int call_count;
|
||||
} listener_callback_info_t;
|
||||
|
||||
static listener_callback_info_t listener1_info;
|
||||
static listener_callback_info_t listener2_info;
|
||||
|
||||
// --- Listener Test Helper Functions ---
|
||||
|
||||
// Clear the memory from possible garbage values
|
||||
static void reset_listener_info(listener_callback_info_t* info) {
|
||||
memset(info, 0, sizeof(listener_callback_info_t));
|
||||
}
|
||||
|
||||
static void test_listener_1(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
||||
/* Just ignore the channel id */
|
||||
listener1_info.old_state = old_state;
|
||||
listener1_info.new_state = new_state;
|
||||
listener1_info.call_count++;
|
||||
}
|
||||
|
||||
static void test_listener_2(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
|
||||
/* Just ignore the channel id */
|
||||
listener2_info.old_state = old_state;
|
||||
listener2_info.new_state = new_state;
|
||||
listener2_info.call_count++;
|
||||
}
|
||||
|
||||
// ### Listener Functionality Tests
|
||||
|
||||
TEST_CASE("Listener is called on state change", "[relay_chn][listener]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
reset_listener_info(&listener1_info);
|
||||
|
||||
// 1. Register the listener
|
||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||
|
||||
// 2. Trigger a state change
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Allow event to be processed
|
||||
|
||||
// 3. Verify the listener was called with correct parameters
|
||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
||||
|
||||
// 4. Unregister to clean up
|
||||
relay_chn_unregister_listener(test_listener_1);
|
||||
}
|
||||
|
||||
TEST_CASE("Unregistered listener is not called", "[relay_chn][listener]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
reset_listener_info(&listener1_info);
|
||||
|
||||
// 1. Register and then immediately unregister the listener
|
||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||
relay_chn_unregister_listener(test_listener_1);
|
||||
|
||||
// 2. Trigger a state change
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
|
||||
// 3. Verify the listener was NOT called
|
||||
TEST_ASSERT_EQUAL(0, listener1_info.call_count);
|
||||
}
|
||||
|
||||
TEST_CASE("Multiple listeners are called on state change", "[relay_chn][listener]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
reset_listener_info(&listener1_info);
|
||||
reset_listener_info(&listener2_info);
|
||||
|
||||
// 1. Register two different listeners
|
||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_2));
|
||||
|
||||
// 2. Trigger a state change
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
|
||||
// 3. Verify listener 1 was called correctly
|
||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener1_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener1_info.new_state);
|
||||
|
||||
// 4. Verify listener 2 was also called correctly
|
||||
TEST_ASSERT_EQUAL(1, listener2_info.call_count);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, listener2_info.old_state);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, listener2_info.new_state);
|
||||
|
||||
// 5. Clean up
|
||||
relay_chn_unregister_listener(test_listener_1);
|
||||
relay_chn_unregister_listener(test_listener_2);
|
||||
}
|
||||
|
||||
TEST_CASE("Listener registration handles invalid arguments and duplicates", "[relay_chn][listener]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
reset_listener_info(&listener1_info);
|
||||
|
||||
// 1. Registering a NULL listener should fail
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, relay_chn_register_listener(NULL));
|
||||
|
||||
// 2. Unregistering a NULL listener should not crash
|
||||
relay_chn_unregister_listener(NULL);
|
||||
|
||||
// 3. Registering the same listener twice should be handled gracefully
|
||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1));
|
||||
TEST_ESP_OK(relay_chn_register_listener(test_listener_1)); // Second call should be a no-op
|
||||
|
||||
// 4. Trigger a state change and verify the listener is only called ONCE
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(1, listener1_info.call_count);
|
||||
|
||||
// 5. Clean up
|
||||
relay_chn_unregister_listener(test_listener_1);
|
||||
}
|
||||
@@ -23,7 +23,7 @@ void prepare_channel_for_tilt(uint8_t chn_id, int initial_cmd) {
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms)); // Allow command to process
|
||||
relay_chn_stop(chn_id); // Stop it to set last_run_cmd but return to FREE for next test
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(chn_id));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(chn_id));
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from running forward to tilt forward
|
||||
@@ -79,7 +79,7 @@ TEST_CASE("Run Reverse to Tilt Reverse transition with inertia", "[relay_chn][ti
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from FREE state to tilt forward (now with preparation)
|
||||
// Scenario: RELAY_CHN_STATE_FREE -> (prepare) -> RELAY_CHN_STATE_FREE -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
||||
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
||||
TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn][tilt][inertia]") {
|
||||
uint8_t ch = 0;
|
||||
|
||||
@@ -88,7 +88,7 @@ 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(ch, RELAY_CHN_CMD_FORWARD);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(ch)); // Ensure we are back to FREE
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch)); // Ensure we are back to FREE
|
||||
|
||||
// Issue tilt forward command
|
||||
relay_chn_tilt_forward(ch);
|
||||
@@ -98,7 +98,7 @@ TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from FREE state to tilt reverse (now with preparation)
|
||||
// Scenario: RELAY_CHN_STATE_FREE -> (prepare) -> RELAY_CHN_STATE_FREE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
||||
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
||||
TEST_CASE("FREE to Tilt Reverse transition with inertia (prepared)", "[relay_chn][tilt][inertia]") {
|
||||
uint8_t ch = 0;
|
||||
|
||||
@@ -107,7 +107,7 @@ 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(ch, RELAY_CHN_CMD_REVERSE);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(ch)); // Ensure we are back to FREE
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch)); // Ensure we are back to FREE
|
||||
|
||||
// Issue tilt reverse command
|
||||
relay_chn_tilt_reverse(ch);
|
||||
@@ -179,7 +179,7 @@ TEST_CASE("Tilt Forward to Run Reverse transition without inertia", "[relay_chn]
|
||||
}
|
||||
|
||||
// TEST_CASE: Test stopping from a tilt state (no inertia for stop command itself)
|
||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_stop) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_FREE
|
||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_stop) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_IDLE
|
||||
TEST_CASE("Tilt to Stop transition without immediate inertia for stop", "[relay_chn][tilt][inertia]") {
|
||||
uint8_t ch = 0;
|
||||
|
||||
@@ -196,7 +196,7 @@ TEST_CASE("Tilt to Stop transition without immediate inertia for stop", "[relay_
|
||||
relay_chn_stop(ch);
|
||||
// Stop command should apply immediately, setting state to FREE since last state was tilt.
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(ch));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(ch));
|
||||
}
|
||||
|
||||
// ### Tilt Broadcast Command (RELAY_CHN_ID_ALL) Tests
|
||||
@@ -259,7 +259,7 @@ TEST_CASE("tilt_stop with ID_ALL stops all tilting channels", "[relay_chn][tilt]
|
||||
|
||||
// 3. Verify all channels are free
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FREE, relay_chn_get_state(i));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,28 +306,28 @@ TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][au
|
||||
}
|
||||
|
||||
// Test sensitivity set/get
|
||||
TEST_CASE("relay_chn_tilt_sensitivity_set and get", "[relay_chn][tilt][sensitivity]") {
|
||||
TEST_CASE("relay_chn_tilt_set_sensitivity and get", "[relay_chn][tilt][sensitivity]") {
|
||||
uint8_t ch = 0;
|
||||
uint8_t val = 0;
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
relay_chn_tilt_sensitivity_set(ch, 0);
|
||||
TEST_ESP_OK(relay_chn_tilt_sensitivity_get(ch, &val, 1));
|
||||
relay_chn_tilt_set_sensitivity(ch, 0);
|
||||
TEST_ESP_OK(relay_chn_tilt_get_sensitivity(ch, &val, 1));
|
||||
TEST_ASSERT_EQUAL_UINT8(0, val);
|
||||
|
||||
relay_chn_tilt_sensitivity_set(ch, 50);
|
||||
TEST_ESP_OK(relay_chn_tilt_sensitivity_get(ch, &val, 1));
|
||||
relay_chn_tilt_set_sensitivity(ch, 50);
|
||||
TEST_ESP_OK(relay_chn_tilt_get_sensitivity(ch, &val, 1));
|
||||
TEST_ASSERT_EQUAL_UINT8(50, val);
|
||||
|
||||
relay_chn_tilt_sensitivity_set(ch, 100);
|
||||
TEST_ESP_OK(relay_chn_tilt_sensitivity_get(ch, &val, 1));
|
||||
relay_chn_tilt_set_sensitivity(ch, 100);
|
||||
TEST_ESP_OK(relay_chn_tilt_get_sensitivity(ch, &val, 1));
|
||||
TEST_ASSERT_EQUAL_UINT8(100, val);
|
||||
|
||||
// Set all channels
|
||||
relay_chn_tilt_sensitivity_set(RELAY_CHN_ID_ALL, 42);
|
||||
relay_chn_tilt_set_sensitivity(RELAY_CHN_ID_ALL, 42);
|
||||
uint8_t vals[CONFIG_RELAY_CHN_COUNT] = {0};
|
||||
TEST_ESP_OK(relay_chn_tilt_sensitivity_get(RELAY_CHN_ID_ALL, vals, relay_chn_count));
|
||||
TEST_ESP_OK(relay_chn_tilt_get_sensitivity(RELAY_CHN_ID_ALL, vals, relay_chn_count));
|
||||
for (int i = 0; i < relay_chn_count; ++i) {
|
||||
TEST_ASSERT_EQUAL_UINT8(42, vals[i]);
|
||||
}
|
||||
275
test_apps/main/test_relay_chn_tilt_single.c
Normal file
275
test_apps/main/test_relay_chn_tilt_single.c
Normal file
@@ -0,0 +1,275 @@
|
||||
#include "test_common.h"
|
||||
|
||||
|
||||
// ### Tilt Functionality Tests (Conditional)
|
||||
|
||||
// This section will only be compiled if **`CONFIG_RELAY_CHN_ENABLE_TILTING`** is defined as **`1`** in `sdkconfig`.
|
||||
|
||||
#ifndef CONFIG_RELAY_CHN_ENABLE_TILTING
|
||||
#error "This test requires CONFIG_RELAY_CHN_ENABLE_TILTING"
|
||||
#endif
|
||||
|
||||
#define RELAY_CHN_CMD_FORWARD 1
|
||||
#define RELAY_CHN_CMD_REVERSE 2
|
||||
|
||||
// Helper function to prepare channel for tilt tests
|
||||
void prepare_channel_for_tilt(int initial_cmd) {
|
||||
// Ensure the channel has had a 'last_run_cmd'
|
||||
if (initial_cmd == RELAY_CHN_CMD_FORWARD) {
|
||||
relay_chn_run_forward();
|
||||
} 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(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// 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]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare channel by running forward first to set last_run_cmd
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
|
||||
// 1. Start in forward direction
|
||||
relay_chn_run_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
|
||||
// 2. Issue tilt forward command
|
||||
relay_chn_tilt_forward();
|
||||
// After tilt command, it should immediately stop and then trigger inertia.
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||
|
||||
// Wait for the inertia period (after which the tilt command will be dispatched)
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// 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]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare channel by running reverse first to set last_run_cmd
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
|
||||
// 1. Start in reverse direction
|
||||
relay_chn_run_reverse();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||
|
||||
// 2. Issue tilt reverse command
|
||||
relay_chn_tilt_reverse();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state());
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from FREE state to tilt forward (now with preparation)
|
||||
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_forward) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_FORWARD
|
||||
TEST_CASE("FREE to Tilt Forward transition with inertia (prepared)", "[relay_chn][tilt][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare channel by running forward first to set last_run_cmd
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); // Ensure we are back to FREE
|
||||
|
||||
// Issue tilt forward command
|
||||
relay_chn_tilt_forward();
|
||||
// From FREE state, tilt command should still incur the inertia due to the internal timer logic
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from FREE state to tilt reverse (now with preparation)
|
||||
// Scenario: RELAY_CHN_STATE_IDLE -> (prepare) -> RELAY_CHN_STATE_IDLE -> (relay_chn_tilt_reverse) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_TILT_REVERSE
|
||||
TEST_CASE("FREE to Tilt Reverse transition with inertia (prepared)", "[relay_chn][tilt][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare channel by running reverse first to set last_run_cmd
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state()); // Ensure we are back to FREE
|
||||
|
||||
// Issue tilt reverse command
|
||||
relay_chn_tilt_reverse();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from tilt forward to run forward (inertia expected for run)
|
||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_forward) -> RELAY_CHN_STATE_FORWARD
|
||||
TEST_CASE("Tilt Forward to Run Forward transition with inertia", "[relay_chn][tilt][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_forward(); // Go to tilt state
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
|
||||
// 2. Issue run forward command
|
||||
relay_chn_run_forward();
|
||||
// From Tilt to Run in the same logical name but in the opposite direction, inertia is expected.
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD_PENDING, relay_chn_get_state());
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from tilt reverse to run reverse (no inertia expected for run)
|
||||
// Scenario: RELAY_CHN_STATE_TILT_REVERSE -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
||||
TEST_CASE("Tilt Reverse to Run Reverse transition with inertia", "[relay_chn][tilt][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare channel by running reverse first to set last_run_cmd, then tilt
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
relay_chn_tilt_reverse(); // Go to tilt state
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||
|
||||
// 2. Issue run reverse command
|
||||
relay_chn_run_reverse();
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE_PENDING, relay_chn_get_state());
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test transition from tilt forward to run reverse (without inertia)
|
||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_run_reverse) -> RELAY_CHN_STATE_REVERSE
|
||||
TEST_CASE("Tilt Forward to Run Reverse transition without inertia", "[relay_chn][tilt][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_forward(); // Go to tilt state
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
|
||||
// 2. Issue run reverse command (opposite direction)
|
||||
relay_chn_run_reverse();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// TEST_CASE: Test stopping from a tilt state (no inertia for stop command itself)
|
||||
// Scenario: RELAY_CHN_STATE_TILT_FORWARD -> (relay_chn_stop) -> RELAY_CHN_STATE_STOPPED -> (inertia) -> RELAY_CHN_STATE_IDLE
|
||||
TEST_CASE("Tilt to Stop transition without immediate inertia for stop", "[relay_chn][tilt][inertia]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare channel by running forward first to set last_run_cmd, then tilt
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_forward(); // Go to tilt state
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
|
||||
// 2. Issue stop command
|
||||
relay_chn_stop();
|
||||
// Stop command should apply immediately, setting state to FREE since last state was tilt.
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_IDLE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// Test relay_chn_tilt_auto() chooses correct tilt direction
|
||||
TEST_CASE("relay_chn_tilt_auto chooses correct direction", "[relay_chn][tilt][auto]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
// Prepare FORWARD
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_auto();
|
||||
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));
|
||||
|
||||
// Prepare REVERSE
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_REVERSE);
|
||||
relay_chn_tilt_auto();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_REVERSE, relay_chn_get_state());
|
||||
}
|
||||
|
||||
// Test sensitivity set/get
|
||||
TEST_CASE("relay_chn_tilt_set_sensitivity and get", "[relay_chn][tilt][sensitivity]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
relay_chn_tilt_set_sensitivity(0);
|
||||
TEST_ASSERT_EQUAL_UINT8(0, relay_chn_tilt_get_sensitivity());
|
||||
|
||||
relay_chn_tilt_set_sensitivity(50);
|
||||
TEST_ASSERT_EQUAL_UINT8(50, relay_chn_tilt_get_sensitivity());
|
||||
|
||||
relay_chn_tilt_set_sensitivity(100);
|
||||
TEST_ASSERT_EQUAL_UINT8(100, relay_chn_tilt_get_sensitivity());
|
||||
|
||||
relay_chn_tilt_set_sensitivity(42);
|
||||
TEST_ASSERT_EQUAL_UINT8(42, relay_chn_tilt_get_sensitivity());
|
||||
}
|
||||
|
||||
// Test tilt counter logic: forward x3, reverse x3, extra reverse fails
|
||||
TEST_CASE("tilt counter logic: forward and reverse consumption", "[relay_chn][tilt][counter]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// 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));
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Test run command during TILT state
|
||||
TEST_CASE("run command during TILT state transitions correctly", "[relay_chn][tilt][run-during-tilt]") {
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
g_is_component_initialized = true;
|
||||
|
||||
prepare_channel_for_tilt(RELAY_CHN_CMD_FORWARD);
|
||||
relay_chn_tilt_forward();
|
||||
vTaskDelay(pdMS_TO_TICKS(opposite_inertia_ms + test_delay_margin_ms));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_TILT_FORWARD, relay_chn_get_state());
|
||||
|
||||
// Issue run reverse while in TILT_FORWARD
|
||||
relay_chn_run_reverse();
|
||||
vTaskDelay(pdMS_TO_TICKS(test_delay_margin_ms));
|
||||
// Should transition to REVERSE or REVERSE_PENDING depending on inertia logic
|
||||
relay_chn_state_t state = relay_chn_get_state();
|
||||
TEST_ASSERT(state == RELAY_CHN_STATE_REVERSE || state == RELAY_CHN_STATE_REVERSE_PENDING);
|
||||
}
|
||||
5
test_apps/partition_table/partitionTable.csv
Normal file
5
test_apps/partition_table/partitionTable.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs,data,nvs,0xa000,24K,
|
||||
phy_init,data,phy,0x10000,4K,
|
||||
factory,app,factory,0x20000,1M,
|
||||
|
@@ -1261,7 +1261,7 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
# Relay Channel Driver Configuration
|
||||
#
|
||||
CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200
|
||||
CONFIG_RELAY_CHN_COUNT=2
|
||||
CONFIG_RELAY_CHN_COUNT=1
|
||||
CONFIG_RELAY_CHN_ENABLE_TILTING=y
|
||||
# end of Relay Channel Driver Configuration
|
||||
# end of Component config
|
||||
|
||||
8
test_apps/sdkconfig.defaults.single
Normal file
8
test_apps/sdkconfig.defaults.single
Normal file
@@ -0,0 +1,8 @@
|
||||
# Disable task WDT for tests
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
|
||||
# Relay Channel Driver Default Configuration for Testing
|
||||
# Keep this as short as possible for tests
|
||||
CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS=200
|
||||
CONFIG_RELAY_CHN_COUNT=1
|
||||
CONFIG_RELAY_CHN_ENABLE_TILTING=y
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Automatically generated file. DO NOT EDIT.
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.4.2 Project Configuration
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Configuration
|
||||
#
|
||||
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
|
||||
CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"
|
||||
@@ -98,7 +98,6 @@ CONFIG_SOC_I2C_FIFO_LEN=32
|
||||
CONFIG_SOC_I2C_CMD_REG_NUM=16
|
||||
CONFIG_SOC_I2C_SUPPORT_SLAVE=y
|
||||
CONFIG_SOC_I2C_SUPPORT_APB=y
|
||||
CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y
|
||||
CONFIG_SOC_I2C_STOP_INDEPENDENT=y
|
||||
CONFIG_SOC_I2S_NUM=2
|
||||
CONFIG_SOC_I2S_HW_VERSION_1=y
|
||||
@@ -176,8 +175,6 @@ CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2
|
||||
CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64
|
||||
CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4
|
||||
CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y
|
||||
CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32
|
||||
CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16
|
||||
CONFIG_SOC_TOUCH_SENSOR_VERSION=1
|
||||
CONFIG_SOC_TOUCH_SENSOR_NUM=10
|
||||
CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1
|
||||
@@ -247,7 +244,7 @@ CONFIG_IDF_TOOLCHAIN_GCC=y
|
||||
CONFIG_IDF_TARGET_ARCH_XTENSA=y
|
||||
CONFIG_IDF_TARGET_ARCH="xtensa"
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_INIT_VERSION="5.4.2"
|
||||
CONFIG_IDF_INIT_VERSION="$IDF_INIT_VERSION"
|
||||
CONFIG_IDF_TARGET_ESP32=y
|
||||
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
|
||||
|
||||
@@ -288,10 +285,10 @@ CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG=y
|
||||
# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL=3
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL=4
|
||||
|
||||
#
|
||||
# Format
|
||||
@@ -402,7 +399,7 @@ CONFIG_PARTITION_TABLE_SINGLE_APP=y
|
||||
# CONFIG_PARTITION_TABLE_CUSTOM is not set
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
||||
CONFIG_PARTITION_TABLE_MD5=y
|
||||
# end of Partition Table
|
||||
|
||||
@@ -465,7 +462,6 @@ CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y
|
||||
#
|
||||
CONFIG_ADC_DISABLE_DAC=y
|
||||
# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set
|
||||
# CONFIG_ADC_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
|
||||
#
|
||||
# Legacy ADC Calibration Configuration
|
||||
@@ -481,55 +477,42 @@ CONFIG_ADC_CAL_LUT_ENABLE=y
|
||||
# Legacy DAC Driver Configurations
|
||||
#
|
||||
# CONFIG_DAC_SUPPRESS_DEPRECATE_WARN is not set
|
||||
# CONFIG_DAC_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
# end of Legacy DAC Driver Configurations
|
||||
|
||||
#
|
||||
# Legacy MCPWM Driver Configurations
|
||||
#
|
||||
# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set
|
||||
# CONFIG_MCPWM_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
# end of Legacy MCPWM Driver Configurations
|
||||
|
||||
#
|
||||
# Legacy Timer Group Driver Configurations
|
||||
#
|
||||
# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set
|
||||
# CONFIG_GPTIMER_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
# end of Legacy Timer Group Driver Configurations
|
||||
|
||||
#
|
||||
# Legacy RMT Driver Configurations
|
||||
#
|
||||
# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set
|
||||
# CONFIG_RMT_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
# end of Legacy RMT Driver Configurations
|
||||
|
||||
#
|
||||
# Legacy I2S Driver Configurations
|
||||
#
|
||||
# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set
|
||||
# CONFIG_I2S_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
# end of Legacy I2S Driver Configurations
|
||||
|
||||
#
|
||||
# Legacy I2C Driver Configurations
|
||||
#
|
||||
# CONFIG_I2C_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
# end of Legacy I2C Driver Configurations
|
||||
|
||||
#
|
||||
# Legacy PCNT Driver Configurations
|
||||
#
|
||||
# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set
|
||||
# CONFIG_PCNT_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
# end of Legacy PCNT Driver Configurations
|
||||
|
||||
#
|
||||
# Legacy SDM Driver Configurations
|
||||
#
|
||||
# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set
|
||||
# CONFIG_SDM_SKIP_LEGACY_CONFLICT_CHECK is not set
|
||||
# end of Legacy SDM Driver Configurations
|
||||
# end of Driver Configurations
|
||||
|
||||
@@ -572,7 +555,6 @@ CONFIG_DAC_DMA_AUTO_16BIT_ALIGN=y
|
||||
CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y
|
||||
# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set
|
||||
# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set
|
||||
CONFIG_GPTIMER_OBJ_CACHE_SAFE=y
|
||||
# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set
|
||||
# end of ESP-Driver:GPTimer Configurations
|
||||
|
||||
@@ -724,7 +706,7 @@ CONFIG_RTC_CLK_CAL_CYCLES=1024
|
||||
#
|
||||
# Peripheral Control
|
||||
#
|
||||
# CONFIG_PERIPH_CTRL_FUNC_IN_IRAM is not set
|
||||
CONFIG_PERIPH_CTRL_FUNC_IN_IRAM=y
|
||||
# end of Peripheral Control
|
||||
|
||||
#
|
||||
@@ -954,6 +936,7 @@ CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
|
||||
CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2
|
||||
CONFIG_HAL_SPI_MASTER_FUNC_IN_IRAM=y
|
||||
CONFIG_HAL_SPI_SLAVE_FUNC_IN_IRAM=y
|
||||
# CONFIG_HAL_ECDSA_GEN_SIG_CM is not set
|
||||
# end of Hardware Abstraction Layer (HAL) and Low Level (LL)
|
||||
|
||||
#
|
||||
@@ -1062,7 +1045,6 @@ CONFIG_MBEDTLS_HAVE_TIME=y
|
||||
# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set
|
||||
# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
|
||||
CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
|
||||
CONFIG_MBEDTLS_SHA1_C=y
|
||||
CONFIG_MBEDTLS_SHA512_C=y
|
||||
# CONFIG_MBEDTLS_SHA3_C is not set
|
||||
CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
|
||||
@@ -1143,7 +1125,6 @@ CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
|
||||
# CONFIG_MBEDTLS_HKDF_C is not set
|
||||
# CONFIG_MBEDTLS_THREADING_C is not set
|
||||
CONFIG_MBEDTLS_ERROR_STRINGS=y
|
||||
# CONFIG_MBEDTLS_ALLOW_WEAK_CERTIFICATE_VERIFICATION is not set
|
||||
# end of mbedTLS
|
||||
|
||||
#
|
||||
@@ -1203,7 +1184,6 @@ CONFIG_SPI_FLASH_BROWNOUT_RESET=y
|
||||
#
|
||||
CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50
|
||||
# CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND is not set
|
||||
# CONFIG_SPI_FLASH_FORCE_ENABLE_C6_H2_SUSPEND is not set
|
||||
# end of Optional and Experimental Features (READ DOCS FIRST)
|
||||
# end of Main Flash configuration
|
||||
|
||||
@@ -1277,10 +1257,10 @@ CONFIG_RELAY_CHN_ENABLE_TILTING=y
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG=y
|
||||
# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL=3
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL=4
|
||||
# CONFIG_APP_ROLLBACK_ENABLE is not set
|
||||
# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
|
||||
# CONFIG_FLASHMODE_QIO is not set
|
||||
|
||||
Reference in New Issue
Block a user