/* * SPDX-FileCopyrightText: 2025 Kozmotronik Tech * * SPDX-License-Identifier: MIT */ #include "esp_check.h" #include "esp_log.h" #include "relay_chn_output.h" #include "relay_chn_core.h" #if CONFIG_RELAY_CHN_ENABLE_NVS #include "relay_chn_nvs.h" #endif static const char *TAG = "RELAY_CHN_OUTPUT"; #if CONFIG_RELAY_CHN_COUNT > 1 static relay_chn_output_t outputs[CONFIG_RELAY_CHN_COUNT]; #else static relay_chn_output_t output; #endif static esp_err_t relay_chn_output_check_gpio_capabilities(uint8_t gpio_count) { // Check if the device's GPIOs are enough for the number of channels if (CONFIG_RELAY_CHN_COUNT > (GPIO_PIN_COUNT / 2)) { ESP_LOGE(TAG, "Not enough GPIOs for the number of channels!"); ESP_LOGE(TAG, "Max available num of channels: %d, requested channels: %d", GPIO_PIN_COUNT / 2, CONFIG_RELAY_CHN_COUNT); return ESP_ERR_INVALID_ARG; } // Check if the provided GPIOs correspond to the number of channels if (gpio_count != CONFIG_RELAY_CHN_COUNT * 2) { ESP_LOGE(TAG, "Invalid number of GPIOs provided: %d", gpio_count); ESP_LOGE(TAG, "Expected number of GPIOs: %d", CONFIG_RELAY_CHN_COUNT * 2); return ESP_ERR_INVALID_ARG; } return ESP_OK; } static esp_err_t relay_chn_output_ctl_init(relay_chn_output_t *output, gpio_num_t forward_pin, gpio_num_t reverse_pin, relay_chn_direction_t direction) { ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(forward_pin), ESP_ERR_INVALID_ARG, TAG, "Invalid GPIO pin number for forward_pin: %d", forward_pin); ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(reverse_pin), ESP_ERR_INVALID_ARG, TAG, "Invalid GPIO pin number for reverse_pin: %d", reverse_pin); // Check if the GPIOs are valid esp_err_t ret; // Initialize the GPIOs ret = gpio_reset_pin(forward_pin); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to reset GPIO forward pin: %d", forward_pin); ret = gpio_set_direction(forward_pin, GPIO_MODE_OUTPUT); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set GPIO direction for forward pin: %d", forward_pin); ret = gpio_reset_pin(reverse_pin); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to reset GPIO reverse pin: %d", reverse_pin); ret = gpio_set_direction(reverse_pin, GPIO_MODE_OUTPUT); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set GPIO direction for reverse pin: %d", reverse_pin); // Initialize the GPIOs // Initialize the relay channel output output->forward_pin = direction == RELAY_CHN_DIRECTION_DEFAULT ? forward_pin : reverse_pin; output->reverse_pin = direction == RELAY_CHN_DIRECTION_DEFAULT ? reverse_pin : forward_pin; output->direction = direction; return ESP_OK; } #if CONFIG_RELAY_CHN_ENABLE_NVS static esp_err_t relay_chn_output_load_direction(uint8_t ch, relay_chn_direction_t *direction) { esp_err_t ret = relay_chn_nvs_get_direction(ch, direction); if (ret == ESP_ERR_NVS_NOT_FOUND) { // If the key does not exist, use the default direction *direction = RELAY_CHN_DIRECTION_DEFAULT; } else if (ret != ESP_OK) { ESP_RETURN_ON_ERROR(ret, TAG, "Failed to get direction from storage for channel %d: %s", ch, esp_err_to_name(ret)); } return ESP_OK; } #endif esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count) { esp_err_t ret; ret = relay_chn_output_check_gpio_capabilities(gpio_count); ESP_RETURN_ON_ERROR(ret, TAG, "Device does not support the provided GPIOs"); #if CONFIG_RELAY_CHN_COUNT > 1 for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { relay_chn_output_t* output = &outputs[i]; int gpio_index = i << 1; // gpio_index = i * 2 gpio_num_t forward_pin = (gpio_num_t) gpio_map[gpio_index]; gpio_num_t reverse_pin = (gpio_num_t) gpio_map[gpio_index + 1]; relay_chn_direction_t direction = RELAY_CHN_DIRECTION_DEFAULT; #if CONFIG_RELAY_CHN_ENABLE_NVS // If NVS storage is enabled, retrieve the direction from storage ret = relay_chn_output_load_direction(i, &direction); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load direction from storage for channel %d", i); #endif ret = relay_chn_output_ctl_init(output, forward_pin, reverse_pin, direction); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel %d", i); } #else relay_chn_direction_t direction = RELAY_CHN_DIRECTION_DEFAULT; #if CONFIG_RELAY_CHN_ENABLE_NVS // If NVS storage is enabled, retrieve the direction from storage ret = relay_chn_output_load_direction(0, &direction); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load direction from storage for channel %d", 0); #endif ret = relay_chn_output_ctl_init(&output, gpio_map[0], gpio_map[1], direction); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel"); #endif return ESP_OK; } static void relay_chn_output_ctl_deinit(relay_chn_output_t *output) { gpio_reset_pin(output->forward_pin); gpio_reset_pin(output->reverse_pin); } void relay_chn_output_deinit() { #if CONFIG_RELAY_CHN_COUNT > 1 for (int i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { relay_chn_output_ctl_deinit(&outputs[i]); } #else relay_chn_output_ctl_deinit(&output); #endif // CONFIG_RELAY_CHN_COUNT > 1 } #if CONFIG_RELAY_CHN_COUNT > 1 relay_chn_output_t *relay_chn_output_get(uint8_t chn_id) { if (!relay_chn_is_channel_id_valid(chn_id)) { return NULL; } return &outputs[chn_id]; } relay_chn_output_t *relay_chn_output_get_all(void) { return outputs; } #else relay_chn_output_t *relay_chn_output_get(void) { return &output; } #endif // CONFIG_RELAY_CHN_COUNT > 1 esp_err_t relay_chn_output_stop(relay_chn_output_t *output) { esp_err_t ret; ret = gpio_set_level(output->forward_pin, 0); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to LOW"); return gpio_set_level(output->reverse_pin, 0); } esp_err_t relay_chn_output_forward(relay_chn_output_t *output) { esp_err_t ret; ret = gpio_set_level(output->forward_pin, 1); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to HIGH"); return gpio_set_level(output->reverse_pin, 0); } esp_err_t relay_chn_output_reverse(relay_chn_output_t *output) { esp_err_t ret; ret = gpio_set_level(output->forward_pin, 0); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set forward pin to LOW"); return gpio_set_level(output->reverse_pin, 1); } void relay_chn_output_flip(relay_chn_output_t *output) { // Flip the output GPIO pins gpio_num_t temp = output->forward_pin; output->forward_pin = output->reverse_pin; output->reverse_pin = temp; // Flip the direction output->direction = (output->direction == RELAY_CHN_DIRECTION_DEFAULT) ? RELAY_CHN_DIRECTION_FLIPPED : RELAY_CHN_DIRECTION_DEFAULT; #if CONFIG_RELAY_CHN_ENABLE_NVS uint8_t ch = 0; #if CONFIG_RELAY_CHN_COUNT > 1 for (uint8_t i = 0; i < CONFIG_RELAY_CHN_COUNT; i++) { if (output == &outputs[i]) { ch = i; break; } } #endif esp_err_t ret = relay_chn_nvs_set_direction(ch, output->direction); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to save flipped direction for channel %d: %s", ch, esp_err_to_name(ret)); } #endif } relay_chn_direction_t relay_chn_output_get_direction(relay_chn_output_t *output) { return output->direction; }