/* * SPDX-FileCopyrightText: 2025 Kozmotronik Tech * * SPDX-License-Identifier: MIT */ #include "esp_check.h" #include "esp_log.h" #include "relay_chn_defs.h" #include "relay_chn_output.h" #include "relay_chn_core.h" static const char *TAG = "RELAY_CHN_OUTPUT"; #if RELAY_CHN_COUNT > 1 static relay_chn_output_t outputs[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 (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, RELAY_CHN_COUNT); return ESP_ERR_INVALID_ARG; } // Check if the provided GPIOs correspond to the number of channels if (gpio_count != RELAY_CHN_COUNT * 2) { ESP_LOGE(TAG, "Invalid number of GPIOs provided: %d", gpio_count); ESP_LOGE(TAG, "Expected number of GPIOs: %d", 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) { 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 = forward_pin; output->reverse_pin = reverse_pin; output->direction = RELAY_CHN_DIRECTION_DEFAULT; return ESP_OK; } 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 RELAY_CHN_COUNT > 1 for (int i = 0; i < 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]; ret = relay_chn_output_ctl_init(output, forward_pin, reverse_pin); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel %d", i); } #else ret = relay_chn_output_ctl_init(&output, gpio_map[0], gpio_map[1]); 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 RELAY_CHN_COUNT > 1 for (int i = 0; i < RELAY_CHN_COUNT; i++) { relay_chn_output_ctl_deinit(&outputs[i]); } #else relay_chn_output_ctl_deinit(&output); #endif // RELAY_CHN_COUNT > 1 } #if 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 // 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; } relay_chn_direction_t relay_chn_output_get_direction(relay_chn_output_t *output) { return output->direction; }