Fixed almost unconditional STOP command issuing when the channel is idle. Refs #1104, #1105 and closes #1107.
498 lines
18 KiB
C
498 lines
18 KiB
C
/*
|
|
* 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"
|
|
#include "relay_chn_notify.h"
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
#include "relay_chn_tilt.h"
|
|
#endif
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
|
#include "relay_chn_nvs.h"
|
|
#endif
|
|
|
|
#include "relay_chn_core.h"
|
|
|
|
|
|
static const char *TAG = "RELAY_CHN_CORE";
|
|
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
/*
|
|
* Run limit timer callback immediately dispatches a STOP command for the
|
|
* relevant channel as soon as the run limit time times out
|
|
*/
|
|
static void relay_chn_run_limit_timer_cb(void* arg)
|
|
{
|
|
relay_chn_ctl_t* chn_ctl = (relay_chn_ctl_t*) arg;
|
|
relay_chn_dispatch_cmd(chn_ctl, RELAY_CHN_CMD_STOP);
|
|
}
|
|
|
|
esp_err_t relay_chn_init_run_limit_timer(relay_chn_ctl_t *chn_ctl)
|
|
{
|
|
char timer_name[32];
|
|
snprintf(timer_name, sizeof(timer_name), "ch_%d_rlimit_timer", chn_ctl->id);
|
|
esp_timer_create_args_t timer_args = {
|
|
.callback = relay_chn_run_limit_timer_cb,
|
|
.arg = chn_ctl,
|
|
.name = timer_name
|
|
};
|
|
return esp_timer_create(&timer_args, &chn_ctl->run_limit_timer);
|
|
}
|
|
#endif
|
|
|
|
// 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);
|
|
}
|
|
|
|
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;
|
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
|
ret = relay_chn_nvs_init();
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize NVS for relay channel");
|
|
#endif
|
|
|
|
// 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 CONFIG_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");
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
// Initialize the tilt feature
|
|
#if CONFIG_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 // CONFIG_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
|
|
|
|
// Initialize the notify feature
|
|
ret = relay_chn_notify_init();
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize notify feature");
|
|
return ret;
|
|
}
|
|
|
|
void relay_chn_destroy(void)
|
|
{
|
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
relay_chn_tilt_deinit();
|
|
#endif
|
|
relay_chn_notify_deinit();
|
|
relay_chn_ctl_deinit();
|
|
relay_chn_output_deinit();
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
|
relay_chn_nvs_deinit();
|
|
#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;
|
|
|
|
relay_chn_notify_state_change(chn_ctl->id, old_state, new_state);
|
|
}
|
|
|
|
static void relay_chn_execute_idle(relay_chn_ctl_t *chn_ctl);
|
|
|
|
static void relay_chn_start_timer_or_idle(relay_chn_ctl_t *chn_ctl, esp_timer_handle_t timer, uint32_t time_ms, const char* timer_name)
|
|
{
|
|
if (relay_chn_start_esp_timer_once(timer, time_ms) != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to start %s timer for ch %d", timer_name, chn_ctl->id);
|
|
// Attempt to go to a safe state.
|
|
// relay_chn_execute_idle is safe to call, it stops timers and sets state.
|
|
relay_chn_execute_idle(chn_ctl);
|
|
}
|
|
}
|
|
|
|
static void relay_chn_stop_prv(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);
|
|
|
|
// 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));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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 || chn_ctl->state == RELAY_CHN_STATE_IDLE) {
|
|
return; // Do nothing if already stopped or idle
|
|
}
|
|
// If the command is STOP, issue it immediately
|
|
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
|
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 current_time_ms = (uint32_t)(esp_timer_get_time() / 1000);
|
|
if (current_time_ms < last_run_cmd_time_ms) { // Timer overflow
|
|
// If timer overflowed, it's been a long time. Run immediately.
|
|
relay_chn_dispatch_cmd(chn_ctl, cmd);
|
|
} else {
|
|
uint32_t inertia_time_passed_ms = current_time_ms - last_run_cmd_time_ms;
|
|
if (inertia_time_passed_ms < CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS) {
|
|
uint32_t inertia_time_ms = CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS - inertia_time_passed_ms;
|
|
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
|
|
if (relay_chn_start_esp_timer_once(chn_ctl->inertia_timer, inertia_time_ms) != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to start inertia timer for ch %d", chn_ctl->id);
|
|
relay_chn_execute_idle(chn_ctl);
|
|
}
|
|
} 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_stop_prv(chn_ctl);
|
|
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_stop_prv(chn_ctl);
|
|
|
|
// 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_timer_or_idle(chn_ctl, chn_ctl->inertia_timer, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS, "inertia");
|
|
break;
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
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, CONFIG_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, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default: ESP_LOGD(TAG, "relay_chn_evaluate: Unknown relay channel state!");
|
|
}
|
|
}
|
|
|
|
#if CONFIG_RELAY_CHN_COUNT > 1
|
|
bool relay_chn_is_channel_id_valid(uint8_t chn_id)
|
|
{
|
|
bool valid = chn_id < CONFIG_RELAY_CHN_COUNT;
|
|
if (!valid) {
|
|
ESP_LOGE(TAG, "Invalid channel ID: %d", chn_id);
|
|
}
|
|
return valid;
|
|
}
|
|
#endif // CONFIG_RELAY_CHN_COUNT > 1
|
|
|
|
|
|
static 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_execute_stop(relay_chn_ctl_t *chn_ctl)
|
|
{
|
|
relay_chn_stop_prv(chn_ctl);
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
esp_timer_stop(chn_ctl->run_limit_timer);
|
|
#endif
|
|
|
|
// Invalidate the channel's timer if it is active
|
|
esp_timer_stop(chn_ctl->inertia_timer);
|
|
|
|
relay_chn_cmd_t last_run_cmd = relay_chn_run_info_get_last_run_cmd(chn_ctl->run_info);
|
|
if (last_run_cmd == RELAY_CHN_CMD_FORWARD || last_run_cmd == RELAY_CHN_CMD_REVERSE ) {
|
|
// Schedule IDLE
|
|
chn_ctl->pending_cmd = RELAY_CHN_CMD_IDLE;
|
|
relay_chn_start_timer_or_idle(chn_ctl, chn_ctl->inertia_timer, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS, "idle");
|
|
} else {
|
|
// If the channel was not running forward or reverse, issue a free command immediately
|
|
relay_chn_execute_idle(chn_ctl);
|
|
}
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
relay_chn_start_timer_or_idle(chn_ctl, chn_ctl->run_limit_timer, chn_ctl->run_limit_sec * 1000, "run limit");
|
|
#endif
|
|
}
|
|
|
|
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);
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
relay_chn_start_timer_or_idle(chn_ctl, chn_ctl->run_limit_timer, chn_ctl->run_limit_sec * 1000, "run limit");
|
|
#endif
|
|
}
|
|
|
|
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_timer_or_idle(chn_ctl, chn_ctl->inertia_timer, CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS, "flip inertia");
|
|
}
|
|
|
|
// Dispatch relay channel command
|
|
void relay_chn_dispatch_cmd(relay_chn_ctl_t *chn_ctl, relay_chn_cmd_t cmd) {
|
|
ESP_LOGD(TAG, "relay_chn_dispatch_cmd: Command: %d", cmd);
|
|
|
|
switch (cmd) {
|
|
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!");
|
|
}
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
// 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
|
|
}
|
|
|
|
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 CONFIG_RELAY_CHN_ENABLE_TILTING
|
|
case RELAY_CHN_STATE_TILT_FORWARD:
|
|
return "TILT_FORWARD";
|
|
case RELAY_CHN_STATE_TILT_REVERSE:
|
|
return "TILT_REVERSE";
|
|
#endif
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
} |