Specific `_*all` and `_*all_with` functions were implemented to make the API more concise and clean, and to replace the use of `RELAY_CHN_ID_ALL`, which caused confusion within the API. Refs #1085
252 lines
7.6 KiB
C
252 lines
7.6 KiB
C
/*
|
|
* 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"
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
|
#include "relay_chn_nvs.h"
|
|
#endif
|
|
|
|
static const char *TAG = "RELAY_CHN_CTL";
|
|
|
|
static relay_chn_ctl_t chn_ctls[CONFIG_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 < CONFIG_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;
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
uint16_t run_limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC;
|
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
|
// Load run limit value from NVS
|
|
ret = relay_chn_nvs_get_run_limit(chn_ctl->id, &run_limit_sec);
|
|
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
|
|
ESP_LOGE(TAG, "Failed to load run limit from NVS for channel %d with error: %s", i, esp_err_to_name(ret));
|
|
}
|
|
#endif
|
|
chn_ctl->run_limit_sec = run_limit_sec;
|
|
ret = relay_chn_init_run_limit_timer(chn_ctl);
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize run limit timer");
|
|
#endif
|
|
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 < CONFIG_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;
|
|
}
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
if (chn_ctl->run_limit_timer != NULL) {
|
|
esp_timer_delete(chn_ctl->run_limit_timer);
|
|
chn_ctl->run_limit_timer = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
relay_chn_state_t relay_chn_ctl_get_state(uint8_t chn_id)
|
|
{
|
|
return relay_chn_is_channel_id_valid(chn_id) ?
|
|
chn_ctls[chn_id].state : RELAY_CHN_STATE_UNDEFINED;
|
|
}
|
|
|
|
esp_err_t relay_chn_ctl_get_state_all(relay_chn_state_t *states)
|
|
{
|
|
ESP_RETURN_ON_FALSE(states != NULL, ESP_ERR_INVALID_ARG, TAG, "states cannot be NULL");
|
|
|
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
|
relay_chn_state_t *dest_state = &states[i];
|
|
if (dest_state == NULL) {
|
|
ESP_LOGW(TAG, "get_state_all: States have been copied until channel %d since states[%d] is NULL", i, i);
|
|
break;
|
|
}
|
|
*dest_state = chn_ctls[i].state;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
char *relay_chn_ctl_get_state_str(uint8_t chn_id)
|
|
{
|
|
return relay_chn_is_channel_id_valid(chn_id)
|
|
? relay_chn_state_str(chn_ctls[chn_id].state)
|
|
: relay_chn_state_str(RELAY_CHN_STATE_UNDEFINED);
|
|
}
|
|
|
|
|
|
static void relay_chn_ctl_issue_cmd_on_all_channels(relay_chn_cmd_t cmd)
|
|
{
|
|
for (int i = 0; i < CONFIG_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))
|
|
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_FORWARD);
|
|
}
|
|
|
|
void relay_chn_ctl_run_forward_all()
|
|
{
|
|
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_FORWARD);
|
|
}
|
|
|
|
void relay_chn_ctl_run_reverse(uint8_t chn_id)
|
|
{
|
|
if (relay_chn_is_channel_id_valid(chn_id))
|
|
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_REVERSE);
|
|
}
|
|
|
|
void relay_chn_ctl_run_reverse_all()
|
|
{
|
|
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_REVERSE);
|
|
}
|
|
|
|
void relay_chn_ctl_stop(uint8_t chn_id)
|
|
{
|
|
if (relay_chn_is_channel_id_valid(chn_id))
|
|
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_STOP);
|
|
}
|
|
|
|
void relay_chn_ctl_stop_all()
|
|
{
|
|
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_STOP);
|
|
}
|
|
|
|
void relay_chn_ctl_flip_direction(uint8_t chn_id)
|
|
{
|
|
if (relay_chn_is_channel_id_valid(chn_id))
|
|
relay_chn_issue_cmd(&chn_ctls[chn_id], RELAY_CHN_CMD_FLIP);
|
|
}
|
|
|
|
void relay_chn_ctl_flip_direction_all()
|
|
{
|
|
relay_chn_ctl_issue_cmd_on_all_channels(RELAY_CHN_CMD_FLIP);
|
|
}
|
|
|
|
relay_chn_direction_t relay_chn_ctl_get_direction(uint8_t chn_id)
|
|
{
|
|
return relay_chn_is_channel_id_valid(chn_id)
|
|
? relay_chn_output_get_direction(chn_ctls[chn_id].output)
|
|
: RELAY_CHN_DIRECTION_DEFAULT;
|
|
}
|
|
|
|
esp_err_t relay_chn_ctl_get_direction_all(relay_chn_direction_t *directions)
|
|
{
|
|
ESP_RETURN_ON_FALSE(directions != NULL, ESP_ERR_INVALID_ARG, TAG, "directions cannot be NULL");
|
|
|
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
|
relay_chn_direction_t *dest_direction = &directions[i];
|
|
if (dest_direction == NULL) {
|
|
ESP_LOGW(TAG, "get_direction_all: Directions have been copied until channel %d since directions[%d] is NULL", i, i);
|
|
break;
|
|
}
|
|
*dest_direction = relay_chn_output_get_direction(chn_ctls[i].output);
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT
|
|
uint16_t relay_chn_ctl_get_run_limit(uint8_t chn_id)
|
|
{
|
|
return relay_chn_is_channel_id_valid(chn_id) ? chn_ctls[chn_id].run_limit_sec : 0;
|
|
}
|
|
|
|
esp_err_t relay_chn_ctl_get_run_limit_all(uint16_t *limits_sec)
|
|
{
|
|
ESP_RETURN_ON_FALSE(limits_sec != NULL, ESP_ERR_INVALID_ARG, TAG, "limits_sec cannot be NULL");
|
|
|
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
|
uint16_t *dest_limit_sec = &limits_sec[i];
|
|
if (dest_limit_sec == NULL) {
|
|
ESP_LOGW(TAG, "get_run_limit_all: Run limits have been copied until channel %d since limits_sec[%d] is NULL", i, i);
|
|
break;
|
|
}
|
|
*dest_limit_sec = chn_ctls[i].run_limit_sec;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static void relay_chn_ctl_set_run_limit_common(uint8_t chn_id, uint16_t limit_sec)
|
|
{
|
|
// Check for boundaries
|
|
if (limit_sec > CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC)
|
|
limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC;
|
|
else if (limit_sec < CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC)
|
|
limit_sec = CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC;
|
|
|
|
chn_ctls[chn_id].run_limit_sec = limit_sec;
|
|
|
|
#if CONFIG_RELAY_CHN_ENABLE_NVS
|
|
relay_chn_nvs_set_run_limit(chn_id, limit_sec);
|
|
#endif
|
|
}
|
|
|
|
void relay_chn_ctl_set_run_limit(uint8_t chn_id, uint16_t limit_sec)
|
|
{
|
|
if (!relay_chn_is_channel_id_valid(chn_id)) {
|
|
ESP_LOGE(TAG, "set_run_limit: Invalid channel ID: %d", chn_id);
|
|
return;
|
|
}
|
|
relay_chn_ctl_set_run_limit_common(chn_id, limit_sec);
|
|
}
|
|
|
|
esp_err_t relay_chn_ctl_set_run_limit_all(uint16_t *limits_sec)
|
|
{
|
|
ESP_RETURN_ON_FALSE(limits_sec != NULL, ESP_ERR_INVALID_ARG, TAG, "limits_sec cannot be NULL");
|
|
|
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
|
uint16_t *src_limit_sec = &limits_sec[i];
|
|
if (src_limit_sec == NULL) {
|
|
ESP_LOGW(TAG, "set_run_limit_all: Run limits have been set until channel %d since limits_sec[%d] is NULL", i, i);
|
|
break;
|
|
}
|
|
relay_chn_ctl_set_run_limit_common(i, *src_limit_sec);
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t relay_chn_ctl_set_run_limit_all_with(uint16_t limit_sec)
|
|
{
|
|
for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) {
|
|
relay_chn_ctl_set_run_limit_common(i, limit_sec);
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
#endif
|
|
|
|
relay_chn_ctl_t *relay_chn_ctl_get(uint8_t chn_id)
|
|
{
|
|
return relay_chn_is_channel_id_valid(chn_id) ? &chn_ctls[chn_id] : NULL;
|
|
}
|
|
|
|
relay_chn_ctl_t *relay_chn_ctl_get_all(void)
|
|
{
|
|
return chn_ctls;
|
|
} |