diff --git a/.cproject b/.cproject index 827a8d3..d553e3f 100644 --- a/.cproject +++ b/.cproject @@ -27,7 +27,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/Debug/.clangd/compile_commands.json b/Debug/.clangd/compile_commands.json index 89230d1..b23d093 100644 --- a/Debug/.clangd/compile_commands.json +++ b/Debug/.clangd/compile_commands.json @@ -148,5 +148,15 @@ "directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug", "command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc", "file" : "/home/frederik/workspace_ccstheia/ESR-11/src/state_machine.c" + }, + { + "directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug", + "command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc", + "file" : "/home/frederik/workspace_ccstheia/ESR-11/src/timer.c" + }, + { + "directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug", + "command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc", + "file" : "/home/frederik/workspace_ccstheia/ESR-11/src/door_sensor.c" } ] diff --git a/main.c b/main.c index 8015b46..4cffd0c 100755 --- a/main.c +++ b/main.c @@ -18,72 +18,13 @@ #include "src/i2c.h" #include "src/lcd.h" #include "src/Board.h" +#include "src/timer.h" +#include "src/state_machine.h" /** On-board LED port and pin (used by Morse module) */ #define LED_PORT GPIO_PORT_P1 /**< On-board LED port */ #define LED_PIN GPIO_PIN0 /**< On-board LED pin */ -volatile char last_key_pressed = '\0'; -volatile bool key_changed = false; - -/** - * @brief Keypad callback invoked on key press interrupt. - * @param key ASCII character of pressed key - * - * Stores key, sets ready flag, and blinks Morse code on LED. - */ -static void myKeyHandler(char key) -{ - last_key_pressed = key; - key_changed = true; -} - -void init_timer(void) { - static Timer_B_initUpModeParam param = {0}; - - param.clockSource = TIMER_B_CLOCKSOURCE_SMCLK; - param.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_1; - param.timerPeriod = 999; // wenn 1000 Taktimpulse gezählt - // wurden, erfolgt ein Interrupt - // Periodendauer somit 1ms - param.timerInterruptEnable_TBIE = - TIMER_B_TBIE_INTERRUPT_DISABLE; // no interrupt on 0x0000 - param.captureCompareInterruptEnable_CCR0_CCIE = - TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE; // interrupt on TRmax - param.timerClear = TIMER_B_DO_CLEAR; - param.startTimer = true; - - // start Timer: - Timer_B_initUpMode(TB0_BASE, ¶m); -} - -void init_i2c(void) { - EUSCI_B_I2C_initMasterParam param = {0}; - - // Configure Pins for I2C - /* - * Select Port 1 - * Set Pin 2, 3 to input with function, (UCB0SIMO/UCB0SDA, UCB0SOMI/UCB0SCL). - */ - - GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_UCB0SCL, GPIO_PIN_UCB0SCL, GPIO_FUNCTION_UCB0SCL); - GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_UCB0SDA, GPIO_PIN_UCB0SDA, GPIO_FUNCTION_UCB0SDA); - - param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK; - param.i2cClk = CS_getSMCLK(); - param.dataRate = EUSCI_B_I2C_SET_DATA_RATE_100KBPS; - param.byteCounterThreshold = 1; - param.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP; - EUSCI_B_I2C_initMaster(EUSCI_B0_BASE, ¶m); - - //Specify slave address - EUSCI_B_I2C_setSlaveAddress(EUSCI_B0_BASE, 0x27); - //Set in transmit mode - EUSCI_B_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE); - //Enable I2C Module to start operations - EUSCI_B_I2C_enable(EUSCI_B0_BASE); -} - /** * @brief Main application entry point. * @@ -102,48 +43,10 @@ int main(void) GPIO_setAsOutputPin(LED_PORT, LED_PIN); GPIO_setOutputLowOnPin(LED_PORT, LED_PIN); - /* Initialize keypad interrupt driver */ - initKeypadInterrupts(myKeyHandler); - init_timer(); + i2c_init(); + lcd_init(); - I2C_init(); /* I²C-Master initialisieren */ - lcd_init(); /* LCD initialisieren */ - - lcd_set_cursor(0, 0); - lcd_print("Press any Key!"); - - /* Enter low-power mode and wait for key interrupts */ - for (;;) { - __bis_SR_register(LPM0_bits | GIE); /* Enter LPM0 with interrupts enabled */ - __no_operation(); - - if (key_changed) { - lcd_set_cursor(1, 0); - char output[20] = "Key pressed: "; - output[13] = last_key_pressed; - - lcd_print(output); - - key_changed = false; - } - } -} - -/** - * @brief Führt eine blockierende Wartezeit aus. - * @param ms Zeit in Millisekunden - */ -void sleep(uint16_t ms) { - while (ms--) { - __bis_SR_register(LPM0_bits + GIE); - __no_operation(); - } -} - -// TimerB0 Interrupt Vector (TBxIV) handler -#pragma vector=TIMER0_B0_VECTOR -__interrupt void TIMER0_B0_ISR(void) -{ - __bic_SR_register_on_exit(LPM0_bits); -} + sm_init(); + sm_loop(); +} \ No newline at end of file diff --git a/src/door_sensor.c b/src/door_sensor.c new file mode 100644 index 0000000..65878cb --- /dev/null +++ b/src/door_sensor.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include "door_sensor.h" +#include "constants.h" + +#define SENSOR_PORT GPIO_PORT_P2 +#define SENSOR_PIN GPIO_PIN0 +#define SENSOR_VECTOR PORT2_VECTOR + +/** User callback invoked on confirmed key press */ +static DoorOpenedCallback_t doorOpenedCallback = NULL; +static DoorClosedCallback_t doorClosedCallback = NULL; + +void door_init(DoorOpenedCallback_t ocb, DoorClosedCallback_t ccb) { + doorOpenedCallback = ocb; + doorClosedCallback = ccb; + + /* Configure port as pull up with interrupt */ + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN0); + GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN0); + GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_LOW_TO_HIGH_TRANSITION); + GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN0); + + /* Enable global interrupts */ + __enable_interrupt(); +} + +volatile bool door_last_open = false; + +/** + * @brief Interrupt Service Routine for PORT2 + */ +#pragma vector=SENSOR_VECTOR +__interrupt void SENSOR_ISR(void) +{ + uint16_t status = GPIO_getInterruptStatus(SENSOR_PORT, SENSOR_PIN); + + if (status) { + if (door_last_open) { + if (doorClosedCallback) + doorClosedCallback(); + GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_LOW_TO_HIGH_TRANSITION); + } else { + if (doorOpenedCallback) + doorOpenedCallback(); + GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_HIGH_TO_LOW_TRANSITION); + } + } + + GPIO_clearInterrupt(SENSOR_PORT, SENSOR_PIN); + + door_last_open = !door_last_open; +} diff --git a/src/door_sensor.h b/src/door_sensor.h new file mode 100644 index 0000000..5b43318 --- /dev/null +++ b/src/door_sensor.h @@ -0,0 +1,13 @@ +#ifndef DOOR_H +#define DOOR_H + +/** + * @brief Callback invoked on a confirmed key press. + * @param key ASCII character of the pressed key. + */ +typedef void (*DoorOpenedCallback_t)(void); +typedef void (*DoorClosedCallback_t)(void); + +void door_init(DoorOpenedCallback_t ocb, DoorClosedCallback_t ccb); + +#endif // DOOR_H \ No newline at end of file diff --git a/src/i2c.c b/src/i2c.c index 1e249ae..2bfcc89 100644 --- a/src/i2c.c +++ b/src/i2c.c @@ -28,7 +28,7 @@ static char dataIn; static volatile bool i2cDone = false; -void I2C_init(void) +void i2c_init(void) { // USCI in Reset setzen um Konfiguration zu ermöglichen UCB0CTLW0 |= UCSWRST; @@ -56,7 +56,7 @@ void I2C_init(void) __enable_interrupt(); } -void I2C_write(uint8_t slaveAddress, char data[], uint8_t length) +void i2c_write(uint8_t slaveAddress, char data[], uint8_t length) { UCB0I2CSA = slaveAddress; packet = data; @@ -77,11 +77,11 @@ void I2C_write(uint8_t slaveAddress, char data[], uint8_t length) } } -char I2C_read_reg(uint8_t slaveAddress, uint8_t registerAddress) +char i2c_read_reg(uint8_t slaveAddress, uint8_t registerAddress) { // Registeradresse zuerst senden char addressBuffer[1] = {registerAddress}; - I2C_write(slaveAddress, addressBuffer, 1); + i2c_write(slaveAddress, addressBuffer, 1); // In Empfangsmodus wechseln und 1 Byte anfordern UCB0CTLW0 &= ~UCTR; diff --git a/src/i2c.h b/src/i2c.h index 16ec6e5..f74dfc6 100644 --- a/src/i2c.h +++ b/src/i2c.h @@ -21,7 +21,7 @@ /** * @brief Initialize the I2C module as master (SMCLK/20 → 50 kHz SCL). */ -void I2C_init(void); +void i2c_init(void); /** * @brief Send a data packet to an I2C slave. @@ -29,7 +29,7 @@ void I2C_init(void); * @param data Pointer to the data buffer to send. * @param length Number of bytes to send. */ -void I2C_write(uint8_t slaveAddress, char data[], uint8_t length); +void i2c_write(uint8_t slaveAddress, char data[], uint8_t length); /** * @brief Read a single byte from a specific register of an I2C slave. @@ -37,6 +37,6 @@ void I2C_write(uint8_t slaveAddress, char data[], uint8_t length); * @param registerAddress Register address to read. * @return The byte read from the device. */ -char I2C_read_reg(uint8_t slaveAddress, uint8_t registerAddress); +char i2c_read_reg(uint8_t slaveAddress, uint8_t registerAddress); #endif /* I2C_H */ diff --git a/src/keypad.c b/src/keypad.c index 856b3ad..0570bbc 100644 --- a/src/keypad.c +++ b/src/keypad.c @@ -54,7 +54,7 @@ static KeypadCallback_t keyCallback = NULL; * @param colIdx Index of column (0–3) that triggered interrupt * @return ASCII character of pressed key, or 0 if none detected */ -static char scanRowForColumn(uint8_t colIdx) +static char scan_row_for_column(uint8_t colIdx) { char result = 0; unsigned int r; @@ -85,7 +85,7 @@ static char scanRowForColumn(uint8_t colIdx) * wait for release, then re-arm interrupts. * @param colIdx Index of column that triggered the interrupt */ -static void handleColumnInterrupt(uint8_t colIdx) +static void handle_column_interrupt(uint8_t colIdx) { unsigned int i; @@ -99,7 +99,7 @@ static void handleColumnInterrupt(uint8_t colIdx) /* Identify pressed key and invoke callback if set */ { - char key = scanRowForColumn(colIdx); + char key = scan_row_for_column(colIdx); if (key && keyCallback) { keyCallback(key); } @@ -137,12 +137,12 @@ __interrupt void PORT1_ISR(void) uint16_t status = GPIO_getInterruptStatus(GPIO_PORT_P1, mask); if (status & colPin[COL1]) { - handleColumnInterrupt(COL1); + handle_column_interrupt(COL1); __bic_SR_register_on_exit(LPM0_bits); } if (status & colPin[COL3]) { - handleColumnInterrupt(COL3); + handle_column_interrupt(COL3); __bic_SR_register_on_exit(LPM0_bits); } @@ -159,12 +159,12 @@ __interrupt void PORT3_ISR(void) uint16_t status = GPIO_getInterruptStatus(GPIO_PORT_P3, mask); if (status & colPin[COL0]) { - handleColumnInterrupt(COL0); + handle_column_interrupt(COL0); __bic_SR_register_on_exit(LPM0_bits); } if (status & colPin[COL2]) { - handleColumnInterrupt(COL2); + handle_column_interrupt(COL2); __bic_SR_register_on_exit(LPM0_bits); } @@ -179,7 +179,7 @@ __interrupt void PORT3_ISR(void) * @brief Initialize keypad GPIOs and interrupts. * @param cb Callback invoked with ASCII key on press */ -void initKeypadInterrupts(KeypadCallback_t cb) +void keypad_init(KeypadCallback_t cb) { unsigned int i; keyCallback = cb; diff --git a/src/keypad.h b/src/keypad.h index 8b19e2d..d391715 100644 --- a/src/keypad.h +++ b/src/keypad.h @@ -27,6 +27,6 @@ typedef void (*KeypadCallback_t)(char key); * @brief Initialize the keypad pins and interrupts. * @param cb User callback for key events. */ -void initKeypadInterrupts(KeypadCallback_t cb); +void keypad_init(KeypadCallback_t cb); #endif /* KEYPAD_H */ diff --git a/src/lcd.c b/src/lcd.c index 87897c8..8b73843 100644 --- a/src/lcd.c +++ b/src/lcd.c @@ -11,13 +11,13 @@ static void lcd_write_nibble(uint8_t nibble, uint8_t control) /* High-Nibble in die oberen 4 Bits */ buf[0] = (nibble << 4) | control | LCD_BACKLIGHT; /* EN=1 */ - I2C_write(LCD_I2C_ADDR, buf, 1); + i2c_write(LCD_I2C_ADDR, buf, 1); buf[0] |= LCD_ENABLE; - I2C_write(LCD_I2C_ADDR, buf, 1); + i2c_write(LCD_I2C_ADDR, buf, 1); __delay_cycles(500); /* ca. 50 µs @ 1 MHz */ /* EN=0 */ buf[0] &= ~LCD_ENABLE; - I2C_write(LCD_I2C_ADDR, buf, 1); + i2c_write(LCD_I2C_ADDR, buf, 1); __delay_cycles(500); } diff --git a/src/morse.c b/src/morse.c index bf04f14..ec0fda6 100644 --- a/src/morse.c +++ b/src/morse.c @@ -32,7 +32,7 @@ /** * @brief Blink the LED for a dot: on 1 unit, off 1 unit. */ -static void blinkDot(void) +static void blink_dot(void) { GPIO_setOutputHighOnPin(LED_PORT, LED_PIN); __delay_cycles(MORSE_UNIT_CYCLES); @@ -43,7 +43,7 @@ static void blinkDot(void) /** * @brief Blink the LED for a dash: on 3 units, off 1 unit. */ -static void blinkDash(void) +static void blink_dash(void) { GPIO_setOutputHighOnPin(LED_PORT, LED_PIN); __delay_cycles(3 * MORSE_UNIT_CYCLES); @@ -102,7 +102,7 @@ static const char *lookupMorse(char in) * Unlocks FRAM I/O power-on default high-impedance lock, * then configures LED pin as output low. */ -void morseInit(void) +void morse_init(void) { PMM_unlockLPM5(); GPIO_setAsOutputPin(LED_PORT, LED_PIN); @@ -118,7 +118,7 @@ void morseInit(void) * * @param c Character to blink (A–Z, a–z, 0–9) */ -void blinkMorseChar(char c) +void blink_morse_char(char c) { const char *pattern = lookupMorse(c); const char *p; @@ -130,9 +130,9 @@ void blinkMorseChar(char c) /* Blink each element in pattern */ for (p = pattern; *p; p++) { if (*p == '.') { - blinkDot(); + blink_dot(); } else if (*p == '-') { - blinkDash(); + blink_dash(); } } diff --git a/src/morse.h b/src/morse.h index 882b770..bb776c1 100644 --- a/src/morse.h +++ b/src/morse.h @@ -10,7 +10,7 @@ /** * @brief Initialize LED output pin (P1.0) for Morse blinking. */ -void morseInit(void); +void morse_init(void); /** * @brief Blink an alphanumeric character in Morse code. @@ -18,6 +18,6 @@ void morseInit(void); * Supports A–Z (case-insensitive) and 0–9. Others are ignored. * @param c Character to blink */ -void blinkMorseChar(char c); +void blink_morse_char(char c); #endif // MORSE_H diff --git a/src/state_machine.c b/src/state_machine.c index df8d82b..e80a490 100644 --- a/src/state_machine.c +++ b/src/state_machine.c @@ -12,4 +12,365 @@ * @date 2025-07-02 */ - \ No newline at end of file +#include +#include +#include +#include +#include +#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; + +volatile bool allow_open = false; + +/* Function Declarations */ +void handle_interrupt(void); +void buzz_invalid_input(void); +void sound_alarm(void); +void reset_alarm(void); +void transition(State_t state); +void ui_draw_idle(void); +void ui_draw_sel_count(void); +void ui_draw_confirmed(void); +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); + +volatile State_t current_state = STATE_IDLE; +volatile bool state_chg = false; + +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; + +volatile bool door_open = false; + +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(); + } +} + +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 Keypad callback invoked on key press interrupt. + * @param key ASCII character of pressed key + * + * Stores key, sets ready flag, and blinks Morse code on LED. + */ +static void keypad_handler(char key) +{ + keypad_last_key = key; + keypad_flag_chg = true; + + switch (current_state) { + case STATE_IDLE: + handle_input_idle(key); + break; + case STATE_SEL_COUNT: + handle_input_sel_count(key); + break; + case STATE_CONFIRMED: + handle_input_confirmed(key); + break; + case STATE_OPEN: + handle_input_confirmed(key); + break; + default: + buzz_invalid_input(); + } +} + +bool any_selected(void) { + return count_a + count_b + count_c + count_d > 0; +} + +static void door_opened_handler(void) { + if (current_state != STATE_CONFIRMED && current_state != STATE_UNLOCKED) { + transition(STATE_UNAUTHORIZED); + } else { + transition(STATE_OPEN); + } + + door_open = true; +} + +static void door_closed_handler(void) { + reset_amounts(); + transition(STATE_IDLE); + + door_open = false; +} + +void buzz_invalid_input(void) { + // FIXME: Implement this later +} + +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) { + lcd_clear(); + lcd_set_cursor(0, 5); + lcd_print("Ready!"); + lcd_set_cursor(1, 1); + lcd_print("Press A/B/C/D"); +} + +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 + ); + + 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]/[*]"); +} + +void ui_draw_error(void) { + lcd_clear(); + lcd_set_cursor(0, 2); + lcd_print("UNAUTHORIZED"); + lcd_set_cursor(1, 1); + lcd_print("CLOSE DOOR NOW"); +} + +void ui_draw_open(void) { + lcd_clear(); + lcd_set_cursor(0, 2); + lcd_print("DOOR IS OPEN"); + lcd_set_cursor(1, 0); + lcd_print("CLOSE /[A-D]/[*]"); +} + +void ui_draw_none_selected(void) { + lcd_clear(); + lcd_set_cursor(0, 5); + lcd_print("SELECT"); + lcd_set_cursor(1, 1); + lcd_print("ANY BEVERAGES!"); + + sleep(1000); + + transition(STATE_SEL_COUNT); + ui_draw_sel_count(); +} + +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"); + + sleep(1000); + + if (door_open) { + transition(STATE_OPEN); + ui_draw_open(); + } else { + transition(STATE_IDLE); + ui_draw_idle(); + } +} \ No newline at end of file diff --git a/src/state_machine.h b/src/state_machine.h index 4017cb5..5742107 100644 --- a/src/state_machine.h +++ b/src/state_machine.h @@ -12,4 +12,33 @@ * @date 2025-07-02 */ -static void keypad_handler(char key); \ No newline at end of file +#ifndef STATE_MACHINE_H +#define STATE_MACHINE_H + +static void keypad_handler(char key); + +void sm_init(void); + +void sm_loop(void); + + +typedef enum { + STATE_IDLE, + STATE_SEL_COUNT, + STATE_CONFIRMED, + STATE_OPEN, + STATE_SECRET_INPUT, + STATE_UNLOCKED, + STATE_UNAUTHORIZED, + STATE_NONE_SELECTED, + STATE_RESET +} State_t; + +typedef enum { + BEV_A, + BEV_B, + BEV_C, + BEV_D +} SelectedBev_t; + +#endif // STATE_MACHINE_H \ No newline at end of file diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..10950cc --- /dev/null +++ b/src/timer.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include "timer.h" + +/** + * @brief Führt eine blockierende Wartezeit aus. + * @param ms Zeit in Millisekunden + */ +void sleep(uint16_t ms) { + while (ms--) { + __bis_SR_register(LPM0_bits + GIE); + __no_operation(); + } +} + +void init_timer(void) { + static Timer_B_initUpModeParam param = {0}; + + param.clockSource = TIMER_B_CLOCKSOURCE_SMCLK; + param.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_1; + param.timerPeriod = 999; // wenn 1000 Taktimpulse gezählt + // wurden, erfolgt ein Interrupt + // Periodendauer somit 1ms + param.timerInterruptEnable_TBIE = + TIMER_B_TBIE_INTERRUPT_DISABLE; // no interrupt on 0x0000 + param.captureCompareInterruptEnable_CCR0_CCIE = + TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE; // interrupt on TRmax + param.timerClear = TIMER_B_DO_CLEAR; + param.startTimer = true; + + // start Timer: + Timer_B_initUpMode(TB0_BASE, ¶m); +} + +// TimerB0 Interrupt Vector (TBxIV) handler +#pragma vector=TIMER0_B0_VECTOR +__interrupt void TIMER0_B0_ISR(void) +{ + __bic_SR_register_on_exit(LPM0_bits); +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..703f61e --- /dev/null +++ b/src/timer.h @@ -0,0 +1,7 @@ +#ifndef TIMER_H +#define TIMER_H + +void sleep(uint16_t ms); +void init_timer(void); + +#endif // TIMER_H \ No newline at end of file