refactor: State Machine Refinement 3
This commit is contained in:
parent
7a7667171c
commit
276ac618b3
@ -42,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8
|
||||
# title of most generated pages and in a few other places.
|
||||
# The default value is: My Project.
|
||||
|
||||
PROJECT_NAME = "My Project"
|
||||
PROJECT_NAME = "ESR-Gruppe 11"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
@ -1087,7 +1087,7 @@ FILE_PATTERNS = *.c \
|
||||
# be searched for input files as well.
|
||||
# The default value is: NO.
|
||||
|
||||
RECURSIVE = NO
|
||||
RECURSIVE = YES
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should be
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
@ -1096,7 +1096,7 @@ RECURSIVE = NO
|
||||
# Note that relative paths are relative to the directory from which Doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE =
|
||||
EXCLUDE = driverlib/
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
@ -2465,7 +2465,7 @@ SEARCH_INCLUDES = YES
|
||||
# RECURSIVE has no effect here.
|
||||
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
|
||||
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_PATH = src/
|
||||
|
||||
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
||||
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
||||
|
||||
@ -4,7 +4,10 @@
|
||||
* @brief State machine implementation for the beverage dispenser core program.
|
||||
*
|
||||
* Tracks per‐type stock levels, enforces stock limits on orders,
|
||||
* and provides an “[A-D]/*” menu in IDLE to edit stock via the keypad.
|
||||
* provides an “[A-D]/*” menu in IDLE to edit stock via the keypad,
|
||||
* implements buzzer feedback, and drives onboard LEDs:
|
||||
* – GREEN (P6.6) when the door may be opened (confirmed order),
|
||||
* – RED (P1.0) otherwise.
|
||||
*
|
||||
* @authors
|
||||
* Frederik Beimgraben
|
||||
@ -17,18 +20,35 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <msp430.h>
|
||||
#include "driverlib.h"
|
||||
#include <driverlib.h>
|
||||
#include <timer_a.h>
|
||||
#include "keypad.h"
|
||||
#include "lcd.h"
|
||||
#include "door_sensor.h"
|
||||
#include "state_machine.h"
|
||||
#include "timer.h"
|
||||
#include "Board.h"
|
||||
|
||||
/** Default initial stock for each beverage. */
|
||||
#define INITIAL_STOCK_DEFAULT 20U
|
||||
/** Maximum stock representable (uint8_t limit). */
|
||||
#define MAX_STOCK 255U
|
||||
|
||||
/** Buzzer-Settings */
|
||||
#define BUZZER_PORT_DIR P5DIR
|
||||
#define BUZZER_PORT_OUT P5OUT
|
||||
#define BUZZER_PIN BIT0
|
||||
#define BUZZER_PERIOD 1000U
|
||||
|
||||
/** Red LED on P1.0. */
|
||||
#define LED_RED_PORT_DIR P1DIR
|
||||
#define LED_RED_PORT_OUT P1OUT
|
||||
#define LED_RED_PIN BIT0
|
||||
/** Green LED on P6.6. */
|
||||
#define LED_GREEN_PORT_DIR P6DIR
|
||||
#define LED_GREEN_PORT_OUT P6OUT
|
||||
#define LED_GREEN_PIN BIT6
|
||||
|
||||
/** Last key pressed on the keypad. */
|
||||
volatile char keypad_last_key = '\0';
|
||||
/** Flag set when a new key is ready to handle. */
|
||||
@ -64,6 +84,12 @@ char buffer_cd[17];
|
||||
|
||||
/* —— Function Prototypes —— */
|
||||
|
||||
/* Hardware feedback */
|
||||
static void update_leds(void);
|
||||
void buzz_invalid_input(void);
|
||||
void sound_alarm(void);
|
||||
void reset_alarm(void);
|
||||
|
||||
/* Keypad input handlers */
|
||||
static void keypad_handler(char key);
|
||||
void handle_input_idle(unsigned char key);
|
||||
@ -97,9 +123,6 @@ void ui_draw_stock_select(void);
|
||||
void ui_draw_stock_set(void);
|
||||
void ui_draw_stock_confirmed(void);
|
||||
|
||||
/* Error/signal feedback */
|
||||
void buzz_invalid_input(void);
|
||||
|
||||
/* Door callbacks */
|
||||
static void door_opened_handler(void);
|
||||
static void door_closed_handler(void);
|
||||
@ -111,11 +134,34 @@ void handle_general_interrupt(void);
|
||||
/**
|
||||
* @brief Initialize peripherals and draw the initial UI.
|
||||
*
|
||||
* Registers keypad and door callbacks, resets counts and stock,
|
||||
* and displays the idle screen.
|
||||
* Configures buzzer and LED GPIOs, registers callbacks,
|
||||
* resets counts and stock, and displays the idle screen.
|
||||
*/
|
||||
void sm_init(void)
|
||||
{
|
||||
/* buzzer pin out */
|
||||
BUZZER_PORT_DIR |= BUZZER_PIN;
|
||||
BUZZER_PORT_OUT &= ~BUZZER_PIN;
|
||||
|
||||
/* set up TB2 in up‐mode, CCR0 interrupt every BUZZER_PERIOD ticks */
|
||||
Timer_B_initUpModeParam param = {
|
||||
.clockSource = TIMER_B_CLOCKSOURCE_SMCLK,
|
||||
.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_1,
|
||||
.timerPeriod = BUZZER_PERIOD,
|
||||
//.timerInterruptEnable_TBIE = TIMER_B_TBIE_INTERRUPT_DISABLE,
|
||||
//.captureCompareInterruptEnable_CCR0_CCIE = TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE,
|
||||
.timerClear = TIMER_B_DO_CLEAR,
|
||||
.startTimer = true
|
||||
};
|
||||
Timer_B_initUpMode(TB2_BASE, ¶m);
|
||||
|
||||
/* Configure LEDs */
|
||||
LED_RED_PORT_DIR |= LED_RED_PIN;
|
||||
LED_GREEN_PORT_DIR |= LED_GREEN_PIN;
|
||||
/* ensure off by default */
|
||||
LED_RED_PORT_OUT |= LED_RED_PIN; // red on initially
|
||||
LED_GREEN_PORT_OUT &= ~LED_GREEN_PIN;
|
||||
|
||||
keypad_init(keypad_handler);
|
||||
door_init(door_opened_handler, door_closed_handler);
|
||||
|
||||
@ -124,6 +170,15 @@ void sm_init(void)
|
||||
stock_a = stock_b = stock_c = stock_d = INITIAL_STOCK_DEFAULT;
|
||||
|
||||
ui_draw_idle();
|
||||
update_leds();
|
||||
}
|
||||
|
||||
|
||||
#pragma vector = TIMER2_B0_VECTOR
|
||||
__interrupt void ISR_TB2_CCR0(void)
|
||||
{
|
||||
BUZZER_PORT_OUT ^= BUZZER_PIN; // flip the buzzer output
|
||||
TB2CCTL0 &= ~CCIFG; // clear the interrupt flag
|
||||
}
|
||||
|
||||
|
||||
@ -139,6 +194,70 @@ void sm_loop(void)
|
||||
}
|
||||
}
|
||||
|
||||
bool open_door_allowed(void) {
|
||||
return (
|
||||
current_state == STATE_CONFIRMED ||
|
||||
current_state == STATE_OPEN ||
|
||||
(current_state == STATE_SEL_COUNT && door_open) ||
|
||||
current_state == STATE_EDIT_STOCK_SELECT ||
|
||||
current_state == STATE_EDIT_STOCK_SET ||
|
||||
current_state == STATE_EDIT_STOCK_CONFIRMED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update the onboard LEDs.
|
||||
*
|
||||
* GREEN on if in STATE_CONFIRMED (door may open), else RED on.
|
||||
*/
|
||||
void update_leds(void)
|
||||
{
|
||||
if (
|
||||
open_door_allowed()
|
||||
) {
|
||||
/* allow open: green on, red off */
|
||||
LED_GREEN_PORT_OUT |= LED_GREEN_PIN;
|
||||
LED_RED_PORT_OUT &= ~LED_RED_PIN;
|
||||
} else {
|
||||
/* otherwise: red on, green off */
|
||||
LED_RED_PORT_OUT |= LED_RED_PIN;
|
||||
LED_GREEN_PORT_OUT &= ~LED_GREEN_PIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Short buzzer beep for invalid input.
|
||||
*/
|
||||
void buzz_invalid_input(void)
|
||||
{
|
||||
/* beep 50ms */
|
||||
sound_alarm();
|
||||
sleep(50);
|
||||
reset_alarm();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sound the alarm continuously.
|
||||
*/
|
||||
void sound_alarm(void)
|
||||
{
|
||||
TB2CCR0 = BUZZER_PERIOD;
|
||||
TB2CCTL0 |= CCIE; // enable CCR0 interrupts
|
||||
TB2CTL = TBSSEL__SMCLK | MC__UP | TBCLR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop any sounding alarm.
|
||||
*/
|
||||
void reset_alarm(void)
|
||||
{
|
||||
TB2CCTL0 &= ~CCIE; // disable CCR0 interrupts
|
||||
TB2CTL &= ~MC__UP; // stop TB2
|
||||
BUZZER_PORT_OUT &= ~BUZZER_PIN; // make sure buzzer pin is low
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Keypad interrupt handler.
|
||||
@ -169,7 +288,7 @@ static void keypad_handler(char key)
|
||||
handle_input_edit_stock_set(key);
|
||||
break;
|
||||
case STATE_EDIT_STOCK_CONFIRMED:
|
||||
transition(STATE_IDLE);
|
||||
transition(STATE_EDIT_STOCK_SELECT);
|
||||
break;
|
||||
default:
|
||||
buzz_invalid_input();
|
||||
@ -221,13 +340,6 @@ void handle_input_sel_count(unsigned char key)
|
||||
} else if (!any_selected()) {
|
||||
transition(STATE_NONE_SELECTED);
|
||||
} else {
|
||||
/* Deduct stock */
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -332,22 +444,22 @@ void update_amount(uint8_t digit)
|
||||
switch (selected_bev) {
|
||||
case BEV_A:
|
||||
tentative = count_a * 10 + digit;
|
||||
if (tentative <= stock_a) count_a = (uint8_t)tentative;
|
||||
if (tentative <= stock_a) count_a = tentative;
|
||||
else buzz_invalid_input();
|
||||
break;
|
||||
case BEV_B:
|
||||
tentative = count_b * 10 + digit;
|
||||
if (tentative <= stock_b) count_b = (uint8_t)tentative;
|
||||
if (tentative <= stock_b) count_b = tentative;
|
||||
else buzz_invalid_input();
|
||||
break;
|
||||
case BEV_C:
|
||||
tentative = count_c * 10 + digit;
|
||||
if (tentative <= stock_c) count_c = (uint8_t)tentative;
|
||||
if (tentative <= stock_c) count_c = tentative;
|
||||
else buzz_invalid_input();
|
||||
break;
|
||||
case BEV_D:
|
||||
tentative = count_d * 10 + digit;
|
||||
if (tentative <= stock_d) count_d = (uint8_t)tentative;
|
||||
if (tentative <= stock_d) count_d = tentative;
|
||||
else buzz_invalid_input();
|
||||
break;
|
||||
}
|
||||
@ -413,12 +525,14 @@ bool any_selected(void)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Redraw the UI if the state has changed.
|
||||
* @brief Redraw the UI and update LEDs if the state has changed.
|
||||
*/
|
||||
void handle_general_interrupt(void)
|
||||
{
|
||||
if (!state_chg) return;
|
||||
|
||||
update_leds();
|
||||
|
||||
switch (current_state) {
|
||||
case STATE_IDLE: ui_draw_idle(); break;
|
||||
case STATE_SEL_COUNT: ui_draw_sel_count(); break;
|
||||
@ -454,9 +568,13 @@ void transition(State_t next)
|
||||
*/
|
||||
static void door_opened_handler(void)
|
||||
{
|
||||
if (current_state != STATE_CONFIRMED) {
|
||||
if (!open_door_allowed()) {
|
||||
transition(STATE_UNAUTHORIZED);
|
||||
} else {
|
||||
} else if (
|
||||
current_state != STATE_EDIT_STOCK_SELECT &&
|
||||
current_state != STATE_EDIT_STOCK_SET &&
|
||||
current_state != STATE_EDIT_STOCK_CONFIRMED
|
||||
) {
|
||||
transition(STATE_OPEN);
|
||||
}
|
||||
door_open = true;
|
||||
@ -470,17 +588,30 @@ static void door_opened_handler(void)
|
||||
*/
|
||||
static void door_closed_handler(void)
|
||||
{
|
||||
reset_amounts();
|
||||
transition(STATE_IDLE);
|
||||
door_open = false;
|
||||
if (
|
||||
current_state != STATE_EDIT_STOCK_SELECT &&
|
||||
current_state != STATE_EDIT_STOCK_SET &&
|
||||
current_state != STATE_EDIT_STOCK_CONFIRMED
|
||||
) {
|
||||
/* Deduct stock */
|
||||
stock_a -= count_a;
|
||||
stock_b -= count_b;
|
||||
stock_c -= count_c;
|
||||
stock_d -= count_d;
|
||||
|
||||
reset_amounts();
|
||||
transition(STATE_IDLE);
|
||||
door_open = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ——— UI Drawing Functions —————————————————————————————— */
|
||||
|
||||
/**
|
||||
* @brief Draw the IDLE screen.
|
||||
*
|
||||
* Line 1: “Ready!” centered.
|
||||
* Line 2: “[A-D]/*” menu hint.
|
||||
* [A-D]/* menu hint.
|
||||
*/
|
||||
void ui_draw_idle(void)
|
||||
{
|
||||
@ -489,11 +620,8 @@ void ui_draw_idle(void)
|
||||
lcd_set_cursor(1,4); lcd_print("[A-D]/*");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draw the order‐quantity selection screen.
|
||||
*
|
||||
* Shows A/B on line 1, C/D on line 2 with “*” marking the selected.
|
||||
*/
|
||||
void ui_draw_sel_count(void)
|
||||
{
|
||||
@ -509,12 +637,8 @@ void ui_draw_sel_count(void)
|
||||
lcd_set_cursor(1,0); lcd_print(buffer_cd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draw the “order confirmed” screen.
|
||||
*
|
||||
* Line 1: “Confirmed!” centered.
|
||||
* Line 2: “Press [A-D]/*” for next action.
|
||||
*/
|
||||
void ui_draw_confirmed(void)
|
||||
{
|
||||
@ -523,7 +647,6 @@ void ui_draw_confirmed(void)
|
||||
lcd_set_cursor(1,2); lcd_print("OPEN/[A-D]/*");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draw the unauthorized‐open error.
|
||||
*/
|
||||
@ -534,7 +657,6 @@ void ui_draw_error(void)
|
||||
lcd_set_cursor(1,3); lcd_print("DOOR OPENED");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draw the “door is open” screen.
|
||||
*/
|
||||
@ -545,7 +667,6 @@ void ui_draw_open(void)
|
||||
lcd_set_cursor(1,2); lcd_print("[*] to reset");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draw when no beverage was selected at “#”.
|
||||
*/
|
||||
@ -560,7 +681,6 @@ void ui_draw_none_selected(void)
|
||||
ui_draw_sel_count();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Transient “all reset” screen.
|
||||
*/
|
||||
@ -580,11 +700,8 @@ void ui_draw_reset(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draw the stock‐selection screen.
|
||||
*
|
||||
* [A-D] picks beverage, [*] cancels.
|
||||
*/
|
||||
void ui_draw_stock_select(void)
|
||||
{
|
||||
@ -593,12 +710,8 @@ void ui_draw_stock_select(void)
|
||||
lcd_set_cursor(1,4); lcd_print("[A-D]/*");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draw the “enter new stock” screen.
|
||||
*
|
||||
* Line 1: “X stock:YYY” current level.
|
||||
* Line 2: “New:ZZZ /*” entry buffer and cancel.
|
||||
*/
|
||||
void ui_draw_stock_set(void)
|
||||
{
|
||||
@ -617,7 +730,6 @@ void ui_draw_stock_set(void)
|
||||
lcd_set_cursor(1,0); lcd_print(buffer_cd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draw the “stock updated” confirmation.
|
||||
*/
|
||||
@ -627,12 +739,3 @@ void ui_draw_stock_confirmed(void)
|
||||
lcd_set_cursor(0,2); lcd_print("Stock Updated");
|
||||
lcd_set_cursor(1,1); lcd_print("Press any key");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Short buzzer tone or LED flash for invalid input.
|
||||
*/
|
||||
void buzz_invalid_input(void)
|
||||
{
|
||||
/* stub: implement buzzer or LED indication */
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user