Compare commits
2 Commits
v0.1
...
437c013a2e
| Author | SHA1 | Date | |
|---|---|---|---|
| 437c013a2e | |||
| 3a47584a86 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -100,8 +100,3 @@ CTestTestfile.cmake
|
|||||||
_deps
|
_deps
|
||||||
CMakeUserPresets.json
|
CMakeUserPresets.json
|
||||||
|
|
||||||
# Build directory
|
|
||||||
build
|
|
||||||
|
|
||||||
# unity-app directory
|
|
||||||
unity-app
|
|
||||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"relay_chn.h": "c"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
idf_component_register(SRCS "src/relay_chn.c"
|
idf_component_register(SRCS "relay_chn.c"
|
||||||
INCLUDE_DIRS include
|
INCLUDE_DIRS include
|
||||||
REQUIRES driver
|
REQUIRES driver
|
||||||
PRIV_REQUIRES esp_timer esp_event)
|
PRIV_REQUIRES esp_timer esp_event)
|
||||||
|
|||||||
@@ -23,14 +23,11 @@
|
|||||||
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RELAY_CHN_ID_ALL CONFIG_RELAY_CHN_COUNT ///< Special ID to address all channels
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enumeration for relay channel direction.
|
* @brief Enumeration for relay channel direction.
|
||||||
*/
|
*/
|
||||||
@@ -61,20 +58,6 @@ enum relay_chn_state_enum {
|
|||||||
*/
|
*/
|
||||||
typedef enum relay_chn_state_enum relay_chn_state_t;
|
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.
|
* @brief Create and initialize relay channels.
|
||||||
@@ -91,26 +74,6 @@ typedef void (*relay_chn_state_listener_t)(uint8_t chn_id, relay_chn_state_t old
|
|||||||
*/
|
*/
|
||||||
esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count);
|
esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 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.
|
* @brief Get the state of the specified relay channel.
|
||||||
*
|
*
|
||||||
@@ -137,14 +100,6 @@ relay_chn_state_t relay_chn_get_state(uint8_t chn_id);
|
|||||||
*/
|
*/
|
||||||
char *relay_chn_get_state_str(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.
|
* @brief Runs the relay channel in the forward direction.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_task.h"
|
#include "esp_task.h"
|
||||||
@@ -24,11 +23,12 @@
|
|||||||
#include "relay_chn.h"
|
#include "relay_chn.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
// TODO: on_state change API si ekle
|
||||||
|
|
||||||
#define RELAY_CHN_OPPOSITE_INERTIA_MS CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS
|
#define RELAY_CHN_OPPOSITE_INERTIA_MS CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS
|
||||||
#define RELAY_CHN_COUNT CONFIG_RELAY_CHN_COUNT
|
#define RELAY_CHN_COUNT CONFIG_RELAY_CHN_COUNT
|
||||||
|
|
||||||
static const char *TAG = "relay_chn";
|
const char* TAG = "relay_chn";
|
||||||
|
|
||||||
ESP_EVENT_DEFINE_BASE(RELAY_CHN_CMD_EVENT);
|
ESP_EVENT_DEFINE_BASE(RELAY_CHN_CMD_EVENT);
|
||||||
|
|
||||||
@@ -82,17 +82,9 @@ typedef struct relay_chn_type {
|
|||||||
relay_chn_run_info_t run_info; ///< Runtime information 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_output_t output; ///< Output configuration of the relay channel.
|
||||||
relay_chn_cmd_t pending_cmd; ///< The command that is pending to be issued
|
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.
|
esp_timer_handle_t timer; ///< Timer to handle the opposite direction inertia time.
|
||||||
} relay_chn_t;
|
} relay_chn_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Structure to manage the state change listeners.
|
|
||||||
*/
|
|
||||||
struct relay_chn_state_listener_manager_type {
|
|
||||||
uint8_t listener_count; ///< The number of registered listeners.
|
|
||||||
relay_chn_state_listener_t *listeners; ///< The list that holds references to the registered listeners.
|
|
||||||
} relay_chn_state_listener_manager;
|
|
||||||
|
|
||||||
|
|
||||||
static relay_chn_t relay_channels[RELAY_CHN_COUNT];
|
static relay_chn_t relay_channels[RELAY_CHN_COUNT];
|
||||||
static esp_event_loop_handle_t relay_chn_event_loop;
|
static esp_event_loop_handle_t relay_chn_event_loop;
|
||||||
@@ -162,7 +154,7 @@ static esp_err_t relay_chn_init_timer(relay_chn_t *relay_chn)
|
|||||||
.arg = &relay_chn->id,
|
.arg = &relay_chn->id,
|
||||||
.name = timer_name
|
.name = timer_name
|
||||||
};
|
};
|
||||||
return esp_timer_create(&timer_args, &relay_chn->inertia_timer);
|
return esp_timer_create(&timer_args, &relay_chn->timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,7 +172,7 @@ static bool relay_chn_is_gpio_valid(gpio_num_t gpio)
|
|||||||
static esp_err_t relay_chn_create_event_loop()
|
static esp_err_t relay_chn_create_event_loop()
|
||||||
{
|
{
|
||||||
esp_event_loop_args_t loop_args = {
|
esp_event_loop_args_t loop_args = {
|
||||||
.queue_size = RELAY_CHN_COUNT * 8,
|
.queue_size = 10,
|
||||||
.task_name = "relay_chn_event_loop",
|
.task_name = "relay_chn_event_loop",
|
||||||
.task_priority = ESP_TASKD_EVENT_PRIO - 1,
|
.task_priority = ESP_TASKD_EVENT_PRIO - 1,
|
||||||
.task_stack_size = 2048,
|
.task_stack_size = 2048,
|
||||||
@@ -212,9 +204,8 @@ esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count)
|
|||||||
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
||||||
int gpio_index = i << 1; // gpio_index = i * 2
|
gpio_num_t forward_pin = gpio_map[i];
|
||||||
gpio_num_t forward_pin = gpio_map[gpio_index];
|
gpio_num_t reverse_pin = gpio_map[i+1];
|
||||||
gpio_num_t reverse_pin = gpio_map[gpio_index + 1];
|
|
||||||
// Check if the GPIOs are valid
|
// Check if the GPIOs are valid
|
||||||
if (!relay_chn_is_gpio_valid(forward_pin)) {
|
if (!relay_chn_is_gpio_valid(forward_pin)) {
|
||||||
ESP_LOGE(TAG, "Invalid GPIO pin number: %d", forward_pin);
|
ESP_LOGE(TAG, "Invalid GPIO pin number: %d", forward_pin);
|
||||||
@@ -244,7 +235,7 @@ esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count)
|
|||||||
relay_chn->output.forward_pin = forward_pin;
|
relay_chn->output.forward_pin = forward_pin;
|
||||||
relay_chn->output.reverse_pin = reverse_pin;
|
relay_chn->output.reverse_pin = reverse_pin;
|
||||||
relay_chn->output.direction = RELAY_CHN_DIRECTION_DEFAULT;
|
relay_chn->output.direction = RELAY_CHN_DIRECTION_DEFAULT;
|
||||||
relay_chn->state = RELAY_CHN_STATE_FREE;
|
relay_chn->state = RELAY_CHN_STATE_STOPPED;
|
||||||
relay_chn->pending_cmd = RELAY_CHN_CMD_NONE;
|
relay_chn->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||||
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_NONE;
|
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_NONE;
|
||||||
ret |= relay_chn_init_timer(relay_chn);// Create direction change inertia timer
|
ret |= relay_chn_init_timer(relay_chn);// Create direction change inertia timer
|
||||||
@@ -257,86 +248,9 @@ esp_err_t relay_chn_create(const gpio_num_t* gpio_map, uint8_t gpio_count)
|
|||||||
// Create relay channel command event loop
|
// Create relay channel command event loop
|
||||||
ret |= relay_chn_create_event_loop();
|
ret |= relay_chn_create_event_loop();
|
||||||
|
|
||||||
// Init the state listener manager
|
|
||||||
relay_chn_state_listener_manager.listeners = malloc(sizeof(relay_chn_state_listener_t*));
|
|
||||||
if (relay_chn_state_listener_manager.listeners == NULL) {
|
|
||||||
ESP_LOGE(TAG, "Failed to initialize memory for the listeners!");
|
|
||||||
ret = ESP_ERR_NO_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int relay_chn_listener_index(relay_chn_state_listener_t listener)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < relay_chn_state_listener_manager.listener_count; i++) {
|
|
||||||
if (relay_chn_state_listener_manager.listeners[i] == listener) {
|
|
||||||
// This is the listener to unregister. Check if it is in the middle
|
|
||||||
ESP_LOGD(TAG, "relay_chn_listener_index: Listener %p; found at index %d.", listener, i);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t relay_chn_register_listener(relay_chn_state_listener_t listener)
|
|
||||||
{
|
|
||||||
if (listener == NULL) {
|
|
||||||
ESP_LOGE(TAG, "relay_chn_register_listener: A NULL listener given.");
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relay_chn_listener_index(listener) > -1) {
|
|
||||||
ESP_LOGD(TAG, "relay_chn_register_listener: The listener %p is already registered.", listener);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "relay_chn_register_listener: Register listener: %p", listener);
|
|
||||||
relay_chn_state_listener_manager.listeners[relay_chn_state_listener_manager.listener_count] = listener;
|
|
||||||
// Update listener count
|
|
||||||
relay_chn_state_listener_manager.listener_count++;
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void relay_chn_unregister_listener(relay_chn_state_listener_t listener)
|
|
||||||
{
|
|
||||||
if (listener == NULL) {
|
|
||||||
ESP_LOGD(TAG, "relay_chn_unregister_listener: A NULL listener given, nothing to do.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Search the listener in the listeners list and get its index if exists
|
|
||||||
int i = relay_chn_listener_index(listener);
|
|
||||||
if (i == -1) {
|
|
||||||
ESP_LOGD(TAG, "relay_chn_unregister_listener: %p is not registered already.", listener);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t max_index = relay_chn_state_listener_manager.listener_count - 1;
|
|
||||||
// Check whether the listener's index is in the middle
|
|
||||||
if (i == max_index) {
|
|
||||||
// free(&relay_chn_state_listener_manager.listeners[i]);
|
|
||||||
relay_chn_state_listener_manager.listeners[i] = NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// It is in the middle, so align the next elements in the list and then free the last empty pointer
|
|
||||||
// Align the next elements
|
|
||||||
uint8_t num_of_elements = max_index - i;
|
|
||||||
relay_chn_state_listener_t *pnext = NULL;
|
|
||||||
// (i + j): current index; (i + j + 1): next index
|
|
||||||
for (uint8_t j = 0; j < num_of_elements; j++) {
|
|
||||||
uint8_t current_index = i + j;
|
|
||||||
uint8_t next_index = current_index + 1;
|
|
||||||
pnext = &relay_chn_state_listener_manager.listeners[next_index];
|
|
||||||
relay_chn_state_listener_manager.listeners[current_index] = *pnext;
|
|
||||||
}
|
|
||||||
// free(&relay_chn_state_listener_manager.listeners[max_index]); // Free the last element
|
|
||||||
relay_chn_state_listener_manager.listeners[max_index] = NULL; // Free the last element
|
|
||||||
}
|
|
||||||
// Decrease listener count
|
|
||||||
relay_chn_state_listener_manager.listener_count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check channel ID validity
|
* @brief Check channel ID validity
|
||||||
*
|
*
|
||||||
@@ -346,7 +260,7 @@ void relay_chn_unregister_listener(relay_chn_state_listener_t listener)
|
|||||||
*/
|
*/
|
||||||
static bool relay_chn_is_channel_id_valid(uint8_t chn_id)
|
static bool relay_chn_is_channel_id_valid(uint8_t chn_id)
|
||||||
{
|
{
|
||||||
bool valid = (chn_id < RELAY_CHN_COUNT) || chn_id == RELAY_CHN_ID_ALL;
|
bool valid = chn_id >= 0 && chn_id < RELAY_CHN_COUNT;
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
ESP_LOGE(TAG, "Invalid channel ID: %d", chn_id);
|
ESP_LOGE(TAG, "Invalid channel ID: %d", chn_id);
|
||||||
}
|
}
|
||||||
@@ -366,35 +280,19 @@ static void relay_chn_dispatch_cmd(relay_chn_t *relay_chn, relay_chn_cmd_t cmd)
|
|||||||
sizeof(relay_chn->id), portMAX_DELAY);
|
sizeof(relay_chn->id), portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t relay_chn_invalidate_timer(relay_chn_t *relay_chn)
|
||||||
static esp_err_t relay_chn_start_esp_timer_once(esp_timer_handle_t esp_timer, uint32_t time_ms)
|
|
||||||
{
|
{
|
||||||
// Invalidate the channel's timer if it is active
|
if (esp_timer_is_active(relay_chn->timer)) {
|
||||||
esp_err_t ret = esp_timer_start_once(esp_timer, time_ms * 1000);
|
return esp_timer_stop(relay_chn->timer);
|
||||||
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 ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void relay_chn_update_state(relay_chn_t *relay_chn, relay_chn_state_t new_state)
|
static esp_err_t relay_chn_start_timer(relay_chn_t *relay_chn, uint32_t time_ms)
|
||||||
{
|
{
|
||||||
relay_chn_state_t old = relay_chn->state;
|
// Invalidate the channel's timer if it is active
|
||||||
relay_chn->state = new_state;
|
relay_chn_invalidate_timer(relay_chn);
|
||||||
for (uint8_t i = 0; i < relay_chn_state_listener_manager.listener_count; i++) {
|
return esp_timer_start_once(relay_chn->timer, time_ms * 1000);
|
||||||
relay_chn_state_listener_t listener = relay_chn_state_listener_manager.listeners[i];
|
|
||||||
if (listener == NULL) {
|
|
||||||
relay_chn_state_listener_manager.listener_count -= 1;
|
|
||||||
ESP_LOGD(TAG, "relay_chn_update_state: A listener is NULL at index: %u", i);
|
|
||||||
}
|
|
||||||
// Emit the state change to the listeners
|
|
||||||
listener(relay_chn->id, old, new_state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -446,14 +344,8 @@ static void relay_chn_issue_cmd(relay_chn_t* relay_chn, relay_chn_cmd_t cmd)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RELAY_CHN_STATE_STOPPED:
|
case RELAY_CHN_STATE_STOPPED:
|
||||||
if (relay_chn->run_info.last_run_cmd == cmd || relay_chn->run_info.last_run_cmd == RELAY_CHN_CMD_NONE) {
|
if (relay_chn->run_info.last_run_cmd == cmd) {
|
||||||
// Since the state is STOPPED, the inertia timer should be running and must be invalidated
|
// If the last run command is the same as the current command, run the command immediately
|
||||||
// with the pending FREE command
|
|
||||||
esp_timer_stop(relay_chn->inertia_timer);
|
|
||||||
relay_chn->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(relay_chn, cmd);
|
relay_chn_dispatch_cmd(relay_chn, cmd);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -463,11 +355,11 @@ static void relay_chn_issue_cmd(relay_chn_t* relay_chn, relay_chn_cmd_t cmd)
|
|||||||
uint32_t inertia_time_ms = RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
uint32_t inertia_time_ms = RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
||||||
if (inertia_time_ms > 0) {
|
if (inertia_time_ms > 0) {
|
||||||
relay_chn->pending_cmd = cmd;
|
relay_chn->pending_cmd = cmd;
|
||||||
relay_chn_state_t new_state = cmd == RELAY_CHN_CMD_FORWARD
|
relay_chn->state = cmd == RELAY_CHN_CMD_FORWARD
|
||||||
? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
? RELAY_CHN_STATE_FORWARD_PENDING
|
||||||
relay_chn_update_state(relay_chn, new_state);
|
: RELAY_CHN_STATE_REVERSE_PENDING;
|
||||||
// If the time passed is less than the opposite inertia time, wait for the remaining time
|
// If the time passed is less than the opposite inertia time, wait for the remaining time
|
||||||
relay_chn_start_esp_timer_once(relay_chn->inertia_timer, inertia_time_ms);
|
relay_chn_start_timer(relay_chn, inertia_time_ms);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If the time passed is more than the opposite inertia time, run the command immediately
|
// If the time passed is more than the opposite inertia time, run the command immediately
|
||||||
@@ -484,21 +376,16 @@ static void relay_chn_issue_cmd(relay_chn_t* relay_chn, relay_chn_cmd_t cmd)
|
|||||||
relay_chn_dispatch_cmd(relay_chn, cmd);
|
relay_chn_dispatch_cmd(relay_chn, cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relay_chn->run_info.last_run_cmd == cmd) {
|
if (relay_chn->run_info.last_run_cmd == cmd) {
|
||||||
// If the last run command is the same as the current command, do nothing
|
// If the last run command is the same as the current command, do nothing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the channel first before the schedule
|
|
||||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
|
||||||
|
|
||||||
// If the last run command is different from the current command, wait for the opposite inertia time
|
// If the last run command is different from the current command, wait for the opposite inertia time
|
||||||
relay_chn->pending_cmd = cmd;
|
relay_chn->pending_cmd = cmd;
|
||||||
relay_chn_state_t new_state = cmd == RELAY_CHN_CMD_FORWARD
|
relay_chn->state = cmd == RELAY_CHN_CMD_FORWARD ? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
||||||
? RELAY_CHN_STATE_FORWARD_PENDING : RELAY_CHN_STATE_REVERSE_PENDING;
|
relay_chn_start_timer(relay_chn, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||||
relay_chn_update_state(relay_chn, new_state);
|
|
||||||
relay_chn_start_esp_timer_once(relay_chn->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: ESP_LOGD(TAG, "relay_chn_evaluate: Unknown relay channel state!");
|
default: ESP_LOGD(TAG, "relay_chn_evaluate: Unknown relay channel state!");
|
||||||
@@ -519,13 +406,21 @@ char *relay_chn_get_state_str(uint8_t chn_id)
|
|||||||
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
||||||
return "INVALID";
|
return "INVALID";
|
||||||
}
|
}
|
||||||
return relay_chn_state_str(relay_channels[chn_id].state);
|
switch (relay_channels[chn_id].state) {
|
||||||
}
|
case RELAY_CHN_STATE_FREE:
|
||||||
|
return "FREE";
|
||||||
static void relay_chn_issue_cmd_on_all_channels(relay_chn_cmd_t cmd)
|
case RELAY_CHN_STATE_STOPPED:
|
||||||
{
|
return "STOPPED";
|
||||||
for (int i = 0; i < RELAY_CHN_COUNT; i++) {
|
case RELAY_CHN_STATE_FORWARD:
|
||||||
relay_chn_issue_cmd(&relay_channels[i], cmd);
|
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";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,11 +428,6 @@ void relay_chn_run_forward(uint8_t chn_id)
|
|||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
||||||
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
relay_chn_issue_cmd_on_all_channels(RELAY_CHN_CMD_FORWARD);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_FORWARD);
|
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_FORWARD);
|
||||||
}
|
}
|
||||||
@@ -546,11 +436,6 @@ void relay_chn_run_reverse(uint8_t chn_id)
|
|||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
||||||
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
relay_chn_issue_cmd_on_all_channels(RELAY_CHN_CMD_REVERSE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_REVERSE);
|
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_REVERSE);
|
||||||
}
|
}
|
||||||
@@ -559,11 +444,6 @@ void relay_chn_stop(uint8_t chn_id)
|
|||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
||||||
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
relay_chn_issue_cmd_on_all_channels(RELAY_CHN_CMD_STOP);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_STOP);
|
||||||
}
|
}
|
||||||
@@ -572,11 +452,6 @@ void relay_chn_flip_direction(uint8_t chn_id)
|
|||||||
{
|
{
|
||||||
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
if (!relay_chn_is_channel_id_valid(chn_id)) return;
|
||||||
|
|
||||||
if (chn_id == RELAY_CHN_ID_ALL) {
|
|
||||||
relay_chn_issue_cmd_on_all_channels(RELAY_CHN_CMD_FLIP);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
relay_chn_t* relay_chn = &relay_channels[chn_id];
|
||||||
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_FLIP);
|
relay_chn_issue_cmd(relay_chn, RELAY_CHN_CMD_FLIP);
|
||||||
}
|
}
|
||||||
@@ -595,12 +470,12 @@ static void relay_chn_execute_stop(relay_chn_t *relay_chn)
|
|||||||
{
|
{
|
||||||
gpio_set_level(relay_chn->output.forward_pin, 0);
|
gpio_set_level(relay_chn->output.forward_pin, 0);
|
||||||
gpio_set_level(relay_chn->output.reverse_pin, 0);
|
gpio_set_level(relay_chn->output.reverse_pin, 0);
|
||||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_STOPPED);
|
relay_chn->state = RELAY_CHN_STATE_STOPPED;
|
||||||
|
|
||||||
// If there is any pending command, cancel it since the STOP command is issued right after it
|
// If there is any pending command, cancel it since the STOP command is issued right after it
|
||||||
relay_chn->pending_cmd = RELAY_CHN_CMD_NONE;
|
relay_chn->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||||
// Invalidate the channel's timer if it is active
|
// Invalidate the channel's timer if it is active
|
||||||
esp_timer_stop(relay_chn->inertia_timer);
|
relay_chn_invalidate_timer(relay_chn);
|
||||||
|
|
||||||
// If the channel was running, schedule a free command for the channel
|
// If the channel was running, schedule a free command for the channel
|
||||||
relay_chn_cmd_t last_run_cmd = relay_chn->run_info.last_run_cmd;
|
relay_chn_cmd_t last_run_cmd = relay_chn->run_info.last_run_cmd;
|
||||||
@@ -609,7 +484,7 @@ static void relay_chn_execute_stop(relay_chn_t *relay_chn)
|
|||||||
relay_chn->run_info.last_run_cmd_time_ms = esp_timer_get_time() / 1000;
|
relay_chn->run_info.last_run_cmd_time_ms = esp_timer_get_time() / 1000;
|
||||||
// Schedule a free command for the channel
|
// Schedule a free command for the channel
|
||||||
relay_chn->pending_cmd = RELAY_CHN_CMD_FREE;
|
relay_chn->pending_cmd = RELAY_CHN_CMD_FREE;
|
||||||
relay_chn_start_esp_timer_once(relay_chn->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
relay_chn_start_timer(relay_chn, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||||
} else {
|
} else {
|
||||||
// If the channel was not running, issue a free command immediately
|
// If the channel was not running, issue a free command immediately
|
||||||
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_FREE);
|
relay_chn_dispatch_cmd(relay_chn, RELAY_CHN_CMD_FREE);
|
||||||
@@ -620,16 +495,16 @@ static void relay_chn_execute_forward(relay_chn_t *relay_chn)
|
|||||||
{
|
{
|
||||||
gpio_set_level(relay_chn->output.reverse_pin, 0);
|
gpio_set_level(relay_chn->output.reverse_pin, 0);
|
||||||
gpio_set_level(relay_chn->output.forward_pin, 1);
|
gpio_set_level(relay_chn->output.forward_pin, 1);
|
||||||
|
relay_chn->state = RELAY_CHN_STATE_FORWARD;
|
||||||
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_FORWARD;
|
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_FORWARD;
|
||||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_FORWARD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void relay_chn_execute_reverse(relay_chn_t *relay_chn)
|
static void relay_chn_execute_reverse(relay_chn_t *relay_chn)
|
||||||
{
|
{
|
||||||
gpio_set_level(relay_chn->output.forward_pin, 0);
|
gpio_set_level(relay_chn->output.forward_pin, 0);
|
||||||
gpio_set_level(relay_chn->output.reverse_pin, 1);
|
gpio_set_level(relay_chn->output.reverse_pin, 1);
|
||||||
|
relay_chn->state = RELAY_CHN_STATE_REVERSE;
|
||||||
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_REVERSE;
|
relay_chn->run_info.last_run_cmd = RELAY_CHN_CMD_REVERSE;
|
||||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_REVERSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void relay_chn_execute_flip(relay_chn_t *relay_chn)
|
static void relay_chn_execute_flip(relay_chn_t *relay_chn)
|
||||||
@@ -644,15 +519,15 @@ static void relay_chn_execute_flip(relay_chn_t *relay_chn)
|
|||||||
: RELAY_CHN_DIRECTION_DEFAULT;
|
: RELAY_CHN_DIRECTION_DEFAULT;
|
||||||
// Set an inertia on the channel to prevent any immediate movement
|
// Set an inertia on the channel to prevent any immediate movement
|
||||||
relay_chn->pending_cmd = RELAY_CHN_CMD_FREE;
|
relay_chn->pending_cmd = RELAY_CHN_CMD_FREE;
|
||||||
relay_chn_start_esp_timer_once(relay_chn->inertia_timer, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
relay_chn_start_timer(relay_chn, RELAY_CHN_OPPOSITE_INERTIA_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_chn_execute_free(relay_chn_t *relay_chn)
|
void relay_chn_execute_free(relay_chn_t *relay_chn)
|
||||||
{
|
{
|
||||||
|
relay_chn->state = RELAY_CHN_STATE_FREE;
|
||||||
relay_chn->pending_cmd = RELAY_CHN_CMD_NONE;
|
relay_chn->pending_cmd = RELAY_CHN_CMD_NONE;
|
||||||
// Invalidate the channel's timer if it is active
|
// Invalidate the channel's timer if it is active
|
||||||
esp_timer_stop(relay_chn->inertia_timer);
|
relay_chn_invalidate_timer(relay_chn);
|
||||||
relay_chn_update_state(relay_chn, RELAY_CHN_STATE_FREE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
|
static void relay_chn_event_handler(void* handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
|
||||||
@@ -702,24 +577,4 @@ static char *relay_chn_cmd_str(relay_chn_cmd_t cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *relay_chn_state_str(relay_chn_state_t state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case RELAY_CHN_STATE_FREE:
|
|
||||||
return "FREE";
|
|
||||||
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";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
#include "driver/gpio.h"
|
|
||||||
#include "unity.h"
|
#include "unity.h"
|
||||||
#include "unity_test_utils.h"
|
|
||||||
#include "relay_chn.h"
|
#include "relay_chn.h"
|
||||||
|
|
||||||
|
|
||||||
const gpio_num_t gpio_map[] = {GPIO_NUM_4, GPIO_NUM_5, GPIO_NUM_18, GPIO_NUM_19};
|
const gpip_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 gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
||||||
const uint8_t relay_chn_count = gpio_count / 2;
|
const uint8_t relay_chn_count = gpio_count / 2;
|
||||||
|
|
||||||
@@ -74,22 +72,4 @@ TEST_CASE("Relay channels do not change state for invalid channel", "[relay_chn]
|
|||||||
check_channels_state_unchanged();
|
check_channels_state_unchanged();
|
||||||
relay_chn_flip_direction(relay_chn_count + 1); // Flip the direction
|
relay_chn_flip_direction(relay_chn_count + 1); // Flip the direction
|
||||||
check_channels_state_unchanged();
|
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();
|
|
||||||
}
|
|
||||||
21
test/main/relay_chn_test_main.c
Normal file
21
test/main/relay_chn_test_main.c
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "unity.h"
|
||||||
|
#include "unity_test_runner.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void print_banner(const char*);
|
||||||
|
|
||||||
|
void app_main(void) {
|
||||||
|
|
||||||
|
print_banner("Starting interactive test menu");
|
||||||
|
/* This function will not return, and will be busy waiting for UART input.
|
||||||
|
* Make sure that task watchdog is disabled if you use this function.
|
||||||
|
*/
|
||||||
|
unity_run_menu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_banner(const char* text)
|
||||||
|
{
|
||||||
|
printf("\n##### %s #####\n\n", text);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user