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
216 lines
7.4 KiB
C
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;
|
|
} |