From dc6198f587c72d838557b6a93683ba7bc7c4dd5d Mon Sep 17 00:00:00 2001 From: Frederik Beimgraben Date: Thu, 3 Jul 2025 04:13:27 +0200 Subject: [PATCH] refactor: State Machine Refinement 1 --- src/state_machine.c | 781 ++++++++++++++++++++++++++++---------------- src/state_machine.h | 69 ++-- 2 files changed, 545 insertions(+), 305 deletions(-) diff --git a/src/state_machine.c b/src/state_machine.c index e80a490..81c1ae3 100644 --- a/src/state_machine.c +++ b/src/state_machine.c @@ -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 per‐type 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 -#include -#include +#include #include -#include +#include +#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 (per‐session) for beverages A–D. */ +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 A–D. */ +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); + +/* Order‐entry */ +void update_amount(uint8_t digit); +void reset_amount(void); +void reset_amounts(void); + +/* Stock‐editing */ +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: low‐power + 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 state‐specific 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. + * + * A–D start ordering that beverage. + * ‘*’ enters stock‐editing 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 idle‐handler. + */ +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. + * + * A–D re‐select 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. + * + * A–D 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 0–9 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 0–9 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 quantity‐selection 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 unauthorized‐open 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 stock‐selection 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; } -} \ No newline at end of file + 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 */ +} diff --git a/src/state_machine.h b/src/state_machine.h index 5742107..b18f493 100644 --- a/src/state_machine.h +++ b/src/state_machine.h @@ -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 keypad‐and‐LCD UI to select beverage types (A–D), + * 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 +#include +/** + * @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 beverage’s 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 \ No newline at end of file +/** + * @brief Initialize the state machine, keypad, door sensor, and LCD. + */ +void sm_init(void); + +/** + * @brief Enter the state‐machine’s main loop (low‐power + interrupts). + */ +void sm_loop(void); + +#endif // STATE_MACHINE_H