refactor: State Machine Refinement 1

This commit is contained in:
Frederik Beimgraben 2025-07-03 04:13:27 +02:00
parent aac5c5a44c
commit dc6198f587
2 changed files with 545 additions and 305 deletions

View File

@ -1,40 +1,90 @@
/* File: state_machine.c */
/**
* @file state_machine.c
* @brief Statemachine for the Core-Program
* @brief State machine implementation for the beverage dispenser core program.
*
* ...
* Tracks pertype stock levels, enforces stock limits on orders,
* and provides an * menu in IDLE to edit stock via the keypad.
*
* @authors
* Frederik Beimgraben
* Minh Dan Cam
* Luis Meyer
* @date 2025-07-02
* Frederik Beimgraben
* Minh Dan Cam
* Luis Meyer
* @date 2025-07-03
*/
#include <stdbool.h>
#include <msp430.h>
#include <driverlib.h>
#include <stdint.h>
#include <stdio.h>
#include <ctype.h>
#include <msp430.h>
#include "driverlib.h"
#include "keypad.h"
#include "lcd.h"
#include "morse.h"
#include "door_sensor.h"
#include "state_machine.h"
#include "timer.h"
volatile char keypad_last_key = '\0';
volatile bool keypad_flag_chg = false;
/* ——— Configurable Defaults ———————————————————————————————— */
#define INITIAL_STOCK_DEFAULT 20U /**< Default stock for each beverage */
#define MAX_STOCK 255U /**< Maximum stock representable */
volatile bool allow_open = false;
/* ——— Internal State Variables —————————————————————————————— */
/* Function Declarations */
void handle_interrupt(void);
void buzz_invalid_input(void);
void sound_alarm(void);
void reset_alarm(void);
void transition(State_t state);
/** Last key pressed on the keypad. */
volatile char keypad_last_key = '\0';
/** Flag set when a new key is ready to handle. */
volatile bool keypad_flag_chg = false;
/** True if the door is currently open. */
volatile bool door_open = false;
/** True if the state has just changed and UI needs redrawing. */
volatile bool state_chg = false;
/** Current UI state. */
volatile State_t current_state = STATE_IDLE;
/** Beverage currently selected either for ordering or editing stock. */
volatile SelectedBev_t selected_bev = BEV_A;
/** Order counts (persession) for beverages AD. */
volatile uint8_t count_a = 0;
volatile uint8_t count_b = 0;
volatile uint8_t count_c = 0;
volatile uint8_t count_d = 0;
/** Stock levels for beverages AD. */
volatile uint8_t stock_a = INITIAL_STOCK_DEFAULT;
volatile uint8_t stock_b = INITIAL_STOCK_DEFAULT;
volatile uint8_t stock_c = INITIAL_STOCK_DEFAULT;
volatile uint8_t stock_d = INITIAL_STOCK_DEFAULT;
/** Temporary buffer for building a new stock value. */
volatile uint8_t new_stock_count = 0;
/** LCD line buffers. */
char buffer_ab[17];
char buffer_cd[17];
/* ——— Function Prototypes ———————————————————————————————— */
/* Keypad input handlers */
void handle_input_idle(unsigned char key);
void handle_input_sel_count(unsigned char key);
void handle_input_confirmed(unsigned char key);
void handle_input_edit_stock_select(unsigned char key);
void handle_input_edit_stock_set(unsigned char key);
/* Utility */
bool any_selected(void);
void transition(State_t next);
/* Orderentry */
void update_amount(uint8_t digit);
void reset_amount(void);
void reset_amounts(void);
/* Stockediting */
void update_new_stock(uint8_t digit);
void reset_new_stock(void);
/* UI drawing */
void ui_draw_idle(void);
void ui_draw_sel_count(void);
void ui_draw_confirmed(void);
@ -42,144 +92,59 @@ void ui_draw_error(void);
void ui_draw_open(void);
void ui_draw_none_selected(void);
void ui_draw_reset(void);
void reset_amount();
void reset_amounts();
bool any_selected(void);
void ui_draw_stock_select(void);
void ui_draw_stock_set(void);
void ui_draw_stock_confirmed(void);
volatile State_t current_state = STATE_IDLE;
volatile bool state_chg = false;
/* Error/signal feedback */
void buzz_invalid_input(void);
volatile uint8_t count_a = 0;
volatile uint8_t count_b = 0;
volatile uint8_t count_c = 0;
volatile uint8_t count_d = 0;
volatile SelectedBev_t selected_bev = BEV_A;
/* Door callbacks */
static void door_opened_handler(void);
static void door_closed_handler(void);
volatile bool door_open = false;
/* Keypad Callback */
static void keypad_handler(char key);
void handle_input_idle(unsigned char key) {
switch (key) {
case 'A':
selected_bev = BEV_A;
transition(STATE_SEL_COUNT);
break;
case 'B':
selected_bev = BEV_B;
transition(STATE_SEL_COUNT);
break;
case 'C':
selected_bev = BEV_C;
transition(STATE_SEL_COUNT);
break;
case 'D':
selected_bev = BEV_D;
transition(STATE_SEL_COUNT);
break;
default:
buzz_invalid_input();
}
/* General interrupt dispatcher */
void handle_general_interrupt(void);
/* ——— Implementation ————————————————————————————————————— */
/**
* @brief Initialize peripherals and draw the initial UI.
*/
void sm_init(void)
{
/* register keypad + door callbacks */
keypad_init(/* callback = */ keypad_handler);
door_init(door_opened_handler, door_closed_handler);
/* start in IDLE with default stocks */
reset_amounts();
reset_new_stock();
stock_a = stock_b = stock_c = stock_d = INITIAL_STOCK_DEFAULT;
ui_draw_idle();
}
void handle_input_confirmed(unsigned char key) {
switch (key) {
case 'A':
selected_bev = BEV_A;
transition(STATE_SEL_COUNT);
break;
case 'B':
selected_bev = BEV_B;
transition(STATE_SEL_COUNT);
break;
case 'C':
selected_bev = BEV_C;
transition(STATE_SEL_COUNT);
break;
case 'D':
selected_bev = BEV_D;
transition(STATE_SEL_COUNT);
break;
case '*':
reset_amounts();
transition(STATE_RESET);
break;
default:
buzz_invalid_input();
}
}
void update_amount(uint8_t new_digit) {
switch (selected_bev) {
case BEV_A:
if (count_a * 10 + new_digit < 255)
count_a = count_a * 10 + new_digit;
break;
case BEV_B:
if (count_b * 10 + new_digit < 255)
count_b = count_b * 10 + new_digit;
break;
case BEV_C:
if (count_c * 10 + new_digit < 255)
count_c = count_c * 10 + new_digit;
break;
case BEV_D:
if (count_d * 10 + new_digit < 255)
count_d = count_d * 10 + new_digit;
break;
}
}
void reset_amount() {
switch (selected_bev) {
case BEV_A:
count_a = 0;
break;
case BEV_B:
count_b = 0;
break;
case BEV_C:
count_c = 0;
break;
case BEV_D:
count_d = 0;
break;
}
}
void reset_amounts() {
count_a = 0;
count_b = 0;
count_c = 0;
count_d = 0;
}
void handle_input_sel_count(unsigned char key) {
// Check if input is number
if (key >= '0' && key <= '9') {
update_amount((uint8_t) key - '0');
transition(current_state);
} else if (key == '#') {
if (door_open) {
transition(STATE_OPEN);
} else {
if (!any_selected()) {
transition(STATE_NONE_SELECTED);
} else {
transition(STATE_CONFIRMED);
}
}
} else if (key == '*') {
reset_amount();
transition(current_state);
} else {
handle_input_idle(key);
/**
* @brief Main event loop: lowpower + interrupts.
*/
void sm_loop(void)
{
for (;;) {
__bis_SR_register(LPM0_bits | GIE); /* sleep until interrupt */
__no_operation();
handle_general_interrupt();
}
}
/**
* @brief Keypad callback invoked on key press interrupt.
* @param key ASCII character of pressed key
* @brief Keypad interrupt handler.
* @param key ASCII code of the pressed key.
*
* Stores key, sets ready flag, and blinks Morse code on LED.
* Routes key to the correct statespecific handler.
*/
static void keypad_handler(char key)
{
@ -194,183 +159,443 @@ static void keypad_handler(char key)
handle_input_sel_count(key);
break;
case STATE_CONFIRMED:
handle_input_confirmed(key);
break;
case STATE_OPEN:
handle_input_confirmed(key);
break;
case STATE_EDIT_STOCK_SELECT:
handle_input_edit_stock_select(key);
break;
case STATE_EDIT_STOCK_SET:
handle_input_edit_stock_set(key);
break;
case STATE_EDIT_STOCK_CONFIRMED:
/* any key closes confirmation */
transition(STATE_IDLE);
break;
default:
buzz_invalid_input();
break;
}
}
bool any_selected(void) {
return count_a + count_b + count_c + count_d > 0;
/**
* @brief Handle keypress when in STATE_IDLE.
* @param key ASCII of pressed key.
*
* AD start ordering that beverage.
* * enters stockediting menu.
*/
void handle_input_idle(unsigned char key)
{
switch (key) {
case 'A': case 'B': case 'C': case 'D':
selected_bev = (SelectedBev_t)(key - 'A');
transition(STATE_SEL_COUNT);
break;
case '*':
reset_new_stock();
transition(STATE_EDIT_STOCK_SELECT);
break;
default:
buzz_invalid_input();
break;
}
}
static void door_opened_handler(void) {
if (current_state != STATE_CONFIRMED && current_state != STATE_UNLOCKED) {
/**
* @brief Handle keypress when selecting order quantity.
* @param key ASCII of pressed key.
*
* Digits build count (up to stock), # confirms, * clears,
* anything else falls back to idlehandler.
*/
void handle_input_sel_count(unsigned char key)
{
if (key >= '0' && key <= '9') {
update_amount(key - '0');
transition(STATE_SEL_COUNT);
}
else if (key == '#') {
if (door_open) {
transition(STATE_OPEN);
} else if (!any_selected()) {
transition(STATE_NONE_SELECTED);
} else {
/* deduct stock before confirming */
switch (selected_bev) {
case BEV_A: stock_a -= count_a; break;
case BEV_B: stock_b -= count_b; break;
case BEV_C: stock_c -= count_c; break;
case BEV_D: stock_d -= count_d; break;
}
transition(STATE_CONFIRMED);
}
}
else if (key == '*') {
reset_amount();
transition(STATE_SEL_COUNT);
}
else {
handle_input_idle(key);
}
}
/**
* @brief Handle keypress in STATE_CONFIRMED (and STATE_OPEN).
* @param key ASCII of pressed key.
*
* AD reselect beverage for new order.
* * resets all order counts.
*/
void handle_input_confirmed(unsigned char key)
{
switch (key) {
case 'A': case 'B': case 'C': case 'D':
selected_bev = (SelectedBev_t)(key - 'A');
transition(STATE_SEL_COUNT);
break;
case '*':
reset_amounts();
transition(STATE_RESET);
break;
default:
buzz_invalid_input();
break;
}
}
/**
* @brief Handle keypress in STATE_EDIT_STOCK_SELECT.
* @param key ASCII pressed.
*
* AD pick which stock to edit, * cancels to IDLE.
*/
void handle_input_edit_stock_select(unsigned char key)
{
switch (key) {
case 'A': case 'B': case 'C': case 'D':
selected_bev = (SelectedBev_t)(key - 'A');
reset_new_stock();
transition(STATE_EDIT_STOCK_SET);
break;
case '*':
transition(STATE_IDLE);
break;
default:
buzz_invalid_input();
break;
}
}
/**
* @brief Handle keypress in STATE_EDIT_STOCK_SET.
* @param key ASCII pressed.
*
* Digits build new stock, # confirms update, * cancels.
*/
void handle_input_edit_stock_set(unsigned char key)
{
if (key >= '0' && key <= '9') {
update_new_stock(key - '0');
transition(STATE_EDIT_STOCK_SET);
}
else if (key == '#') {
/* apply new stock */
switch (selected_bev) {
case BEV_A: stock_a = new_stock_count; break;
case BEV_B: stock_b = new_stock_count; break;
case BEV_C: stock_c = new_stock_count; break;
case BEV_D: stock_d = new_stock_count; break;
}
transition(STATE_EDIT_STOCK_CONFIRMED);
}
else if (key == '*') {
reset_new_stock();
transition(STATE_EDIT_STOCK_SELECT);
}
else {
buzz_invalid_input();
}
}
/**
* @brief Update the order count for selected beverage.
* @param digit 09 to append.
*
* Ensures you never exceed the stock level.
*/
void update_amount(uint8_t digit)
{
uint16_t tentative;
switch (selected_bev) {
case BEV_A:
tentative = count_a * 10 + digit;
if (tentative <= stock_a) count_a = (uint8_t)tentative;
else buzz_invalid_input();
break;
case BEV_B:
tentative = count_b * 10 + digit;
if (tentative <= stock_b) count_b = (uint8_t)tentative;
else buzz_invalid_input();
break;
case BEV_C:
tentative = count_c * 10 + digit;
if (tentative <= stock_c) count_c = (uint8_t)tentative;
else buzz_invalid_input();
break;
case BEV_D:
tentative = count_d * 10 + digit;
if (tentative <= stock_d) count_d = (uint8_t)tentative;
else buzz_invalid_input();
break;
}
}
/**
* @brief Reset the order count for the currently selected beverage.
*/
void reset_amount(void)
{
switch (selected_bev) {
case BEV_A: count_a = 0; break;
case BEV_B: count_b = 0; break;
case BEV_C: count_c = 0; break;
case BEV_D: count_d = 0; break;
}
}
/**
* @brief Reset all order counts to zero.
*/
void reset_amounts(void)
{
count_a = count_b = count_c = count_d = 0;
}
/**
* @brief Build up new stock value from digit.
* @param digit 09 to append.
*
* Caps at MAX_STOCK.
*/
void update_new_stock(uint8_t digit)
{
uint16_t tentative = new_stock_count * 10 + digit;
if (tentative <= MAX_STOCK) {
new_stock_count = (uint8_t)tentative;
} else {
buzz_invalid_input();
}
}
/**
* @brief Reset the new stock entry buffer to zero.
*/
void reset_new_stock(void)
{
new_stock_count = 0;
}
/**
* @brief True if any order count > 0.
* @return bool
*/
bool any_selected(void)
{
return (count_a + count_b + count_c + count_d) > 0;
}
/**
* @brief Perform the visual update when state changes.
*/
void handle_general_interrupt(void)
{
if (!state_chg) return;
switch (current_state) {
case STATE_IDLE: ui_draw_idle(); break;
case STATE_SEL_COUNT: ui_draw_sel_count(); break;
case STATE_CONFIRMED: ui_draw_confirmed(); break;
case STATE_UNAUTHORIZED: ui_draw_error(); break;
case STATE_OPEN: ui_draw_open(); break;
case STATE_NONE_SELECTED: ui_draw_none_selected(); break;
case STATE_RESET: ui_draw_reset(); break;
case STATE_EDIT_STOCK_SELECT: ui_draw_stock_select(); break;
case STATE_EDIT_STOCK_SET: ui_draw_stock_set(); break;
case STATE_EDIT_STOCK_CONFIRMED: ui_draw_stock_confirmed(); break;
default: buzz_invalid_input(); break;
}
state_chg = false;
}
/**
* @brief Transition to a new state (requests a redraw).
* @param next Next state.
*/
void transition(State_t next)
{
current_state = next;
state_chg = true;
}
/* ——— Door Callbacks —————————————————————————————————————— */
/**
* @brief Called when door opens.
*/
static void door_opened_handler(void)
{
if (current_state != STATE_CONFIRMED) {
transition(STATE_UNAUTHORIZED);
} else {
transition(STATE_OPEN);
}
door_open = true;
}
static void door_closed_handler(void) {
/**
* @brief Called when door closes.
*/
static void door_closed_handler(void)
{
reset_amounts();
transition(STATE_IDLE);
door_open = false;
}
void buzz_invalid_input(void) {
// FIXME: Implement this later
}
/* ——— UI Drawing Functions —————————————————————————————— */
void sound_alarm(void) {
// FIXME: Implement this later
}
void reset_alarm(void) {
// FIXME: Implement this later
}
void transition(State_t state) {
state_chg = true;
current_state = state;
}
void sm_init(void) {
keypad_init(keypad_handler);
door_init(door_opened_handler, door_closed_handler);
ui_draw_idle();
}
void sm_loop(void) {
for (;;) {
__bis_SR_register(LPM0_bits | GIE); /* Enter LPM0 with interrupts enabled */
__no_operation();
handle_general_interrupt();
}
}
void handle_general_interrupt(void) {
if (state_chg) {
switch (current_state) {
case STATE_IDLE:
ui_draw_idle();
break;
case STATE_SEL_COUNT:
ui_draw_sel_count();
break;
case STATE_CONFIRMED:
ui_draw_confirmed();
break;
case STATE_UNAUTHORIZED:
ui_draw_error();
break;
case STATE_OPEN:
ui_draw_open();
break;
case STATE_NONE_SELECTED:
ui_draw_none_selected();
break;
case STATE_RESET:
ui_draw_reset();
break;
}
state_chg = false;
}
}
char buffer_ab[16];
char buffer_cd[16];
void ui_draw_idle(void) {
/**
* @brief Draw the IDLE screen.
*/
void ui_draw_idle(void)
{
lcd_clear();
lcd_set_cursor(0, 5);
lcd_print("Ready!");
lcd_set_cursor(1, 1);
lcd_print("Press A/B/C/D");
lcd_set_cursor(0,5); lcd_print("Ready!");
lcd_set_cursor(1,0); lcd_print("A-D to order * to edit");
}
void ui_draw_sel_count(void) {
snprintf(buffer_ab, 17, "A:%c%4d B:%c%4d ",
selected_bev == BEV_A ? '*' : ' ',
count_a,
selected_bev == BEV_B ? '*' : ' ',
count_b
);
snprintf(buffer_cd, 17, "C:%c%4d D:%c%4d ",
selected_bev == BEV_C ? '*' : ' ',
count_c,
selected_bev == BEV_D ? '*' : ' ',
count_d
);
/**
* @brief Draw the quantityselection screen.
*/
void ui_draw_sel_count(void)
{
snprintf(buffer_ab, 17, "A:%c%3u B:%c%3u",
(selected_bev==BEV_A?'*':' '), count_a,
(selected_bev==BEV_B?'*':' '), count_b);
snprintf(buffer_cd, 17, "C:%c%3u D:%c%3u",
(selected_bev==BEV_C?'*':' '), count_c,
(selected_bev==BEV_D?'*':' '), count_d);
lcd_set_cursor(0, 0);
lcd_print(buffer_ab);
lcd_set_cursor(1, 0);
lcd_print(buffer_cd);
}
void ui_draw_confirmed(void) {
lcd_clear();
lcd_set_cursor(0, 3);
lcd_print("Confirmed!");
lcd_set_cursor(1, 1);
lcd_print("OPEN/[A-D]/[*]");
lcd_set_cursor(0,0); lcd_print(buffer_ab);
lcd_set_cursor(1,0); lcd_print(buffer_cd);
}
void ui_draw_error(void) {
/**
* @brief Draw the order confirmed screen.
*/
void ui_draw_confirmed(void)
{
lcd_clear();
lcd_set_cursor(0, 2);
lcd_print("UNAUTHORIZED");
lcd_set_cursor(1, 1);
lcd_print("CLOSE DOOR NOW");
lcd_set_cursor(0,3); lcd_print("Confirmed!");
lcd_set_cursor(1,1); lcd_print("Press A-D or *");
}
void ui_draw_open(void) {
/**
* @brief Draw the unauthorizedopen error.
*/
void ui_draw_error(void)
{
lcd_clear();
lcd_set_cursor(0, 2);
lcd_print("DOOR IS OPEN");
lcd_set_cursor(1, 0);
lcd_print("CLOSE /[A-D]/[*]");
lcd_set_cursor(0,2); lcd_print("UNAUTHORIZED");
lcd_set_cursor(1,1); lcd_print("DOOR OPENED!");
}
void ui_draw_none_selected(void) {
/**
* @brief Draw the door is open screen.
*/
void ui_draw_open(void)
{
lcd_clear();
lcd_set_cursor(0, 5);
lcd_print("SELECT");
lcd_set_cursor(1, 1);
lcd_print("ANY BEVERAGES!");
lcd_set_cursor(0,2); lcd_print("DOOR OPEN");
lcd_set_cursor(1,0); lcd_print("Close then *");
}
/**
* @brief Draw when no beverage was selected at #.
*/
void ui_draw_none_selected(void)
{
lcd_clear();
lcd_set_cursor(0,4); lcd_print("SELECT!");
lcd_set_cursor(1,1); lcd_print("Choose A-D");
sleep(1000);
transition(STATE_SEL_COUNT);
ui_draw_sel_count();
}
void ui_draw_reset(void) {
/**
* @brief Transient amounts reset screen.
*/
void ui_draw_reset(void)
{
lcd_clear();
lcd_set_cursor(0, 2);
lcd_print("AMOUNTS HAVE");
lcd_set_cursor(1, 3);
lcd_print("BEEN RESET");
lcd_set_cursor(0,2); lcd_print("All Reset");
lcd_set_cursor(1,1); lcd_print("Ready");
sleep(1000);
transition(STATE_IDLE);
ui_draw_idle();
}
if (door_open) {
transition(STATE_OPEN);
ui_draw_open();
} else {
transition(STATE_IDLE);
ui_draw_idle();
/**
* @brief Draw the stockselection screen.
*/
void ui_draw_stock_select(void)
{
lcd_clear();
lcd_set_cursor(0,3); lcd_print("Edit Stock");
lcd_set_cursor(1,1); lcd_print("A-D:*cancel");
}
/**
* @brief Draw the enter new stock screen.
*/
void ui_draw_stock_set(void)
{
uint8_t cur = 0;
switch (selected_bev) {
case BEV_A: cur = stock_a; break;
case BEV_B: cur = stock_b; break;
case BEV_C: cur = stock_c; break;
case BEV_D: cur = stock_d; break;
}
}
lcd_clear();
snprintf(buffer_ab,17,"%c stock:%3u", 'A'+selected_bev, cur);
lcd_set_cursor(0,0); lcd_print(buffer_ab);
snprintf(buffer_cd,17,"New:%3u *cancel", new_stock_count);
lcd_set_cursor(1,0); lcd_print(buffer_cd);
}
/**
* @brief Draw the stock updated confirmation.
*/
void ui_draw_stock_confirmed(void)
{
lcd_clear();
lcd_set_cursor(0,1); lcd_print("Stock Updated!");
lcd_set_cursor(1,1); lcd_print("Press any key");
}
/* ——— Feedback ——————————————————————————————————————————— */
/**
* @brief Short buzzer tone for invalid input.
*/
void buzz_invalid_input(void)
{
/* stub: beep or flash LED */
}

View File

@ -1,44 +1,59 @@
/* File: state_machine.h */
/**
* @file state_machine.h
* @brief Statemachine for the Core-Program
* @brief State machine interface for the beverage dispenser core program.
*
* ...
* This module drives a keypadandLCD UI to select beverage types (AD),
* choose quantities, confirm orders, detect door events, and edit stock levels.
*
* @authors
* Frederik Beimgraben
* Minh Dan Cam
* Luis Meyer
* @date 2025-07-02
* @author Frederik Beimgraben
* @author Minh Dan Cam
* @author Luis Meyer
* @date 2025-07-03
*/
#ifndef STATE_MACHINE_H
#define STATE_MACHINE_H
static void keypad_handler(char key);
void sm_init(void);
void sm_loop(void);
#include <stdint.h>
#include <stdbool.h>
/**
* @enum State_t
* @brief All possible states of the UI state machine.
*/
typedef enum {
STATE_IDLE,
STATE_SEL_COUNT,
STATE_CONFIRMED,
STATE_OPEN,
STATE_SECRET_INPUT,
STATE_UNLOCKED,
STATE_UNAUTHORIZED,
STATE_NONE_SELECTED,
STATE_RESET
STATE_IDLE, /**< Waiting for user input */
STATE_SEL_COUNT, /**< Selecting order quantity */
STATE_CONFIRMED, /**< Order confirmed */
STATE_OPEN, /**< Door is open */
STATE_UNAUTHORIZED, /**< Unauthorized door opening */
STATE_NONE_SELECTED, /**< No beverage selected at confirm */
STATE_RESET, /**< Transient “reset” display */
STATE_EDIT_STOCK_SELECT, /**< Select which beverages stock to edit */
STATE_EDIT_STOCK_SET, /**< Enter new stock value */
STATE_EDIT_STOCK_CONFIRMED /**< Stock update confirmed */
} State_t;
/**
* @enum SelectedBev_t
* @brief Identifiers for the four beverage types.
*/
typedef enum {
BEV_A,
BEV_B,
BEV_C,
BEV_D
BEV_A, /**< Beverage A */
BEV_B, /**< Beverage B */
BEV_C, /**< Beverage C */
BEV_D /**< Beverage D */
} SelectedBev_t;
#endif // STATE_MACHINE_H
/**
* @brief Initialize the state machine, keypad, door sensor, and LCD.
*/
void sm_init(void);
/**
* @brief Enter the statemachines main loop (lowpower + interrupts).
*/
void sm_loop(void);
#endif // STATE_MACHINE_H