Compare commits
15 Commits
437c013a2e
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5481f79e7 | ||
|
|
7d3f08b56b | ||
| a694938224 | |||
| dcb5453522 | |||
| feb1f4ac81 | |||
| 069363205a | |||
| d4fdff949a | |||
| dc2dcfec7d | |||
| 8517993358 | |||
| e21bfb5b26 | |||
| 27c669066a | |||
| d64370c925 | |||
| b47244b5d1 | |||
| 6158dce3b4 | |||
| d3fb1e6620 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -100,3 +100,8 @@ CTestTestfile.cmake
|
||||
_deps
|
||||
CMakeUserPresets.json
|
||||
|
||||
# Build directory
|
||||
build
|
||||
|
||||
# unity-app directory
|
||||
unity-app
|
||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"relay_chn.h": "c"
|
||||
}
|
||||
}
|
||||
4
CMakeLists.txt
Normal file
4
CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "src/relay_chn.c"
|
||||
INCLUDE_DIRS include
|
||||
REQUIRES driver
|
||||
PRIV_REQUIRES esp_timer esp_event)
|
||||
29
Kconfig
Normal file
29
Kconfig
Normal file
@@ -0,0 +1,29 @@
|
||||
menu "Relay Channel Driver Configuration"
|
||||
|
||||
config RELAY_CHN_OPPOSITE_INERTIA_MS
|
||||
int "Inertia time before it runs opposite direction (ms)"
|
||||
range 200 1500
|
||||
default 800
|
||||
help
|
||||
Time to wait after changing the direction of the output before
|
||||
starting the output. This is useful for the motors or some other
|
||||
mechanical actuators to allow them to stop and settle before
|
||||
changing the direction.
|
||||
|
||||
config RELAY_CHN_COUNT
|
||||
int "Number of relay channels"
|
||||
range 1 8
|
||||
default 1
|
||||
help
|
||||
Number of relay channels between 1 and 8.
|
||||
|
||||
config RELAY_CHN_ENABLE_TILTING
|
||||
bool "Enable tilting on relay channels"
|
||||
default n
|
||||
help
|
||||
This option controls enabling tilting on channels. Tilting makes
|
||||
a channel move with a specific pattern moving with small steps
|
||||
at a time. Tilting is specifically designed for controlling some
|
||||
types of curtains that need to be adjusted to let enter specific
|
||||
amount of day light.
|
||||
endmenu
|
||||
83
README.md
83
README.md
@@ -1,3 +1,82 @@
|
||||
# relay_chn
|
||||
# relay_chn - Relay Channel Controller
|
||||
|
||||
A custom ESP-IDF component for controlling a relay channel
|
||||
An ESP-IDF component for controlling relay channels, specifically designed for driving bipolar motors through relay pairs.
|
||||
|
||||
## Features
|
||||
|
||||
- Controls multiple relay channel pairs (up to 8 channels)
|
||||
- Built-in direction change inertia protection
|
||||
- Automatic command sequencing and timing
|
||||
- Event-driven architecture for reliable operation
|
||||
- Forward/Reverse direction control
|
||||
- Direction flipping capability
|
||||
- State monitoring and reporting
|
||||
|
||||
## Description
|
||||
|
||||
Each relay channel consists of 2 output relays controlled by 2 GPIO pins. The component provides APIs to control these relay pairs while ensuring safe operation, particularly for driving bipolar motors. It prevents short-circuits by automatically managing direction changes with configurable inertia timing.
|
||||
|
||||
## Configuration
|
||||
|
||||
Configure the component through menuconfig under "Relay Channel Driver Configuration":
|
||||
|
||||
- `CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS`: Time to wait before changing direction (200-1500ms, default: 800ms)
|
||||
- `CONFIG_RELAY_CHN_COUNT`: Number of relay channels (1-8, default: 1)
|
||||
|
||||
## Installation
|
||||
|
||||
1. Copy the component to your project's components directory
|
||||
2. Add dependency to your project's `idf_component.yml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
relay_chn:
|
||||
version: "^0.1.0"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### 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_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||
|
||||
// Create and initialize relay channels
|
||||
esp_err_t ret = relay_chn_create(gpio_map, gpio_count);
|
||||
if (ret != ESP_OK) {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Control relay channels
|
||||
|
||||
```c
|
||||
// Run channel 0 forward
|
||||
relay_chn_run_forward(0);
|
||||
|
||||
// Run channel 0 reverse
|
||||
relay_chn_run_reverse(0);
|
||||
|
||||
// Stop channel 0
|
||||
relay_chn_stop(0);
|
||||
|
||||
// Flip direction of channel 0
|
||||
relay_chn_flip_direction(0);
|
||||
```
|
||||
|
||||
### 3. Monitor channel state
|
||||
|
||||
```c
|
||||
// Get channel state
|
||||
relay_chn_state_t state = relay_chn_get_state(0);
|
||||
char *state_str = relay_chn_get_state_str(0);
|
||||
|
||||
// Get channel direction
|
||||
relay_chn_direction_t direction = relay_chn_get_direction(0);
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](LICENSE) - Copyright (c) 2025 kozmotronik.
|
||||
|
||||
7
idf_component.yml
Normal file
7
idf_component.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
name: relay_chn
|
||||
version: 0.1.0
|
||||
description: Custom component for relay channel control
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=4.0"
|
||||
# TODO: Repo ve belgelendirme bağlantılarını ekle.
|
||||
228
include/relay_chn.h
Normal file
228
include/relay_chn.h
Normal file
@@ -0,0 +1,228 @@
|
||||
#ifndef RELAY_CHN_H
|
||||
#define RELAY_CHN_H
|
||||
/**
|
||||
* @file relay_chn.h
|
||||
*
|
||||
* @author
|
||||
* Ismail Sahillioglu <ismailsahillioglu@gmail.com>
|
||||
*
|
||||
* @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.
|
||||
* The module also automatically manages the direction change inertia to prevent short-circuiting the motor.
|
||||
* The STOP command overrides any other command and clears the pending command if any.
|
||||
*
|
||||
* The module internally uses a custom esp event loop to handle relay commands serially to ensure
|
||||
* reliability and prevent conflict operations. Also, the esp timer is used to manage the direction change inertia.
|
||||
*/
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include <stdint.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_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.
|
||||
*
|
||||
* This function initializes the relay channels based on the provided GPIO map.
|
||||
*
|
||||
* @param gpio_map Pointer to an array of GPIO numbers that correspond to the relay channels.
|
||||
* @param gpio_count The number of GPIOs in the gpio_map array.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - 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);
|
||||
|
||||
/**
|
||||
* @brief Register a channel state change listener.
|
||||
*
|
||||
* @param listener A function that implements relay_chn_state_listener_t interface.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NO_MEM: No enough memory
|
||||
* - ESP_FAIL: General failure
|
||||
*/
|
||||
esp_err_t relay_chn_register_listener(relay_chn_state_listener_t listener);
|
||||
|
||||
/**
|
||||
* @brief Unregister a channel state change listener.
|
||||
*
|
||||
* @param listener A function that implements relay_chn_state_listener_t interface.
|
||||
*/
|
||||
void relay_chn_unregister_listener(relay_chn_state_listener_t listener);
|
||||
|
||||
/**
|
||||
* @brief Get the state of the specified relay channel.
|
||||
*
|
||||
* This function retrieves the current state of the relay channel identified by the given channel ID.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel whose state is to be retrieved.
|
||||
* @return The current state of the specified relay channel.
|
||||
*/
|
||||
relay_chn_state_t relay_chn_get_state(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Get the state string of the specified relay channel.
|
||||
*
|
||||
* This function returns a string representation of the state of the relay
|
||||
* channel identified by the given channel ID.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel whose state is to be retrieved.
|
||||
* The valid range of channel IDs depends on the specific hardware
|
||||
* and implementation.
|
||||
*
|
||||
* @return A pointer to a string representing the state of the specified relay
|
||||
* channel. The returned string is managed internally and should not be
|
||||
* modified or freed by the caller.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This function activates the specified relay channel to run in the forward direction.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to be activated.
|
||||
*/
|
||||
void relay_chn_run_forward(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Runs the relay channel in reverse.
|
||||
*
|
||||
* This function activates the specified relay channel to run in reverse.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to be reversed.
|
||||
*/
|
||||
void relay_chn_run_reverse(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Stops the relay channel specified by the channel ID.
|
||||
*
|
||||
* This function stops the operation of the relay channel identified by the
|
||||
* provided channel ID. It is typically used to turn off or disable the relay
|
||||
* channel.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to stop.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
void relay_chn_flip_direction(uint8_t chn_id);
|
||||
|
||||
/**
|
||||
* @brief Get the direction of the specified relay channel.
|
||||
*
|
||||
* This function retrieves the direction configuration of a relay channel
|
||||
* identified by the given channel ID.
|
||||
*
|
||||
* @param chn_id The ID of the relay channel to query.
|
||||
* @return The direction of the specified relay channel as a value of type
|
||||
* relay_chn_direction_t.
|
||||
*/
|
||||
relay_chn_direction_t relay_chn_get_direction(uint8_t chn_id);
|
||||
|
||||
|
||||
#if CONFIG_RELAY_CHN_ENABLE_TILTING == 1
|
||||
|
||||
void relay_chn_tilt_auto(uint8_t chn_id);
|
||||
|
||||
void relay_chn_tilt_forward(uint8_t chn_id);
|
||||
|
||||
void relay_chn_tilt_reverse(uint8_t chn_id);
|
||||
|
||||
void relay_chn_tilt_stop(uint8_t chn_id);
|
||||
|
||||
void relay_chn_tilt_sensitivity_set(uint8_t chn_id, uint8_t sensitivity);
|
||||
|
||||
uint8_t relay_chn_tilt_sensitivity_get(uint8_t chn_id);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
|
||||
#endif // RELAY_CHN_H
|
||||
1101
src/relay_chn.c
Normal file
1101
src/relay_chn.c
Normal file
File diff suppressed because it is too large
Load Diff
8
test/CMakeLists.txt
Normal file
8
test/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
|
||||
"../../relay_chn")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(relay_chn_test)
|
||||
3
test/main/CMakeLists.txt
Normal file
3
test/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity test_utils relay_chn)
|
||||
95
test/main/test_relay_chn.c
Normal file
95
test/main/test_relay_chn.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "driver/gpio.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "relay_chn.h"
|
||||
|
||||
|
||||
const gpio_num_t gpio_map[] = {GPIO_NUM_4, GPIO_NUM_5, GPIO_NUM_18, GPIO_NUM_19};
|
||||
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||
const uint8_t relay_chn_count = gpio_count / 2;
|
||||
|
||||
TEST_CASE("relay chn inits correctly", "[relay_chn]")
|
||||
{
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
}
|
||||
|
||||
TEST_CASE("Relay channels run forward and update state", "[relay_chn][forward]")
|
||||
{
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
// Test forward run on all channels
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||
relay_chn_run_forward(i); // Run the channel forward
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
||||
relay_chn_stop(i); // Stop the channel
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||
|
||||
relay_chn_flip_direction(i); // Flip the direction
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(i));
|
||||
relay_chn_run_forward(i); // Run the channel forward
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_FORWARD, relay_chn_get_state(i));
|
||||
relay_chn_stop(i); // Stop the channel
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Relay channels run reverse and update state", "[relay_chn][reverse]")
|
||||
{
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
// Test reverse run on all channels
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||
relay_chn_run_reverse(i); // Run the channel reverse
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
||||
relay_chn_stop(i); // Stop the channel
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||
|
||||
relay_chn_flip_direction(i); // Flip the direction
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_FLIPPED, relay_chn_get_direction(i));
|
||||
relay_chn_run_reverse(i); // Run the channel forward
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_REVERSE, relay_chn_get_state(i));
|
||||
relay_chn_stop(i); // Stop the channel
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||
}
|
||||
}
|
||||
|
||||
static void check_channels_state_unchanged(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < relay_chn_count; i++) {
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(i));
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_DIRECTION_DEFAULT, relay_chn_get_direction(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Relay channels do not change state for invalid channel", "[relay_chn][invalid]")
|
||||
{
|
||||
TEST_ESP_OK(relay_chn_create(gpio_map, gpio_count));
|
||||
// Test invalid channel run
|
||||
relay_chn_run_forward(relay_chn_count + 1); // Run the channel forward
|
||||
check_channels_state_unchanged();
|
||||
relay_chn_run_reverse(relay_chn_count + 1); // Run the channel reverse
|
||||
check_channels_state_unchanged();
|
||||
relay_chn_stop(relay_chn_count + 1); // Stop the channel
|
||||
TEST_ASSERT_EQUAL(RELAY_CHN_STATE_STOPPED, relay_chn_get_state(relay_chn_count + 1));
|
||||
check_channels_state_unchanged();
|
||||
relay_chn_flip_direction(relay_chn_count + 1); // Flip the direction
|
||||
check_channels_state_unchanged();
|
||||
}
|
||||
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
// Run before each test
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
// Run after each test
|
||||
}
|
||||
|
||||
// Test app entry point
|
||||
void app_main(void)
|
||||
{
|
||||
// Run the Unity tests menu
|
||||
unity_run_menu();
|
||||
}
|
||||
5
test/sdkconfig.defaults
Normal file
5
test/sdkconfig.defaults
Normal file
@@ -0,0 +1,5 @@
|
||||
# For IDF 5.0
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
# For IDF4.4
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
Reference in New Issue
Block a user