2
* fsm-events.c: Event-handling functions for SpaghettiMonster.
4
* Copyright (C) 2017 Selene Scriven
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1
// fsm-events.c: Event-handling functions for SpaghettiMonster.
2
// Copyright (C) 2017-2023 Selene ToyKeeper
3
// SPDX-License-Identifier: GPL-3.0-or-later
23
7
#include <util/delay_basic.h>
10
void append_emission(Event event, uint16_t arg) {
14
(i<EMISSION_QUEUE_LEN) && (emissions[i].event != EV_none);
17
if (i < EMISSION_QUEUE_LEN) {
18
emissions[i].event = event;
19
emissions[i].arg = arg;
21
// TODO: if queue full, what should we do?
25
void delete_first_emission() {
27
for(i=0; i<EMISSION_QUEUE_LEN-1; i++) {
28
emissions[i].event = emissions[i+1].event;
29
emissions[i].arg = emissions[i+1].arg;
31
emissions[i].event = EV_none;
35
void process_emissions() {
36
while (emissions[0].event != EV_none) {
37
emit_now(emissions[0].event, emissions[0].arg);
38
delete_first_emission();
42
// Call stacked callbacks for the given event until one handles it.
43
uint8_t emit_now(Event event, uint16_t arg) {
44
for(int8_t i=state_stack_len-1; i>=0; i--) {
45
uint8_t err = state_stack[i](event, arg);
48
return 1; // event not handled
51
void emit(Event event, uint16_t arg) {
52
// add this event to the queue for later,
53
// so we won't use too much time during an interrupt
54
append_emission(event, arg);
57
void emit_current_event(uint16_t arg) {
58
emit(current_event, arg);
26
61
void empty_event_sequence() {
27
62
current_event = EV_none;
63
ticks_since_last_event = 0;
28
64
// when the user completes an input sequence, interrupt any running timers
29
65
// to cancel any delays currently in progress
30
66
// This eliminates a whole bunch of extra code:
33
69
interrupt_nice_delays();
36
uint8_t push_event(uint8_t ev_type) {
37
ticks_since_last_event = 0; // something happened
72
uint8_t push_event(uint8_t ev_type) { // only for use by PCINT_inner()
73
// don't do this here; do it in PCINT_inner() instead
74
//ticks_since_last_event = 0; // something happened
39
76
// only click events are sent to this function
40
77
current_event |= B_CLICK;
63
100
return 0; // unexpected event type
68
void append_emission(Event event, uint16_t arg) {
72
(i<EMISSION_QUEUE_LEN) && (emissions[i].event != EV_none);
75
if (i < EMISSION_QUEUE_LEN) {
76
emissions[i].event = event;
77
emissions[i].arg = arg;
79
// TODO: if queue full, what should we do?
83
void delete_first_emission() {
85
for(i=0; i<EMISSION_QUEUE_LEN-1; i++) {
86
emissions[i].event = emissions[i+1].event;
87
emissions[i].arg = emissions[i+1].arg;
89
emissions[i].event = EV_none;
93
void process_emissions() {
94
while (emissions[0].event != EV_none) {
95
emit_now(emissions[0].event, emissions[0].arg);
96
delete_first_emission();
100
104
// explicitly interrupt these "nice" delays
101
105
volatile uint8_t nice_delay_interrupt = 0;
117
120
while(ms-- > 0) {
121
if (nice_delay_interrupt) {
118
125
#ifdef USE_DYNAMIC_UNDERCLOCKING
119
126
#ifdef USE_RAMPING
120
127
uint8_t level = actual_level; // volatile, avoid repeat access
121
128
if (level < QUARTERSPEED_LEVEL) {
122
129
clock_prescale_set(clock_div_4);
123
_delay_loop_2(BOGOMIPS*90/100/4);
130
_delay_loop_2(BOGOMIPS*DELAY_FACTOR/100/4);
125
132
//else if (level < HALFSPEED_LEVEL) {
126
133
// clock_prescale_set(clock_div_2);
136
143
// underclock MCU to save power
137
144
clock_prescale_set(clock_div_4);
139
_delay_loop_2(BOGOMIPS*90/100/4);
146
_delay_loop_2(BOGOMIPS*DELAY_FACTOR/100/4);
140
147
// restore regular clock speed
141
148
clock_prescale_set(clock_div_1);
142
149
#endif // ifdef USE_RAMPING
145
_delay_loop_2(BOGOMIPS*90/100);
152
_delay_loop_2(BOGOMIPS*DELAY_FACTOR/100);
146
153
#endif // ifdef USE_DYNAMIC_UNDERCLOCKING
148
155
// run pending system processes while we wait
149
156
handle_deferred_interrupts();
151
if ((nice_delay_interrupt) || (old_state != current_state)) {
152
return 0; // state changed; abort
154
158
// handle events only afterward, so that any collapsed delays will
155
159
// finish running the UI's loop() code before taking any further actions
156
160
// (this helps make sure code runs in the correct order)
195
// Call stacked callbacks for the given event until one handles it.
196
uint8_t emit_now(Event event, uint16_t arg) {
197
for(int8_t i=state_stack_len-1; i>=0; i--) {
198
uint8_t err = state_stack[i](event, arg);
201
return 1; // event not handled
204
void emit(Event event, uint16_t arg) {
205
// add this event to the queue for later,
206
// so we won't use too much time during an interrupt
207
append_emission(event, arg);
210
void emit_current_event(uint16_t arg) {
211
ticks_since_last_event = arg;
212
emit(current_event, arg);