#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#define BUTTON_GPIO GPIO_NUM_15
#define BUTTON_ISR_PRIORITY 2
#define QUEUE_LENGTH 10
QueueHandle_t queue;
enum elevator_state {
IN_FLOOR_1_DOOR_OPENED,
IN_FLOOR_1_DOOR_CLOSED,
IN_FLOOR_2_DOOR_OPENED,
IN_FLOOR_2_DOOR_CLOSED,
GOING_UP,
GOING_DOWN,
OPENING_DOOR_1,
CLOSING_DOOR_1,
OPENING_DOOR_2,
CLOSING_DOOR_2
};
enum elevator_event {
UP_PRESSED,
DOWN_PRESSED,
OPEN_PRESSED,
CLOSED_PRESSED,
ARRIVED_AT_FLOOR_1,
DOOR_1_OPENED,
DOOR_1_CLOSED,
ARRIVED_AT_FLOOR_2,
DOOR_2_OPENED,
DOOR_2_CLOSED
};
struct elevator {
enum elevator_state state;
int current_floor;
};
struct elevator e = {
.state = IN_FLOOR_1_DOOR_OPENED,
.current_floor = 1
};
static void IRAM_ATTR button_isr_handler(void* arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint32_t button_pressed = 1;
xQueueSendToBackFromISR(queue, &button_pressed, NULL);
}
void transition(struct elevator *e, enum elevator_event event) {
switch (e->state) {
case IN_FLOOR_1_DOOR_OPENED :
if(event == CLOSED_PRESSED) {
printf("Closing door...");
e->state = IN_FLOOR_1_DOOR_CLOSED;
}
else if(event == UP_PRESSED) {
printf("Closing door and going up!");
e->state = GOING_UP;
}
break;
case IN_FLOOR_1_DOOR_CLOSED:
if(event == UP_PRESSED) {
printf("Going up!");
e->state = GOING_UP;
}
else if(event == OPEN_PRESSED) {
printf("Opening door!");
e->state = IN_FLOOR_1_DOOR_OPENED;
}
break;
case IN_FLOOR_2_DOOR_OPENED:
if(event == CLOSED_PRESSED) {
printf("Closing door...");
e->state = IN_FLOOR_2_DOOR_CLOSED;
}
else if(event == DOWN_PRESSED) {
printf("Closing door and going up!");
e->state = GOING_DOWN;
}
break;
case IN_FLOOR_2_DOOR_CLOSED:
if(event == OPEN_PRESSED) {
printf("Closing door...");
e->state = IN_FLOOR_2_DOOR_OPENED;
}
else if(event == DOWN_PRESSED) {
printf("Closing door and going down!");
e->state = GOING_DOWN;
}
break;
//The following states cannot be triggered by the user due to safety concerns
case GOING_UP:
printf("Arrived to the 2nd floor!");
e->state = IN_FLOOR_2_DOOR_OPENED;
break;
case GOING_DOWN:
printf("Arrived to the 1st floor!");
e->state = IN_FLOOR_1_DOOR_OPENED;
break;
case OPENING_DOOR_1:
e->state = IN_FLOOR_1_DOOR_OPENED;
printf("Door in the 1st floor is opened!");
break;
case CLOSING_DOOR_1:
e->state = IN_FLOOR_1_DOOR_CLOSED;
printf("Door in the 1st floor is closed!");
break;
case OPENING_DOOR_2:
e->state = IN_FLOOR_2_DOOR_OPENED;
printf("Door in the 2nd floor is opened!");
break;
case CLOSING_DOOR_2:
e->state = IN_FLOOR_2_DOOR_CLOSED;
printf("Door in the 2nd floor is closed!");
break;
}
}
void elevator_toggle_task(void *p) {
uint32_t event;
while (1) {
if (xQueueReceive(queue, &event, portMAX_DELAY) == pdPASS) {
if (event == UP_PRESSED) {
transition(&e, UP_PRESSED);
}
else if (event == DOWN_PRESSED) {
transition(&e, DOWN_PRESSED);
}
else if (event == OPEN_PRESSED) {
transition(&e, OPEN_PRESSED);
}
else if (event == CLOSED_PRESSED) {
transition(&e, CLOSED_PRESSED);
}
}
}
}
void app_main() {
queue = xQueueCreate(QUEUE_LENGTH, sizeof(uint32_t));
printf("Welcome to the elevator!\n");
if (queue == NULL) {
printf("Error creating the queue.\n");
return;
}
// Initialize Button Pin
gpio_install_isr_service(0);
gpio_reset_pin(BUTTON_GPIO);
gpio_set_direction(BUTTON_GPIO, GPIO_MODE_INPUT);
gpio_set_intr_type(BUTTON_GPIO, GPIO_INTR_NEGEDGE);
gpio_isr_handler_add(BUTTON_GPIO, button_isr_handler, (void *)BUTTON_GPIO);
xTaskCreate(elevator_toggle_task, "elevator_toggle_task", 2048, NULL, 10, NULL);
}
void setup() {
app_main();
}
void loop() {
}