|
|
|
@@ -0,0 +1,290 @@
|
|
|
|
|
/*
|
|
|
|
|
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
|
#include "freertos/task.h"
|
|
|
|
|
#include "esp_err.h"
|
|
|
|
|
#include "esp_log.h"
|
|
|
|
|
#include "esp_check.h"
|
|
|
|
|
#include "driver/gpio.h"
|
|
|
|
|
#include "nvs.h"
|
|
|
|
|
#include "nvs_flash.h"
|
|
|
|
|
#include "button_gpio.h"
|
|
|
|
|
#include "iot_button.h"
|
|
|
|
|
#include "led_indicator.h"
|
|
|
|
|
#include "relay_chn.h"
|
|
|
|
|
|
|
|
|
|
static const char *TAG = "RELAY_CHN_SINGLE_EXAMPLE";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief LED indicator modes for different states.
|
|
|
|
|
*/
|
|
|
|
|
typedef enum {
|
|
|
|
|
INDICATOR_MODE_OK, /*!< OK/Success indication */
|
|
|
|
|
INDICATOR_MODE_FAIL, /*!< Fail/Error indication */
|
|
|
|
|
INDICATOR_MODE_TILTING, /*!< Tilting operation in progress */
|
|
|
|
|
INDICATOR_MODE_RUNNING, /*!< Full run operation in progress */
|
|
|
|
|
INDICATOR_MODE_MAX /*!< Maximum number of indicator modes */
|
|
|
|
|
} indicator_mode_t;
|
|
|
|
|
|
|
|
|
|
/** @brief Blink pattern for OK/Success indication. */
|
|
|
|
|
static const blink_step_t indc_mode_ok[] = {
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step1: turn on LED 100 ms
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step2: turn off LED 50 ms
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step3: turn on LED 100 ms
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step4: turn off LED 50 ms
|
|
|
|
|
{LED_BLINK_STOP, 0, 0}, // step5: stop blink (off)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** @brief Blink pattern for Fail/Error indication. */
|
|
|
|
|
static const blink_step_t indc_mode_fail[] = {
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_ON, 1000}, // step1: turn on LED 1000 ms
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_OFF, 500}, // step2: turn off LED 500 ms
|
|
|
|
|
{LED_BLINK_STOP, 0, 0}, // step4: stop blink (off)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** @brief Blink pattern for full run operation. */
|
|
|
|
|
static const blink_step_t indc_mode_running[] = {
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_ON, 300}, // step1: turn on LED 300 ms
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_OFF, 100}, // step2: turn off LED 100 ms
|
|
|
|
|
{LED_BLINK_LOOP, 0, 0}, // step3: loop from step1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** @brief Blink pattern for tilting operation. */
|
|
|
|
|
static const blink_step_t indc_mode_tilting[] = {
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_ON, 100}, // step1: turn on LED 100 ms
|
|
|
|
|
{LED_BLINK_HOLD, LED_STATE_OFF, 50}, // step2: turn off LED 50 ms
|
|
|
|
|
{LED_BLINK_LOOP, 0, 0}, // step3: loop from step1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** @brief Array of LED indicator blink patterns. */
|
|
|
|
|
blink_step_t const *led_indicator_modes[] = {
|
|
|
|
|
[INDICATOR_MODE_OK] = indc_mode_ok,
|
|
|
|
|
[INDICATOR_MODE_FAIL] = indc_mode_fail,
|
|
|
|
|
[INDICATOR_MODE_RUNNING] = indc_mode_running,
|
|
|
|
|
[INDICATOR_MODE_TILTING] = indc_mode_tilting,
|
|
|
|
|
[INDICATOR_MODE_MAX] = NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** @brief Handle for the LED indicator. */
|
|
|
|
|
static led_indicator_handle_t indicator = NULL;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Initializes the buttons for user interaction.
|
|
|
|
|
*
|
|
|
|
|
* This function configures and creates GPIO buttons for UP, DOWN, and STOP
|
|
|
|
|
* operations. It also registers callbacks for single-click and long-press
|
|
|
|
|
* events to control the relay channel.
|
|
|
|
|
*
|
|
|
|
|
* @return esp_err_t
|
|
|
|
|
* - ESP_OK: Success
|
|
|
|
|
* - Others: Fail
|
|
|
|
|
*/
|
|
|
|
|
static esp_err_t init_buttons(void);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Initializes the LED indicator.
|
|
|
|
|
*
|
|
|
|
|
* This function configures and creates the LED indicator used to provide
|
|
|
|
|
* visual feedback on the relay channel's status.
|
|
|
|
|
*
|
|
|
|
|
* @return esp_err_t
|
|
|
|
|
* - ESP_OK: Success
|
|
|
|
|
* - ESP_FAIL: Fail
|
|
|
|
|
*/
|
|
|
|
|
static esp_err_t init_led_indicator(void);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Event listener for relay channel state changes to control the LED indicator.
|
|
|
|
|
*/
|
|
|
|
|
static void example_event_listener_1(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Event listener for relay channel state changes to log the state transition.
|
|
|
|
|
*/
|
|
|
|
|
static void example_event_listener_2(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state);
|
|
|
|
|
|
|
|
|
|
void app_main(void)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t gpio_map[] = { 4, 5 };
|
|
|
|
|
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Initializing relay channel");
|
|
|
|
|
ESP_ERROR_CHECK(relay_chn_create(gpio_map, gpio_count));
|
|
|
|
|
ESP_ERROR_CHECK(relay_chn_register_listener(example_event_listener_1));
|
|
|
|
|
ESP_ERROR_CHECK(relay_chn_register_listener(example_event_listener_2));
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Initializing buttons");
|
|
|
|
|
ESP_ERROR_CHECK(init_buttons());
|
|
|
|
|
ESP_LOGI(TAG, "Initializing LED indicator");
|
|
|
|
|
ESP_ERROR_CHECK(init_led_indicator());
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Relay Channel Single Example is ready to operate");
|
|
|
|
|
|
|
|
|
|
// Indicate init was successful
|
|
|
|
|
led_indicator_start(indicator, INDICATOR_MODE_OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_click_up(void *arg, void *data)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_run_forward();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_click_down(void *arg, void *data)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_run_reverse();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_click_stop(void *arg, void *data)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_click_flip(void *arg, void *data)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_flip_direction();
|
|
|
|
|
led_indicator_start(indicator, INDICATOR_MODE_OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_click_tilt_up(void *arg, void *data)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_tilt_forward();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_click_tilt_down(void *arg, void *data)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_tilt_reverse();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_release_tilt(void *arg, void *data)
|
|
|
|
|
{
|
|
|
|
|
relay_chn_tilt_stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void example_event_listener_1(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state)
|
|
|
|
|
{
|
|
|
|
|
ESP_LOGI(TAG, "example_event_listener_1: Defining new indicator mode for #%d and state change from %d to %d", ch, old_state, new_state);
|
|
|
|
|
switch (new_state) {
|
|
|
|
|
case RELAY_CHN_STATE_FORWARD:
|
|
|
|
|
case RELAY_CHN_STATE_REVERSE:
|
|
|
|
|
led_indicator_start(indicator, INDICATOR_MODE_RUNNING);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RELAY_CHN_STATE_STOPPED:
|
|
|
|
|
case RELAY_CHN_STATE_IDLE:
|
|
|
|
|
if (old_state == RELAY_CHN_STATE_FORWARD || old_state == RELAY_CHN_STATE_REVERSE) {
|
|
|
|
|
led_indicator_stop(indicator, INDICATOR_MODE_RUNNING);
|
|
|
|
|
// Make sure the indicator turned off
|
|
|
|
|
led_indicator_set_on_off(indicator, false);
|
|
|
|
|
}
|
|
|
|
|
else if (old_state == RELAY_CHN_STATE_TILT_FORWARD || old_state == RELAY_CHN_STATE_TILT_REVERSE) {
|
|
|
|
|
led_indicator_stop(indicator, INDICATOR_MODE_TILTING);
|
|
|
|
|
// Make sure the indicator turned off
|
|
|
|
|
led_indicator_set_on_off(indicator, false);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RELAY_CHN_STATE_TILT_FORWARD:
|
|
|
|
|
case RELAY_CHN_STATE_TILT_REVERSE:
|
|
|
|
|
led_indicator_start(indicator, INDICATOR_MODE_TILTING);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: // No-op
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void example_event_listener_2(uint8_t ch, relay_chn_state_t old_state, relay_chn_state_t new_state)
|
|
|
|
|
{
|
|
|
|
|
ESP_LOGI(TAG, "example_event_listener_2: State change for #%d, from %s to %s",
|
|
|
|
|
ch, relay_chn_state_to_str(old_state), relay_chn_state_to_str(new_state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t init_buttons()
|
|
|
|
|
{
|
|
|
|
|
esp_err_t ret;
|
|
|
|
|
button_config_t btn_cfg = {0};
|
|
|
|
|
|
|
|
|
|
uint8_t active_level = CONFIG_EXAMPLE_RLCHN_BTN_ACTIVE_LEVEL_LOW ? 0 : 1;
|
|
|
|
|
|
|
|
|
|
button_gpio_config_t btn_gpio_ccfg = {
|
|
|
|
|
.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_UP_IO_NUM,
|
|
|
|
|
.active_level = active_level
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Initializing buttons with active level: %u", active_level);
|
|
|
|
|
button_handle_t btn_up = NULL, btn_down = NULL, btn_stop = NULL;
|
|
|
|
|
// --- Create buttons ---
|
|
|
|
|
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_up);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create UP button");
|
|
|
|
|
ESP_RETURN_ON_FALSE(btn_up != NULL, ret, TAG, "Failed to create UP button");
|
|
|
|
|
|
|
|
|
|
btn_gpio_ccfg.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_DOWN_IO_NUM;
|
|
|
|
|
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_down);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create DOWN button");
|
|
|
|
|
ESP_RETURN_ON_FALSE(btn_down != NULL, ret, TAG, "Failed to create DOWN button");
|
|
|
|
|
|
|
|
|
|
btn_gpio_ccfg.gpio_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_BTN_STOP_IO_NUM;
|
|
|
|
|
ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_ccfg, &btn_stop);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create STOP button");
|
|
|
|
|
ESP_RETURN_ON_FALSE(btn_stop != NULL, ret, TAG, "Failed to create STOP button");
|
|
|
|
|
// --- Create buttons ---
|
|
|
|
|
|
|
|
|
|
// --- Register button callbacks ---
|
|
|
|
|
ESP_LOGI(TAG, "Setting up button callbacks. Configured long press time: %d ms", CONFIG_EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS);
|
|
|
|
|
button_event_args_t btn_event_args = {
|
|
|
|
|
.long_press.press_time = CONFIG_EXAMPLE_RLCHN_BTN_LONG_PRESS_TIME_MS
|
|
|
|
|
};
|
|
|
|
|
// --- Register UP and TILT_UP operations on UP button ---
|
|
|
|
|
ret = iot_button_register_cb(btn_up, BUTTON_SINGLE_CLICK, NULL, on_click_up, NULL);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register UP button click callback");
|
|
|
|
|
ret = iot_button_register_cb(btn_up, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_tilt_up, NULL);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_UP button press callback");
|
|
|
|
|
ret = iot_button_register_cb(btn_up, BUTTON_LONG_PRESS_UP, NULL, on_release_tilt, NULL);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_UP button release callback");
|
|
|
|
|
|
|
|
|
|
// --- Register DOWN and TILT_DOWN operations on DOWN button ---
|
|
|
|
|
ret = iot_button_register_cb(btn_down, BUTTON_SINGLE_CLICK, NULL, on_click_down, NULL);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register DOWN button click callback");
|
|
|
|
|
ret = iot_button_register_cb(btn_down, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_tilt_down, NULL);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_DOWN button press callback");
|
|
|
|
|
ret = iot_button_register_cb(btn_down, BUTTON_LONG_PRESS_UP, NULL, on_release_tilt, NULL);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register TILT_DOWN button release callback");
|
|
|
|
|
|
|
|
|
|
// --- Register STOP and FLIP operations on STOP ---
|
|
|
|
|
ret = iot_button_register_cb(btn_stop, BUTTON_SINGLE_CLICK, NULL, on_click_stop, NULL);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register STOP button click callback");
|
|
|
|
|
ret = iot_button_register_cb(btn_stop, BUTTON_LONG_PRESS_START, &btn_event_args, on_click_flip, NULL);
|
|
|
|
|
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to register FLIP button press callback");
|
|
|
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t init_led_indicator()
|
|
|
|
|
{
|
|
|
|
|
const gpio_num_t indicator_io_num = (gpio_num_t) CONFIG_EXAMPLE_RLCHN_LED_INDICATOR_IO_NUM;
|
|
|
|
|
gpio_reset_pin(indicator_io_num); // Clear the output buffers
|
|
|
|
|
|
|
|
|
|
led_indicator_gpio_config_t led_indicator_gpio_cfg = {
|
|
|
|
|
.gpio_num = indicator_io_num,
|
|
|
|
|
.is_active_level_high = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
led_indicator_config_t led_indicator_cfg = {
|
|
|
|
|
.mode = LED_GPIO_MODE,
|
|
|
|
|
.led_indicator_gpio_config = &led_indicator_gpio_cfg,
|
|
|
|
|
.blink_lists = led_indicator_modes,
|
|
|
|
|
.blink_list_num = INDICATOR_MODE_MAX
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
indicator = led_indicator_create(&led_indicator_cfg);
|
|
|
|
|
if (!indicator) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to create LED indicator");
|
|
|
|
|
return ESP_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|