Files
relay_chn/src/relay_chn_output.c
ismail 3831384169 Implement specific *all functions
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
2025-08-26 08:42:49 +03:00

216 lines
7.4 KiB
C

/*
* 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;
}