1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
/*
* fsm-events.h: 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 <http://www.gnu.org/licenses/>.
*/
#ifndef FSM_EVENTS_H
#define FSM_EVENTS_H
#include <avr/pgmspace.h>
// typedefs
typedef PROGMEM const uint8_t Event;
typedef Event * EventPtr;
typedef struct Emission {
EventPtr event;
uint16_t arg;
} Emission;
#define EVENT_HANDLED 0
#define EVENT_NOT_HANDLED 1
#define MISCHIEF_MANAGED EVENT_HANDLED
#define MISCHIEF_NOT_MANAGED EVENT_NOT_HANDLED
#define EV_MAX_LEN 16
uint8_t current_event[EV_MAX_LEN];
// at 0.016 ms per tick, 255 ticks = 4.08 s
// TODO: 16 bits?
static volatile uint16_t ticks_since_last_event = 0;
// timeout durations in ticks (each tick 1/60th s)
#define HOLD_TIMEOUT 24
#define RELEASE_TIMEOUT 24
#define A_ENTER_STATE 1
#define A_LEAVE_STATE 2
#define A_TICK 3
#define A_PRESS 4
#define A_HOLD 5
#define A_RELEASE 6
#define A_RELEASE_TIMEOUT 7
// TODO: add events for over/under-heat conditions (with parameter for severity)
#define A_OVERHEATING 8
#define A_UNDERHEATING 9
// TODO: add events for low voltage conditions
#define A_VOLTAGE_LOW 10
//#define A_VOLTAGE_CRITICAL 11
#define A_DEBUG 255 // test event for debugging
// Event types
Event EV_debug[] = {
A_DEBUG,
0 } ;
Event EV_enter_state[] = {
A_ENTER_STATE,
0 } ;
Event EV_leave_state[] = {
A_LEAVE_STATE,
0 } ;
Event EV_tick[] = {
A_TICK,
0 } ;
#ifdef USE_LVP
Event EV_voltage_low[] = {
A_VOLTAGE_LOW,
0 } ;
#endif
#ifdef USE_THERMAL_REGULATION
Event EV_temperature_high[] = {
A_OVERHEATING,
0 } ;
Event EV_temperature_low[] = {
A_UNDERHEATING,
0 } ;
#endif
Event EV_click1_press[] = {
A_PRESS,
0 };
// shouldn't normally happen, but UI might reset event while button is down
// so a release with no recorded prior hold could be possible
Event EV_release[] = {
A_RELEASE,
0 };
Event EV_click1_release[] = {
A_PRESS,
A_RELEASE,
0 };
#define EV_1click EV_click1_complete
Event EV_click1_complete[] = {
A_PRESS,
A_RELEASE,
A_RELEASE_TIMEOUT,
0 };
#define EV_hold EV_click1_hold
// FIXME: Should holds use "start+tick" or just "tick" with a tick number?
// Or "start+tick" with a tick number?
Event EV_click1_hold[] = {
A_PRESS,
A_HOLD,
0 };
Event EV_click1_hold_release[] = {
A_PRESS,
A_HOLD,
A_RELEASE,
0 };
Event EV_click2_press[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
0 };
Event EV_click2_hold[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
A_HOLD,
0 };
Event EV_click2_hold_release[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
A_HOLD,
A_RELEASE,
0 };
Event EV_click2_release[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
0 };
#define EV_2clicks EV_click2_complete
Event EV_click2_complete[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
A_RELEASE_TIMEOUT,
0 };
Event EV_click3_press[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
A_PRESS,
0 };
Event EV_click3_release[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
0 };
#define EV_3clicks EV_click3_complete
Event EV_click3_complete[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
A_RELEASE_TIMEOUT,
0 };
#define EV_4clicks EV_click4_complete
Event EV_click4_complete[] = {
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
A_PRESS,
A_RELEASE,
A_RELEASE_TIMEOUT,
0 };
// ... and so on
// A list of button event types for easy iteration
EventPtr event_sequences[] = {
EV_click1_press,
EV_release,
EV_click1_release,
EV_click1_complete,
EV_click1_hold,
EV_click1_hold_release,
EV_click2_press,
EV_click2_hold,
EV_click2_hold_release,
EV_click2_release,
EV_click2_complete,
EV_click3_press,
EV_click3_release,
EV_click3_complete,
EV_click4_complete,
// ...
};
#define events_match(a,b) compare_event_sequences(a,b)
// return 1 if (a == b), 0 otherwise
uint8_t compare_event_sequences(uint8_t *a, const uint8_t *b);
void empty_event_sequence();
uint8_t push_event(uint8_t ev_type);
// uint8_t last_event(uint8_t offset);
inline uint8_t last_event_num();
#define EMISSION_QUEUE_LEN 16
// no comment about "volatile emissions"
volatile Emission emissions[EMISSION_QUEUE_LEN];
void append_emission(EventPtr event, uint16_t arg);
void delete_first_emission();
void process_emissions();
//#define emit_now emit
uint8_t emit_now(EventPtr event, uint16_t arg);
void emit(EventPtr event, uint16_t arg);
void emit_current_event(uint16_t arg);
uint8_t nice_delay_ms(uint16_t ms);
//uint8_t nice_delay_4ms(uint8_t ms);
//uint8_t nice_delay_s();
inline void interrupt_nice_delays();
#endif
|