From 7d36e7192348c6a4f2a3db021e6af101aeefd449 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Wed, 15 May 2024 22:07:53 +0200 Subject: [PATCH] WIP: started implementing the countdown state machine --- src/main.c | 164 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 127 insertions(+), 37 deletions(-) diff --git a/src/main.c b/src/main.c index 36f42e1..ec9fbba 100644 --- a/src/main.c +++ b/src/main.c @@ -1,16 +1,24 @@ #include "hardware/gpio.h" #include "hardware/irq.h" -#include "hardware/pwm.h" -#include "hardware/irq.h" #include "sseg.h" +#include "buttons.h" +#include "buzzer.h" #include "pinout.h" #include -const uint8_t all_gpios[] = { - OUTPUT_ENABLE_PIN, -}; +typedef enum { + COUNTDOWN_UNINITIALIZED, + COUNTDOWN_STOPPED, + COUNTDOWN_STARTING, + COUNTDOWN_RUNNING +} countdown_state_t; + +static countdown_state_t m_countdown_state; +static uint32_t m_last_state_change_time; + +static uint32_t m_countdown_off_time; static volatile bool m_ms_triggered; static uint32_t m_next_ms_trigger; @@ -45,62 +53,139 @@ static void configure_ms_trig_alarm(void) m_next_ms_trigger = timer_hw->timelr + 10000; } +static void update_countdown_fsm(uint32_t time_ms) +{ + countdown_state_t last_state = m_countdown_state; + + // note: this calculation works even if time_ms overflows + uint32_t time_in_state = time_ms - m_last_state_change_time; + bool state_entered = (time_in_state == 1); + + uint32_t countdown_time_remaining; // only used in COUNTDOWN_RUNNING state + + switch(m_countdown_state) { + case COUNTDOWN_UNINITIALIZED: + m_countdown_state = COUNTDOWN_STOPPED; + break; + + case COUNTDOWN_STOPPED: + if(state_entered) { + sseg_set_char(0, 'o', false); + sseg_set_char(1, 'f', false); + sseg_set_char(2, 'f', false); + } + + if(buttons_get_events(BTN_ON) & BTN_EVENT_PRESSED) { + m_countdown_state = COUNTDOWN_STARTING; + } + break; + + case COUNTDOWN_STARTING: + // TODO: show a fancy animation + beep code + + if(buttons_get_events(BTN_ON) & BTN_EVENT_RELEASED) { + // button released too early -> back to stopped state + m_countdown_state = COUNTDOWN_STOPPED; + } + + if(time_in_state == 3000) { + m_countdown_off_time = time_ms + 30 * 60 * 1000; + m_countdown_state = COUNTDOWN_RUNNING; + } + break; + + case COUNTDOWN_RUNNING: + if(state_entered) { + // countdown has been started -> switch on the load + gpio_put(OUTPUT_ENABLE_PIN, true); + } + + countdown_time_remaining = m_countdown_off_time - time_ms; + + // TODO: show time on display + // TODO: off button handling + // TODO: on button handling (extend time) + + // beep codes + switch(countdown_time_remaining) { + case 300000: // short beep at 5 minutes remaining + case 60000: // double beep at 1 minute remaining + case 59600: + case 10000: // triple beep at 10 seconds remaining + case 9600: + case 9200: + case 5000: // count down the last 5 seconds + case 4000: + case 3000: + case 2000: + case 1000: // last second beep is longer + buzzer_on(1000); + break; + + case 299800: + case 59800: + case 59400: + case 9800: + case 9400: + case 9000: + case 4800: + case 3800: + case 2800: + case 1800: + case 500: + buzzer_off(); + break; + } + + if(countdown_time_remaining == 0) { + // switch off the load + gpio_put(OUTPUT_ENABLE_PIN, false); + m_countdown_state = COUNTDOWN_STOPPED; + } + } + + if(m_countdown_state != last_state) { + m_last_state_change_time = time_ms; + } +} + int main() { //stdio_init_all(); //printf("Hello, world!\n"); - bool power_switch_state = false; + gpio_init(OUTPUT_ENABLE_PIN); + gpio_put(OUTPUT_ENABLE_PIN, false); + gpio_set_dir(OUTPUT_ENABLE_PIN, true); - for(size_t i = 0; i < sizeof(all_gpios); i++) { - gpio_init(all_gpios[i]); - gpio_put(all_gpios[i], false); - gpio_set_dir(all_gpios[i], true); - } + buzzer_init(); + buttons_init(); - gpio_put(OUTPUT_ENABLE_PIN, true); - - // set up PWM for 50 kHz @ 512 steps resolution - uint slice_num = pwm_gpio_to_slice_num(BUZZER_PIN); - - pwm_set_clkdiv_int_frac(slice_num, 244, (14 << 4) / 100); // 125 MHz / 244.14 / 512 = 1 kHz - gpio_set_function(BUZZER_PIN, GPIO_FUNC_PWM); - pwm_set_wrap(slice_num, 512); - pwm_set_chan_level(slice_num, PWM_CHAN_B, 1 * 512 / 100); - pwm_set_enabled(slice_num, true); + buzzer_on(1000); sleep_ms(200); - pwm_set_enabled(slice_num, false); - pwm_set_clkdiv_int_frac(slice_num, 122, (7 << 4) / 100); // 125 MHz / 122.07 / 512 = 2 kHz - pwm_set_enabled(slice_num, true); - + buzzer_off(); + buzzer_on(2000); sleep_ms(200); - pwm_set_enabled(slice_num, false); - pwm_set_clkdiv_int_frac(slice_num, 61, (3 << 4) / 100); // 125 MHz / 61.03 / 512 = 4 kHz - pwm_set_enabled(slice_num, true); + buzzer_off(); + buzzer_on(4000); sleep_ms(200); - pwm_set_enabled(slice_num, false); - gpio_init(BUZZER_PIN); - gpio_put(BUZZER_PIN, false); - gpio_set_dir(BUZZER_PIN, true); + buzzer_off(); sleep_ms(2400); - pwm_set_enabled(slice_num, false); - gpio_init(BUZZER_PIN); - - gpio_put(OUTPUT_ENABLE_PIN, false); - sseg_init(); configure_ms_trig_alarm(); arm_ms_trig_alarm(); + m_countdown_state = COUNTDOWN_UNINITIALIZED; + uint32_t ms_counter = 0; while (true) { sseg_loop(); @@ -109,6 +194,11 @@ int main() m_ms_triggered = false; ms_counter++; + + buttons_update_state(ms_counter); + + update_countdown_fsm(ms_counter); + sseg_set_char(2, '0' + (ms_counter / 100) % 10, false); sseg_set_char(1, '0' + (ms_counter / 1000) % 10, true); sseg_set_char(0, '0' + (ms_counter / 10000) % 10, false);