From 7cb4fe0944b839f28dfd96a88a772cd6a8b58019 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 2 Nov 2023 17:16:25 -0600 Subject: reorganized project files (part 1) (just moved files, didn't change the contents yet, and nothing will work without updating #includes and build scripts and stuff) --- fsm/events.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 fsm/events.c (limited to 'fsm/events.c') diff --git a/fsm/events.c b/fsm/events.c new file mode 100644 index 0000000..6987ae2 --- /dev/null +++ b/fsm/events.c @@ -0,0 +1,198 @@ +// fsm-events.c: Event-handling functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + + +void append_emission(Event event, uint16_t arg) { + uint8_t i; + // find last entry + for(i=0; + (i=0; i--) { + uint8_t err = state_stack[i](event, arg); + if (! err) return 0; + } + return 1; // event not handled +} + +void emit(Event event, uint16_t arg) { + // add this event to the queue for later, + // so we won't use too much time during an interrupt + append_emission(event, arg); +} + +void emit_current_event(uint16_t arg) { + emit(current_event, arg); +} + +void empty_event_sequence() { + current_event = EV_none; + ticks_since_last_event = 0; + // when the user completes an input sequence, interrupt any running timers + // to cancel any delays currently in progress + // This eliminates a whole bunch of extra code: + // before: if (! nice_delay_ms(ms)) {break;} + // after: nice_delay_ms(ms); + interrupt_nice_delays(); +} + +uint8_t push_event(uint8_t ev_type) { // only for use by PCINT_inner() + // don't do this here; do it in PCINT_inner() instead + //ticks_since_last_event = 0; // something happened + + // only click events are sent to this function + current_event |= B_CLICK; + + // handle button presses + if (ev_type == B_PRESS) { + // set press flag + current_event |= B_PRESS; + // increase click counter + if ((current_event & B_COUNT) < (B_COUNT)) { + current_event ++; + } + return 1; // event pushed, even if max clicks already reached + // (will just repeat the max over and over) + } + // handle button releases + else if (ev_type == B_RELEASE) { + // clear the press flag + current_event &= (~B_PRESS); + // if a "hold" event just ended, set the timeout flag + // to indicate that the event is done and can be cleared + if (current_event & B_HOLD) { current_event |= B_TIMEOUT; } + return 1; // event pushed + } + + return 0; // unexpected event type +} + + +// explicitly interrupt these "nice" delays +volatile uint8_t nice_delay_interrupt = 0; +inline void interrupt_nice_delays() { nice_delay_interrupt = 1; } + +// like delay_ms, except it aborts on state change +// return value: +// 0: state changed +// 1: normal completion +uint8_t nice_delay_ms(uint16_t ms) { + /* // delay_zero() implementation + if (ms == 0) { + CLKPR = 1< 0) { + if (nice_delay_interrupt) { + return 0; + } + + #ifdef USE_DYNAMIC_UNDERCLOCKING + #ifdef USE_RAMPING + uint8_t level = actual_level; // volatile, avoid repeat access + if (level < QUARTERSPEED_LEVEL) { + clock_prescale_set(clock_div_4); + _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100/4); + } + //else if (level < HALFSPEED_LEVEL) { + // clock_prescale_set(clock_div_2); + // _delay_loop_2(BOGOMIPS*95/100/2); + //} + else { + clock_prescale_set(clock_div_1); + _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100); + } + // restore regular clock speed + clock_prescale_set(clock_div_1); + #else + // underclock MCU to save power + clock_prescale_set(clock_div_4); + // wait + _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100/4); + // restore regular clock speed + clock_prescale_set(clock_div_1); + #endif // ifdef USE_RAMPING + #else + // wait + _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100); + #endif // ifdef USE_DYNAMIC_UNDERCLOCKING + + // run pending system processes while we wait + handle_deferred_interrupts(); + + // handle events only afterward, so that any collapsed delays will + // finish running the UI's loop() code before taking any further actions + // (this helps make sure code runs in the correct order) + // (otherwise, a new state's EV_enter runs before the old state's + // loop() has finished, and things can get weird) + process_emissions(); + } + return 1; +} + +#ifdef USE_DYNAMIC_UNDERCLOCKING +void delay_4ms(uint8_t ms) { + while(ms-- > 0) { + // underclock MCU to save power + clock_prescale_set(clock_div_4); + // wait + _delay_loop_2(BOGOMIPS*98/100); + // restore regular clock speed + clock_prescale_set(clock_div_1); + } +} +#else +void delay_4ms(uint8_t ms) { + while(ms-- > 0) { + // wait + _delay_loop_2(BOGOMIPS*398/100); + } +} +#endif +/* +uint8_t nice_delay_4ms(uint8_t ms) { + return nice_delay_ms((uint16_t)ms << 2); +} +*/ + +/* +uint8_t nice_delay_s() { + return nice_delay_4ms(250); +} +*/ + -- cgit v1.2.3