~toykeeper/flashlight-firmware/fsm

« back to all changes in this revision

Viewing changes to ToyKeeper/spaghetti-monster/fsm-events.c

  • Committer: Selene ToyKeeper
  • Date: 2023-11-04 15:09:10 UTC
  • mfrom: (483.1.175 anduril2)
  • Revision ID: bzr@toykeeper.net-20231104150910-ddd3afw4nhfvof2l
merged anduril2 branch -> fsm, with *years* of changes
(this also means this code is now Anduril 2 instead of Anduril 1)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * fsm-events.c: Event-handling functions for SpaghettiMonster.
3
 
 *
4
 
 * Copyright (C) 2017 Selene Scriven
5
 
 *
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.
10
 
 *
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.
15
 
 *
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/>.
18
 
 */
 
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
19
4
 
20
 
#ifndef FSM_EVENTS_C
21
 
#define FSM_EVENTS_C
 
5
#pragma once
22
6
 
23
7
#include <util/delay_basic.h>
24
8
 
25
9
 
 
10
void append_emission(Event event, uint16_t arg) {
 
11
    uint8_t i;
 
12
    // find last entry
 
13
    for(i=0;
 
14
        (i<EMISSION_QUEUE_LEN) && (emissions[i].event != EV_none);
 
15
        i++) { }
 
16
    // add new entry
 
17
    if (i < EMISSION_QUEUE_LEN) {
 
18
        emissions[i].event = event;
 
19
        emissions[i].arg = arg;
 
20
    } else {
 
21
        // TODO: if queue full, what should we do?
 
22
    }
 
23
}
 
24
 
 
25
void delete_first_emission() {
 
26
    uint8_t i;
 
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;
 
30
    }
 
31
    emissions[i].event = EV_none;
 
32
    emissions[i].arg = 0;
 
33
}
 
34
 
 
35
void process_emissions() {
 
36
    while (emissions[0].event != EV_none) {
 
37
        emit_now(emissions[0].event, emissions[0].arg);
 
38
        delete_first_emission();
 
39
    }
 
40
}
 
41
 
 
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);
 
46
        if (! err) return 0;
 
47
    }
 
48
    return 1;  // event not handled
 
49
}
 
50
 
 
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);
 
55
}
 
56
 
 
57
void emit_current_event(uint16_t arg) {
 
58
    emit(current_event, arg);
 
59
}
 
60
 
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();
34
70
}
35
71
 
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
38
75
 
39
76
    // only click events are sent to this function
40
77
    current_event |= B_CLICK;
61
98
    }
62
99
 
63
100
    return 0;  // unexpected event type
64
 
 
65
 
}
66
 
 
67
 
 
68
 
void append_emission(Event event, uint16_t arg) {
69
 
    uint8_t i;
70
 
    // find last entry
71
 
    for(i=0;
72
 
        (i<EMISSION_QUEUE_LEN) && (emissions[i].event != EV_none);
73
 
        i++) { }
74
 
    // add new entry
75
 
    if (i < EMISSION_QUEUE_LEN) {
76
 
        emissions[i].event = event;
77
 
        emissions[i].arg = arg;
78
 
    } else {
79
 
        // TODO: if queue full, what should we do?
80
 
    }
81
 
}
82
 
 
83
 
void delete_first_emission() {
84
 
    uint8_t i;
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;
88
 
    }
89
 
    emissions[i].event = EV_none;
90
 
    emissions[i].arg = 0;
91
 
}
92
 
 
93
 
void process_emissions() {
94
 
    while (emissions[0].event != EV_none) {
95
 
        emit_now(emissions[0].event, emissions[0].arg);
96
 
        delete_first_emission();
97
 
    }
98
 
}
 
101
}
 
102
 
99
103
 
100
104
// explicitly interrupt these "nice" delays
101
105
volatile uint8_t nice_delay_interrupt = 0;
106
110
//   0: state changed
107
111
//   1: normal completion
108
112
uint8_t nice_delay_ms(uint16_t ms) {
109
 
    StatePtr old_state = current_state;
110
113
    /*  // delay_zero() implementation
111
114
    if (ms == 0) {
112
115
        CLKPR = 1<<CLKPCE; CLKPR = 0;  // full speed
115
118
    }
116
119
    */
117
120
    while(ms-- > 0) {
 
121
        if (nice_delay_interrupt) {
 
122
            return 0;
 
123
        }
 
124
 
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);
124
131
        }
125
132
        //else if (level < HALFSPEED_LEVEL) {
126
133
        //    clock_prescale_set(clock_div_2);
128
135
        //}
129
136
        else {
130
137
            clock_prescale_set(clock_div_1);
131
 
            _delay_loop_2(BOGOMIPS*90/100);
 
138
            _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100);
132
139
        }
133
140
        // restore regular clock speed
134
141
        clock_prescale_set(clock_div_1);
136
143
        // underclock MCU to save power
137
144
        clock_prescale_set(clock_div_4);
138
145
        // wait
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
143
150
        #else
144
151
        // wait
145
 
        _delay_loop_2(BOGOMIPS*90/100);
 
152
        _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100);
146
153
        #endif  // ifdef USE_DYNAMIC_UNDERCLOCKING
147
154
 
148
155
        // run pending system processes while we wait
149
156
        handle_deferred_interrupts();
150
157
 
151
 
        if ((nice_delay_interrupt) || (old_state != current_state)) {
152
 
            return 0;  // state changed; abort
153
 
        }
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)
192
196
}
193
197
*/
194
198
 
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);
199
 
        if (! err) return 0;
200
 
    }
201
 
    return 1;  // event not handled
202
 
}
203
 
 
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);
208
 
}
209
 
 
210
 
void emit_current_event(uint16_t arg) {
211
 
    ticks_since_last_event = arg;
212
 
    emit(current_event, arg);
213
 
}
214
 
 
215
 
#endif