/* * 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 RELAY_CHN_ENABLE_NVS == 1 #include "relay_chn_nvs.h" #endif 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; #if RELAY_CHN_ENABLE_RUN_LIMIT == 1 uint16_t run_limit_sec = RELAY_CHN_RUN_LIMIT_DEFAULT_SEC; #if RELAY_CHN_ENABLE_NVS == 1 // 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 < 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 RELAY_CHN_ENABLE_RUN_LIMIT == 1 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) { 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); } #if RELAY_CHN_ENABLE_RUN_LIMIT == 1 uint16_t relay_chn_ctl_get_run_limit(uint8_t chn_id) { if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) { ESP_LOGE(TAG, "get_run_limit: Invalid channel ID: %d", chn_id); return 0; } return chn_ctls[chn_id].run_limit_sec; } void relay_chn_ctl_set_run_limit(uint8_t chn_id, uint16_t time_sec) { if (!relay_chn_is_channel_id_valid(chn_id) || chn_id == RELAY_CHN_ID_ALL) { ESP_LOGE(TAG, "set_run_limit: Invalid channel ID: %d", chn_id); return; } // Check for boundaries if (time_sec > RELAY_CHN_RUN_LIMIT_MAX_SEC) time_sec = RELAY_CHN_RUN_LIMIT_MAX_SEC; else if (time_sec < RELAY_CHN_RUN_LIMIT_MIN_SEC) time_sec = RELAY_CHN_RUN_LIMIT_MIN_SEC; chn_ctls[chn_id].run_limit_sec = time_sec; #if RELAY_CHN_ENABLE_NVS == 1 relay_chn_nvs_set_run_limit(chn_id, time_sec); #endif } #endif 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; }