/* * fsm-events.c: Event-handling functions for SpaghettiMonster. * * Copyright (C) 2017 Selene ToyKeeper * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FSM_EVENTS_C #define FSM_EVENTS_C #include void empty_event_sequence() { current_event = EV_none; // 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) { 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 } void append_emission(Event event, uint16_t arg) { uint8_t i; // find last entry for(i=0; (i 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*98/100/4); } //else if (level < HALFSPEED_LEVEL) { // clock_prescale_set(clock_div_2); // _delay_loop_2(BOGOMIPS*98/100/2); //} else { clock_prescale_set(clock_div_1); _delay_loop_2(BOGOMIPS*98/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*98/100/4); // restore regular clock speed clock_prescale_set(clock_div_1); #endif // ifdef USE_RAMPING #else // wait _delay_loop_2(BOGOMIPS*98/100); #endif // ifdef USE_DYNAMIC_UNDERCLOCKING // run pending system processes while we wait handle_deferred_interrupts(); if ((nice_delay_interrupt) || (old_state != current_state)) { return 0; // state changed; abort } // 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); } */ // Call stacked callbacks for the given event until one handles it. uint8_t emit_now(Event event, uint16_t arg) { for(int8_t i=state_stack_len-1; 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) { ticks_since_last_event = arg; emit(current_event, arg); } #endif