#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_log.h"
#define ESP_INTR_FLAG_DEFAULT 0
// GPIO Pin Definitions
#define LED_2_COM_PIN GPIO_NUM_4
#define LED_3_COM_PIN GPIO_NUM_18
#define LED_4_COM_PIN GPIO_NUM_19
#define LED_1_COM_PIN GPIO_NUM_21
#define COLOR_RED_PIN GPIO_NUM_22
#define COLOR_GREEN_PIN GPIO_NUM_23
#define COLOR_BLUE_PIN GPIO_NUM_25
#define SWITCH_PIN GPIO_NUM_27
// UART Configuration
#define UART_NUM UART_NUM_0
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE * 2)
#define TD_BUF_SIZE (BUF_SIZE * 2)
// Speed Configurations (in milliseconds)
#define VEL1_DELAY 2000
#define VEL2_DELAY 1500
#define VEL3_DELAY 1000
#define VEL4_DELAY 750
#define WINDOW_TO_CHANGE_COLOR 10000
#define EVENT_CHANGE_TO_LEFT ( 1 << 0 )
#define EVENT_CHANGE_TO_RIGHT ( 1 << 1 )
#define EVENT_SWITCH_CHANGE ( 1 << 2 )
#define EVENT_ANIMATION_END ( 1 << 3 )
#define EVENT_COLOR_CHANGE ( 1 << 4 )
/* Bits used to synchronize the simultaneous start of all tasks. */
#define STAR_LEDS_TASK_BIT ( 1 << 0 )
#define UART_COLOR_TASK_BIT ( 1 << 1 )
#define MONITOR_SWITCH_TASK_BIT ( 1 << 2 )
#define ALL_TASK_SYNC_BITS ( STAR_LEDS_TASK_BIT | UART_COLOR_TASK_BIT | MONITOR_SWITCH_TASK_BIT )
// Enum for the animation states
typedef enum {
LIGHTING_UP = 1,
TURNING_OFF = 2
} animation_state_t;
// Enum for the animation steps
typedef enum {
STAR_OFF = 1,
PHASE_TWO = 2,
PHASE_THREE = 3,
PHASE_FOUR = 4,
STAR_ON = 5
} animation_step_t;
// Enum for the star colors
typedef enum {
NONE = 0,
ROJO = 1,
VERDE = 2,
AZUL = 3,
MORADO = 4,
AMARILLO = 5,
VERDE_AZULADO = 6
} animation_color_t;
// Global Variables
static EventGroupHandle_t animation_events = NULL;
static EventGroupHandle_t sync_tasks_start = NULL;
static animation_color_t animation_color = ROJO;
// Function Prototypes
void Star_LEDs_Task(void*);
void UART_Color_Task(void*);
void Monitor_Switch_Task(void*);
void setup_gpio(void);
void setup_interrupts(void);
void setup_uart(void);
animation_step_t animate_star_lighting_up(animation_step_t); // state machine
animation_step_t animate_star_turning_off(animation_step_t); // state machine
void update_leds(animation_step_t);
void print_color(animation_color_t);
// Switch Interrupt Handler
static void IRAM_ATTR switch_interrupt_handler(void* args) {
xEventGroupSetBitsFromISR(animation_events, EVENT_SWITCH_CHANGE, pdFALSE);
}
void app_main(void) {
// Initialize hardware
setup_gpio();
setup_interrupts();
setup_uart();
// Create de event group
animation_events = xEventGroupCreate();
// Create tasks
sync_tasks_start = xEventGroupCreate();
xTaskCreate(Star_LEDs_Task, "Star_LEDs_Task", 1024, NULL, 1, NULL);
xTaskCreate(UART_Color_Task, "UART_Color_Task", 1024, NULL, 1, NULL);
xTaskCreate(Monitor_Switch_Task, "Monitor_Switch_Task", 1024, NULL, 1, NULL);
}
// LED Animation Task
void Star_LEDs_Task(void *pvParameters)
{
animation_state_t state = TURNING_OFF;
animation_step_t step = STAR_OFF;
xEventGroupSync( sync_tasks_start, STAR_LEDS_TASK_BIT, ALL_TASK_SYNC_BITS, portMAX_DELAY );
while (true) {
if (state != LIGHTING_UP) {
state = LIGHTING_UP;
step = animate_star_lighting_up(step);
}
else {
state = TURNING_OFF;
step = animate_star_turning_off(step);
}
}
vTaskDelete(NULL);
}
// UART read input user color
void UART_Color_Task(void *pvParameters)
{
const char *msg_color = "\nCambiar color: ";
const char *msg_err = "\nNo se pudo cambiar el color!";
uint8_t *data = (uint8_t *) malloc(BUF_SIZE);
int len = 0;
EventBits_t event_bits;
xEventGroupSync( sync_tasks_start, UART_COLOR_TASK_BIT, ALL_TASK_SYNC_BITS, portMAX_DELAY );
while (true)
{
event_bits = xEventGroupWaitBits( animation_events,
EVENT_ANIMATION_END,
pdFALSE,
pdFALSE,
100 / portTICK_PERIOD_MS);
if (event_bits & EVENT_ANIMATION_END)
{
uart_write_bytes(UART_NUM, msg_color, strlen(msg_color));
do {
len = uart_read_bytes(UART_NUM, data, (BUF_SIZE - 1), 100 / portTICK_PERIOD_MS);
if (len > 0) {
data[len-1] = '\0';
if (strcmp("ROJO", (const char *) data) == 0)
animation_color = ROJO;
else if (strcmp("VERDE", (const char *) data) == 0)
animation_color = VERDE;
else if (strcmp("AZUL", (const char *) data) == 0)
animation_color = AZUL;
else if (strcmp("MORADO", (const char *) data) == 0)
animation_color = MORADO;
else if (strcmp("AMARILLO", (const char *) data) == 0)
animation_color = AMARILLO;
else if (strcmp("VERDE_AZULADO", (const char *) data) == 0)
animation_color = VERDE_AZULADO;
else {
uart_write_bytes(UART_NUM, msg_err, strlen(msg_err));
continue;
}
xEventGroupSetBits(animation_events, EVENT_COLOR_CHANGE);
}
} while (xEventGroupGetBits(animation_events) & EVENT_ANIMATION_END);
print_color(animation_color);
}
}
free(data);
vTaskDelete(NULL);
}
void Monitor_Switch_Task(void *pvParmeters)
{
const TickType_t xBounceTime = 50 / portTICK_PERIOD_MS;
xEventGroupSync( sync_tasks_start, MONITOR_SWITCH_TASK_BIT, ALL_TASK_SYNC_BITS, portMAX_DELAY );
while (true)
{
xEventGroupClearBits(animation_events, EVENT_SWITCH_CHANGE);
xEventGroupWaitBits(animation_events,
EVENT_SWITCH_CHANGE,
pdFALSE,
pdFALSE,
portMAX_DELAY);
vTaskDelay(xBounceTime);
if (gpio_get_level(SWITCH_PIN)) {
xEventGroupSetBits(animation_events, EVENT_CHANGE_TO_LEFT);
//uart_write_bytes(UART_NUM, (const char *) "LEFT", 4);
}
else {
xEventGroupSetBits(animation_events, EVENT_CHANGE_TO_RIGHT);
//uart_write_bytes(UART_NUM, (const char *) "RIGHT", 5);
}
}
vTaskDelete(NULL);
}
animation_step_t animate_star_lighting_up(animation_step_t step)
{
TickType_t xStepDelay = VEL2_DELAY / portTICK_PERIOD_MS;
EventBits_t event_bits;
while (step != STAR_ON)
{
switch (step) {
case STAR_OFF:
update_leds(step = PHASE_TWO);
break;
case PHASE_TWO:
update_leds(step = PHASE_THREE);
break;
case PHASE_THREE:
update_leds(step = PHASE_FOUR);
break;
case PHASE_FOUR:
xStepDelay = portMAX_DELAY;
update_leds(step = STAR_ON);
break;
default:
}
xEventGroupClearBits(animation_events, EVENT_CHANGE_TO_RIGHT);
event_bits = xEventGroupWaitBits( animation_events,
EVENT_CHANGE_TO_RIGHT,
pdFALSE,
pdFALSE,
xStepDelay);
if (event_bits & EVENT_CHANGE_TO_RIGHT)
return step;
}
return step;
}
animation_step_t animate_star_turning_off(animation_step_t step)
{
TickType_t xStepDelay = VEL2_DELAY / portTICK_PERIOD_MS;
EventBits_t event_bits;
EventBits_t bits_to_wait = EVENT_CHANGE_TO_LEFT;
while (step != STAR_OFF)
{
switch (step) {
case STAR_ON:
update_leds(step = PHASE_FOUR);
break;
case PHASE_FOUR:
update_leds(step = PHASE_THREE);
break;
case PHASE_THREE:
update_leds(step = PHASE_TWO);
break;
case PHASE_TWO:
update_leds(step = STAR_OFF);
xStepDelay = WINDOW_TO_CHANGE_COLOR / portTICK_PERIOD_MS;
bits_to_wait = EVENT_COLOR_CHANGE;
xEventGroupSetBits(animation_events, EVENT_ANIMATION_END);
break;
default:
break;
}
xEventGroupClearBits(animation_events, EVENT_CHANGE_TO_LEFT);
event_bits = xEventGroupWaitBits( animation_events,
bits_to_wait,
pdTRUE, // clear on exit
pdFALSE,
xStepDelay);
if (event_bits & EVENT_ANIMATION_END)
xEventGroupClearBits(animation_events, EVENT_ANIMATION_END);
if (event_bits & EVENT_CHANGE_TO_LEFT)
return step;
}
return step;
}
void update_leds(animation_step_t step)
{
static animation_color_t last_color = NONE;
if (last_color != animation_color) {
switch (animation_color) {
case ROJO:
gpio_set_level(COLOR_RED_PIN, 1);
gpio_set_level(COLOR_GREEN_PIN, 0);
gpio_set_level(COLOR_BLUE_PIN, 0);
break;
case VERDE:
gpio_set_level(COLOR_RED_PIN, 0);
gpio_set_level(COLOR_GREEN_PIN, 1);
gpio_set_level(COLOR_BLUE_PIN, 0);
break;
case AZUL:
gpio_set_level(COLOR_RED_PIN, 0);
gpio_set_level(COLOR_GREEN_PIN, 0);
gpio_set_level(COLOR_BLUE_PIN, 1);
break;
case MORADO:
gpio_set_level(COLOR_RED_PIN, 1);
gpio_set_level(COLOR_GREEN_PIN, 0);
gpio_set_level(COLOR_BLUE_PIN, 1);
break;
case AMARILLO:
gpio_set_level(COLOR_RED_PIN, 1);
gpio_set_level(COLOR_GREEN_PIN, 1);
gpio_set_level(COLOR_BLUE_PIN, 0);
break;
case VERDE_AZULADO:
gpio_set_level(COLOR_RED_PIN, 0);
gpio_set_level(COLOR_GREEN_PIN, 1);
gpio_set_level(COLOR_BLUE_PIN, 1);
break;
case NONE:
break;
default:
break;
}
last_color = animation_color;
}
switch (step) {
case STAR_OFF:
gpio_set_level(LED_1_COM_PIN, 1);
gpio_set_level(LED_2_COM_PIN, 1);
gpio_set_level(LED_3_COM_PIN, 1);
gpio_set_level(LED_4_COM_PIN, 1);
break;
case PHASE_TWO:
gpio_set_level(LED_1_COM_PIN, 0);
gpio_set_level(LED_2_COM_PIN, 1);
gpio_set_level(LED_3_COM_PIN, 1);
gpio_set_level(LED_4_COM_PIN, 1);
break;
case PHASE_THREE:
gpio_set_level(LED_1_COM_PIN, 0);
gpio_set_level(LED_2_COM_PIN, 0);
gpio_set_level(LED_3_COM_PIN, 1);
gpio_set_level(LED_4_COM_PIN, 1);
break;
case PHASE_FOUR:
gpio_set_level(LED_1_COM_PIN, 0);
gpio_set_level(LED_2_COM_PIN, 0);
gpio_set_level(LED_3_COM_PIN, 0);
gpio_set_level(LED_4_COM_PIN, 1);
break;
case STAR_ON:
gpio_set_level(LED_1_COM_PIN, 0);
gpio_set_level(LED_2_COM_PIN, 0);
gpio_set_level(LED_3_COM_PIN, 0);
gpio_set_level(LED_4_COM_PIN, 0);
break;
default:
break;
}
}
void print_color(animation_color_t color)
{
uart_write_bytes(UART_NUM, (const char *) "\n", 1);
switch (color) {
case ROJO: uart_write_bytes(UART_NUM, (const char *) "Color: ROJO", 11); break;
case VERDE: uart_write_bytes(UART_NUM, (const char *) "Color: VERDE", 12); break;
case AZUL: uart_write_bytes(UART_NUM, (const char *) "Color: AZUL", 11); break;
case MORADO: uart_write_bytes(UART_NUM, (const char *) "Color: MORADO", 13); break;
case AMARILLO: uart_write_bytes(UART_NUM, (const char *) "Color: AMARILLO", 15); break;
case VERDE_AZULADO: uart_write_bytes(UART_NUM, (const char *) "Color: VERDE_AZULADO", 20); break;
case NONE: break;
}
}
// Configure GPIO Pins
void setup_gpio(void) {
gpio_config_t io_conf;
// LED Pins Configuration
io_conf.pin_bit_mask =
(1ULL << LED_1_COM_PIN) | (1ULL << LED_2_COM_PIN) | (1ULL << LED_3_COM_PIN) |
(1ULL << LED_4_COM_PIN) | (1ULL << COLOR_RED_PIN) | (1ULL << COLOR_GREEN_PIN) |
(1ULL << COLOR_BLUE_PIN);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.intr_type = GPIO_INTR_DISABLE;
gpio_config(&io_conf);
// Switch Pin Configuration
io_conf.pin_bit_mask = (1ULL << SWITCH_PIN);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.intr_type = GPIO_INTR_ANYEDGE;
gpio_config(&io_conf);
}
// Configure GPIO Interrupts
void setup_interrupts(void) {
// Instalar servicio de interrupciones y asociar handlers
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
gpio_isr_handler_add(SWITCH_PIN, switch_interrupt_handler, NULL);
}
// Configure UART
void setup_uart(void) {
const uint8_t uart_num = UART_NUM;
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
// Configure UART parameters
uart_param_config(uart_num, &uart_config);
// Set UART pins
uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
// Install UART drivers
uart_driver_install(uart_num, RD_BUF_SIZE, TD_BUF_SIZE, 0, NULL, 0);
}