Files
relay_chn/src/relay_chn_output.c
ismail ea5d2d90c5 Add single channel mode feature.
The addition of a single-channel mode implied further modularisation of the component. This commit has broken the component down into the following modules to avoid a huge single source file and to make unit testing easier.

The modules:

- Separation of public and private code
- *types and *defs
- public relay_chn API
- *adapter
- *output
- *run_info
- *core
- *ctl (control)
- *tilt
2025-08-13 17:53:27 +03:00

168 lines
5.4 KiB
C

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