aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSelene ToyKeeper2018-11-11 05:14:47 -0700
committerSelene ToyKeeper2018-11-11 05:14:47 -0700
commite942fa7c47f446891e3bb0a07316d22cc32c00c2 (patch)
treea74c2cbe1a48554f66d8ca18a0dbc1bf0d69ebdc
parentcalibrated Sofirn SP36 config (diff)
downloadanduril-e942fa7c47f446891e3bb0a07316d22cc32c00c2.tar.gz
anduril-e942fa7c47f446891e3bb0a07316d22cc32c00c2.tar.bz2
anduril-e942fa7c47f446891e3bb0a07316d22cc32c00c2.zip
Rewrote the event system to use a single byte for each event instead of an array of actions.
Not thoroughly tested yet, not done yet, have only updated Anduril to fit, and only partially.
-rw-r--r--spaghetti-monster/anduril/anduril.c116
-rw-r--r--spaghetti-monster/fsm-events.c96
-rw-r--r--spaghetti-monster/fsm-events.h607
-rw-r--r--spaghetti-monster/fsm-pcint.c4
-rw-r--r--spaghetti-monster/fsm-states.c4
-rw-r--r--spaghetti-monster/fsm-states.h6
-rw-r--r--spaghetti-monster/fsm-wdt.c38
7 files changed, 253 insertions, 618 deletions
diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c
index df478ee..de4f996 100644
--- a/spaghetti-monster/anduril/anduril.c
+++ b/spaghetti-monster/anduril/anduril.c
@@ -226,45 +226,45 @@ typedef enum {
// FSM states
-uint8_t off_state(EventPtr event, uint16_t arg);
+uint8_t off_state(Event event, uint16_t arg);
// simple numeric entry config menu
-uint8_t config_state_base(EventPtr event, uint16_t arg,
+uint8_t config_state_base(Event event, uint16_t arg,
uint8_t num_config_steps,
void (*savefunc)());
#define MAX_CONFIG_VALUES 3
uint8_t config_state_values[MAX_CONFIG_VALUES];
// ramping mode and its related config mode
-uint8_t steady_state(EventPtr event, uint16_t arg);
-uint8_t ramp_config_state(EventPtr event, uint16_t arg);
+uint8_t steady_state(Event event, uint16_t arg);
+uint8_t ramp_config_state(Event event, uint16_t arg);
// party and tactical strobes
#ifdef USE_STROBE_STATE
-uint8_t strobe_state(EventPtr event, uint16_t arg);
+uint8_t strobe_state(Event event, uint16_t arg);
#endif
#ifdef USE_BATTCHECK
-uint8_t battcheck_state(EventPtr event, uint16_t arg);
+uint8_t battcheck_state(Event event, uint16_t arg);
#endif
#ifdef USE_THERMAL_REGULATION
-uint8_t tempcheck_state(EventPtr event, uint16_t arg);
-uint8_t thermal_config_state(EventPtr event, uint16_t arg);
+uint8_t tempcheck_state(Event event, uint16_t arg);
+uint8_t thermal_config_state(Event event, uint16_t arg);
#endif
// 1-hour ramp down from low, then automatic off
-uint8_t goodnight_state(EventPtr event, uint16_t arg);
+uint8_t goodnight_state(Event event, uint16_t arg);
// beacon mode and its related config mode
-uint8_t beacon_state(EventPtr event, uint16_t arg);
-uint8_t beacon_config_state(EventPtr event, uint16_t arg);
+uint8_t beacon_state(Event event, uint16_t arg);
+uint8_t beacon_config_state(Event event, uint16_t arg);
// soft lockout
#define MOON_DURING_LOCKOUT_MODE
-uint8_t lockout_state(EventPtr event, uint16_t arg);
+uint8_t lockout_state(Event event, uint16_t arg);
// momentary / signalling mode
-uint8_t momentary_state(EventPtr event, uint16_t arg);
+uint8_t momentary_state(Event event, uint16_t arg);
#ifdef USE_MUGGLE_MODE
// muggle mode, super-simple, hard to exit
-uint8_t muggle_state(EventPtr event, uint16_t arg);
+uint8_t muggle_state(Event event, uint16_t arg);
uint8_t muggle_mode_active = 0;
#endif
// general helper function for config modes
-uint8_t number_entry_state(EventPtr event, uint16_t arg);
+uint8_t number_entry_state(Event event, uint16_t arg);
// return value from number_entry_state()
volatile uint8_t number_entry_value;
@@ -387,7 +387,7 @@ uint8_t triangle_wave(uint8_t phase);
volatile uint8_t beacon_seconds = 2;
-uint8_t off_state(EventPtr event, uint16_t arg) {
+uint8_t off_state(Event event, uint16_t arg) {
// turn emitter off when entering state
if (event == EV_enter_state) {
set_level(0);
@@ -527,7 +527,7 @@ uint8_t off_state(EventPtr event, uint16_t arg) {
}
-uint8_t steady_state(EventPtr event, uint16_t arg) {
+uint8_t steady_state(Event event, uint16_t arg) {
uint8_t mode_min = ramp_smooth_floor;
uint8_t mode_max = ramp_smooth_ceil;
uint8_t ramp_step_size = 1;
@@ -846,7 +846,7 @@ uint8_t steady_state(EventPtr event, uint16_t arg) {
#ifdef USE_STROBE_STATE
-uint8_t strobe_state(EventPtr event, uint16_t arg) {
+uint8_t strobe_state(Event event, uint16_t arg) {
// 'st' reduces ROM size by avoiding access to a volatile var
// (maybe I should just make it nonvolatile?)
strobe_mode_te st = strobe_type;
@@ -1059,7 +1059,7 @@ uint8_t strobe_state(EventPtr event, uint16_t arg) {
#ifdef USE_BATTCHECK
-uint8_t battcheck_state(EventPtr event, uint16_t arg) {
+uint8_t battcheck_state(Event event, uint16_t arg) {
// 1 click: off
if (event == EV_1click) {
set_state(off_state, 0);
@@ -1076,7 +1076,7 @@ uint8_t battcheck_state(EventPtr event, uint16_t arg) {
#ifdef USE_THERMAL_REGULATION
-uint8_t tempcheck_state(EventPtr event, uint16_t arg) {
+uint8_t tempcheck_state(Event event, uint16_t arg) {
// 1 click: off
if (event == EV_1click) {
set_state(off_state, 0);
@@ -1097,7 +1097,7 @@ uint8_t tempcheck_state(EventPtr event, uint16_t arg) {
#endif
-uint8_t beacon_state(EventPtr event, uint16_t arg) {
+uint8_t beacon_state(Event event, uint16_t arg) {
// 1 click: off
if (event == EV_1click) {
set_state(off_state, 0);
@@ -1124,7 +1124,7 @@ uint8_t beacon_state(EventPtr event, uint16_t arg) {
#define GOODNIGHT_TICKS_PER_STEPDOWN (GOODNIGHT_TIME*TICKS_PER_SECOND*60L/GOODNIGHT_LEVEL)
-uint8_t goodnight_state(EventPtr event, uint16_t arg) {
+uint8_t goodnight_state(Event event, uint16_t arg) {
static uint16_t ticks_since_stepdown = 0;
// blink on start
if (event == EV_enter_state) {
@@ -1163,28 +1163,27 @@ uint8_t goodnight_state(EventPtr event, uint16_t arg) {
}
-uint8_t lockout_state(EventPtr event, uint16_t arg) {
+uint8_t lockout_state(Event event, uint16_t arg) {
#ifdef MOON_DURING_LOCKOUT_MODE
// momentary(ish) moon mode during lockout
// not all presses will be counted;
// it depends on what is in the master event_sequences table
- uint8_t last = 0;
- for(uint8_t i=0; pgm_read_byte(event + i) && (i<EV_MAX_LEN); i++)
- last = pgm_read_byte(event + i);
if (arg == 0) { // Only turn on/off when button state changes
- if ((last == A_PRESS) || (last == A_HOLD)) {
- #ifdef LOCKOUT_MOON_LOWEST
- // Use lowest moon configured
- uint8_t lvl = ramp_smooth_floor;
- if (ramp_discrete_floor < lvl) lvl = ramp_discrete_floor;
- set_level(lvl);
- #else
- // Use moon from current ramp
- set_level(nearest_level(1));
- #endif
- }
- else if ((last == A_RELEASE) || (last == A_RELEASE_TIMEOUT)) {
- set_level(0);
+ if (! (event & B_SYSTEM)) { // event is a button click type
+ if (event & B_PRESS) { // button is being held
+ #ifdef LOCKOUT_MOON_LOWEST
+ // Use lowest moon configured
+ uint8_t lvl = ramp_smooth_floor;
+ if (ramp_discrete_floor < lvl) lvl = ramp_discrete_floor;
+ set_level(lvl);
+ #else
+ // Use moon from current ramp
+ set_level(nearest_level(1));
+ #endif
+ }
+ else { // button not being held
+ set_level(0);
+ }
}
}
#endif
@@ -1278,21 +1277,33 @@ uint8_t lockout_state(EventPtr event, uint16_t arg) {
}
-uint8_t momentary_state(EventPtr event, uint16_t arg) {
+uint8_t momentary_state(Event event, uint16_t arg) {
// TODO: momentary strobe here? (for light painting)
- if (event == EV_click1_press) {
+
+ // light up when the button is pressed; go dark otherwise
+ #if 0
+ if ((event ^ B_SYSTEM) & B_PRESS) {
set_level(memorized_level);
- empty_event_sequence(); // don't attempt to parse multiple clicks
return MISCHIEF_MANAGED;
}
-
- else if (event == EV_release) {
+ else if (((event ^ B_SYSTEM) & B_PRESS) == 0) {
set_level(0);
- empty_event_sequence(); // don't attempt to parse multiple clicks
+ empty_event_sequence();
//go_to_standby = 1; // sleep while light is off
- // TODO: lighted button should use lockout config?
return MISCHIEF_MANAGED;
}
+ #else
+ if (! (event & B_SYSTEM)) { // is a button-related event
+ if (event & B_PRESS) { // button is pressed
+ set_level(memorized_level);
+ } else { // button was released
+ set_level(0);
+ empty_event_sequence();
+ //go_to_standby = 1; // sleep while light is off
+ }
+ return MISCHIEF_MANAGED;
+ }
+ #endif
// Sleep, dammit! (but wait a few seconds first)
// (because standby mode uses such little power that it can interfere
@@ -1302,6 +1313,7 @@ uint8_t momentary_state(EventPtr event, uint16_t arg) {
else if ((event == EV_tick) && (actual_level == 0)) {
if (arg > TICKS_PER_SECOND*15) { // sleep after 15 seconds
go_to_standby = 1; // sleep while light is off
+ // TODO: lighted button should use lockout config?
}
return MISCHIEF_MANAGED;
}
@@ -1311,7 +1323,7 @@ uint8_t momentary_state(EventPtr event, uint16_t arg) {
#ifdef USE_MUGGLE_MODE
-uint8_t muggle_state(EventPtr event, uint16_t arg) {
+uint8_t muggle_state(Event event, uint16_t arg) {
static int8_t ramp_direction;
static int8_t muggle_off_mode;
@@ -1461,7 +1473,7 @@ uint8_t muggle_state(EventPtr event, uint16_t arg) {
// ask the user for a sequence of numbers, then save them and return to caller
-uint8_t config_state_base(EventPtr event, uint16_t arg,
+uint8_t config_state_base(Event event, uint16_t arg,
uint8_t num_config_steps,
void (*savefunc)()) {
static uint8_t config_step;
@@ -1520,7 +1532,7 @@ void ramp_config_save() {
}
}
-uint8_t ramp_config_state(EventPtr event, uint16_t arg) {
+uint8_t ramp_config_state(Event event, uint16_t arg) {
uint8_t num_config_steps;
num_config_steps = 2 + ramp_style;
return config_state_base(event, arg,
@@ -1548,7 +1560,7 @@ void thermal_config_save() {
if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL;
}
-uint8_t thermal_config_state(EventPtr event, uint16_t arg) {
+uint8_t thermal_config_state(Event event, uint16_t arg) {
return config_state_base(event, arg,
2, thermal_config_save);
}
@@ -1563,13 +1575,13 @@ void beacon_config_save() {
}
}
-uint8_t beacon_config_state(EventPtr event, uint16_t arg) {
+uint8_t beacon_config_state(Event event, uint16_t arg) {
return config_state_base(event, arg,
1, beacon_config_save);
}
-uint8_t number_entry_state(EventPtr event, uint16_t arg) {
+uint8_t number_entry_state(Event event, uint16_t arg) {
static uint8_t value;
static uint8_t blinks_left;
static uint8_t entry_step;
diff --git a/spaghetti-monster/fsm-events.c b/spaghetti-monster/fsm-events.c
index ee7bc97..091d4cf 100644
--- a/spaghetti-monster/fsm-events.c
+++ b/spaghetti-monster/fsm-events.c
@@ -20,25 +20,8 @@
#ifndef FSM_EVENTS_C
#define FSM_EVENTS_C
-// TODO: maybe compare events by number instead of pointer?
-// (number = index in event types array)
-// (comparison would use full event content, but send off index to callbacks)
-// (saves space by using uint8_t instead of a pointer)
-// (also eliminates the need to duplicate single-entry events like for voltage or timer tick)
-
-// return 1 if (a == b), 0 otherwise
-uint8_t compare_event_sequences(uint8_t *a, const uint8_t *b) {
- for(uint8_t i=0; (i<EV_MAX_LEN) && (a[i] == pgm_read_byte(b+i)); i++) {
- // end of zero-terminated sequence
- if (a[i] == 0) return 1;
- }
- // if we ever fall out, that means something was different
- // (or the sequence is too long)
- return 0;
-}
-
void empty_event_sequence() {
- for(uint8_t i=0; i<EV_MAX_LEN; i++) current_event[i] = 0;
+ current_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:
@@ -49,46 +32,41 @@ void empty_event_sequence() {
uint8_t push_event(uint8_t ev_type) {
ticks_since_last_event = 0; // something happened
- uint8_t i;
- //uint8_t prev_event = 0; // never push the same event twice in a row
- for(i=0; current_event[i] && (i<EV_MAX_LEN); i++) {
- // this doesn't actually seem to be necessary any more...
- //prev_event = current_event[i];
+
+ // 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-1)) {
+ current_event ++;
+ return 1; // event pushed
+ }
+ return 0; // maximum number of clicks reached
}
- //if ((i < EV_MAX_LEN) && (prev_event != ev_type)) {
- //if (prev_event != ev_type) {
- if (i < EV_MAX_LEN) {
- current_event[i] = ev_type;
+ // 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
- } else {
- // TODO: ... something?
}
- return 0; // no event pushed
-}
-// find and return last action in the current event sequence
-/*
-uint8_t last_event(uint8_t offset) {
- uint8_t i;
- for(i=0; current_event[i] && (i<EV_MAX_LEN); i++);
- if (i == EV_MAX_LEN) return current_event[EV_MAX_LEN-offset];
- else if (i >= offset) return current_event[i-offset];
- return 0;
-}
-*/
+ return 0; // unexpected event type
-inline uint8_t last_event_num() {
- uint8_t i;
- for(i=0; current_event[i] && (i<EV_MAX_LEN); i++);
- return i;
}
-void append_emission(EventPtr event, uint16_t arg) {
+void append_emission(Event event, uint16_t arg) {
uint8_t i;
// find last entry
for(i=0;
- (i<EMISSION_QUEUE_LEN) && (emissions[i].event != NULL);
+ (i<EMISSION_QUEUE_LEN) && (emissions[i].event != EV_none);
i++) { }
// add new entry
if (i < EMISSION_QUEUE_LEN) {
@@ -105,12 +83,12 @@ void delete_first_emission() {
emissions[i].event = emissions[i+1].event;
emissions[i].arg = emissions[i+1].arg;
}
- emissions[i].event = NULL;
+ emissions[i].event = EV_none;
emissions[i].arg = 0;
}
void process_emissions() {
- while (emissions[0].event != NULL) {
+ while (emissions[0].event != EV_none) {
emit_now(emissions[0].event, emissions[0].arg);
delete_first_emission();
}
@@ -202,7 +180,7 @@ uint8_t nice_delay_s() {
*/
// Call stacked callbacks for the given event until one handles it.
-uint8_t emit_now(EventPtr event, uint16_t arg) {
+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;
@@ -210,26 +188,10 @@ uint8_t emit_now(EventPtr event, uint16_t arg) {
return 1; // event not handled
}
-void emit(EventPtr event, uint16_t arg) {
+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);
}
-// Search the pre-defined event list for one matching what the user just did,
-// and emit it if one was found.
-void emit_current_event(uint16_t arg) {
- //uint8_t err = 1;
- for (uint8_t i=0; i<(sizeof(event_sequences)/sizeof(EventPtr)); i++) {
- if (events_match(current_event, event_sequences[i])) {
- //DEBUG_FLASH;
- //err = emit(event_sequences[i], arg);
- //return err;
- emit(event_sequences[i], arg);
- return;
- }
- }
- //return err;
-}
-
#endif
diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h
index 0212c2c..d838800 100644
--- a/spaghetti-monster/fsm-events.h
+++ b/spaghetti-monster/fsm-events.h
@@ -23,10 +23,9 @@
#include <avr/pgmspace.h>
// typedefs
-typedef PROGMEM const uint8_t Event;
-typedef Event * EventPtr;
+typedef uint8_t Event;
typedef struct Emission {
- EventPtr event;
+ Event event;
uint16_t arg;
} Emission;
@@ -36,11 +35,11 @@ typedef struct Emission {
#define MISCHIEF_NOT_MANAGED EVENT_NOT_HANDLED
#ifndef MAX_CLICKS
-#define MAX_CLICKS 4
+#define MAX_CLICKS 15
#endif
#define EV_MAX_LEN ((MAX_CLICKS*2)+3)
-uint8_t current_event[EV_MAX_LEN];
+Event current_event;
// at 0.016 ms per tick, 255 ticks = 4.08 s
static volatile uint16_t ticks_since_last_event = 0;
@@ -52,509 +51,175 @@ static volatile uint16_t ticks_since_last_event = 0;
#define RELEASE_TIMEOUT 24
#endif
-#define A_ENTER_STATE 1
-#define A_LEAVE_STATE 2
-#define A_REENTER_STATE 3
-#define A_TICK 4
-#define A_SLEEP_TICK 5
-#define A_PRESS 6
-#define A_HOLD 7
-#define A_RELEASE 8
-#define A_RELEASE_TIMEOUT 9
-#define A_OVERHEATING 10
-#define A_UNDERHEATING 11
-#define A_VOLTAGE_LOW 12
-//#define A_VOLTAGE_CRITICAL 13
-#define A_DEBUG 255 // test event for debugging
+/* Event structure
+ * Bit 7: 1 for a button input event, 0 for all others.
+ * If bit 7 is 1:
+ * Bits 0,1,2,3: Click counter. Up to 15 clicks.
+ * Bit 4: 1 for a "press" event, 0 for a "release" event.
+ * Bit 5: 1 for a "hold" event, 0 otherwise.
+ * Bit 6: 1 for a "timeout" event, 0 otherwise.
+ * If bit 7 is 0:
+ * Not yet defined.
+ */
+
+// event masks / bits
+#define B_SYSTEM 0b10000000
+#define B_CLICK 0b00000000
+#define B_TIMEOUT 0b01000000
+#define B_HOLD 0b00100000
+#define B_PRESS 0b00010000
+#define B_RELEASE 0b00000000
+#define B_COUNT 0b00001111
+#define B_FLAGS 0b11110000
// Event types
-// TODO: make these progmem-only?
-Event EV_debug[] = {
- A_DEBUG,
- 0 } ;
-Event EV_enter_state[] = {
- A_ENTER_STATE,
- 0 } ;
-Event EV_leave_state[] = {
- A_LEAVE_STATE,
- 0 } ;
-Event EV_reenter_state[] = {
- A_REENTER_STATE,
- 0 } ;
-Event EV_tick[] = {
- A_TICK,
- 0 } ;
+#define EV_debug (B_SYSTEM|0b01111111)
+#define EV_enter_state (B_SYSTEM|0b00001000)
+#define EV_leave_state (B_SYSTEM|0b00001001)
+#define EV_reenter_state (B_SYSTEM|0b00001010)
+#define EV_tick (B_SYSTEM|0b00000001)
#ifdef TICK_DURING_STANDBY
-Event EV_sleep_tick[] = {
- A_SLEEP_TICK,
- 0 } ;
+#define EV_sleep_tick (B_SYSTEM|0b00000011)
#endif
#ifdef USE_LVP
-Event EV_voltage_low[] = {
- A_VOLTAGE_LOW,
- 0 } ;
+#define EV_voltage_low (B_SYSTEM|0b00000100)
#endif
#ifdef USE_THERMAL_REGULATION
-Event EV_temperature_high[] = {
- A_OVERHEATING,
- 0 } ;
-Event EV_temperature_low[] = {
- A_UNDERHEATING,
- 0 } ;
+#define EV_temperature_high (B_SYSTEM|0b00000101)
+#define EV_temperature_low (B_SYSTEM|0b00000110)
#endif
-Event EV_click1_press[] = {
- A_PRESS,
- 0 };
+
+#define EV_none 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_release (B_CLICK|B_RELEASE|0)
+
+#define EV_click1_press (B_CLICK|B_PRESS|1)
+#define EV_click1_hold (B_CLICK|B_HOLD|B_PRESS|1)
+#define EV_click1_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|1)
+#define EV_click1_release (B_CLICK|B_RELEASE|1)
+#define EV_click1_complete (B_CLICK|B_TIMEOUT|1)
#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 };
-#if MAX_CLICKS >= 2
-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_click2_press (B_CLICK|B_PRESS|2)
+#define EV_click2_hold (B_CLICK|B_HOLD|B_PRESS|2)
+#define EV_click2_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|2)
+#define EV_click2_release (B_CLICK|B_RELEASE|2)
+#define EV_click2_complete (B_CLICK|B_TIMEOUT|2)
#define EV_2clicks EV_click2_complete
-Event EV_click2_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif // MAX_CLICKS >= 2
-#if MAX_CLICKS >= 3
-Event EV_click3_press[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- 0 };
-Event EV_click3_hold[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_HOLD,
- 0 };
-Event EV_click3_hold_release[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_HOLD,
- A_RELEASE,
- 0 };
-Event EV_click3_release[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- 0 };
+
+#define EV_click3_press (B_CLICK|B_PRESS|3)
+#define EV_click3_hold (B_CLICK|B_HOLD|B_PRESS|3)
+#define EV_click3_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|3)
+#define EV_click3_release (B_CLICK|B_RELEASE|3)
+#define EV_click3_complete (B_CLICK|B_TIMEOUT|3)
#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 };
-#endif // MAX_CLICKS >= 3
-#if MAX_CLICKS >= 4
+
+#define EV_click4_press (B_CLICK|B_PRESS|4)
+#define EV_click4_hold (B_CLICK|B_HOLD|B_PRESS|4)
+#define EV_click4_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|4)
+#define EV_click4_release (B_CLICK|B_RELEASE|4)
+#define EV_click4_complete (B_CLICK|B_TIMEOUT|4)
#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 };
-#endif
-#if MAX_CLICKS >= 5
+
+#define EV_click5_press (B_CLICK|B_PRESS|5)
+#define EV_click5_hold (B_CLICK|B_HOLD|B_PRESS|5)
+#define EV_click5_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|5)
+#define EV_click5_release (B_CLICK|B_RELEASE|5)
+#define EV_click5_complete (B_CLICK|B_TIMEOUT|5)
#define EV_5clicks EV_click5_complete
-Event EV_click5_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 6
+
+#define EV_click6_press (B_CLICK|B_PRESS|6)
+#define EV_click6_hold (B_CLICK|B_HOLD|B_PRESS|6)
+#define EV_click6_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|6)
+#define EV_click6_release (B_CLICK|B_RELEASE|6)
+#define EV_click6_complete (B_CLICK|B_TIMEOUT|6)
#define EV_6clicks EV_click6_complete
-Event EV_click6_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 7
+
+#define EV_click7_press (B_CLICK|B_PRESS|7)
+#define EV_click7_hold (B_CLICK|B_HOLD|B_PRESS|7)
+#define EV_click7_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|7)
+#define EV_click7_release (B_CLICK|B_RELEASE|7)
+#define EV_click7_complete (B_CLICK|B_TIMEOUT|7)
#define EV_7clicks EV_click7_complete
-Event EV_click7_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 8
+
+#define EV_click8_press (B_CLICK|B_PRESS|8)
+#define EV_click8_hold (B_CLICK|B_HOLD|B_PRESS|8)
+#define EV_click8_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|8)
+#define EV_click8_release (B_CLICK|B_RELEASE|8)
+#define EV_click8_complete (B_CLICK|B_TIMEOUT|8)
#define EV_8clicks EV_click8_complete
-Event EV_click8_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 9
+
+#define EV_click9_press (B_CLICK|B_PRESS|9)
+#define EV_click9_hold (B_CLICK|B_HOLD|B_PRESS|9)
+#define EV_click9_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|9)
+#define EV_click9_release (B_CLICK|B_RELEASE|9)
+#define EV_click9_complete (B_CLICK|B_TIMEOUT|9)
#define EV_9clicks EV_click9_complete
-Event EV_click9_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 10
+
+#define EV_click10_press (B_CLICK|B_PRESS|10)
+#define EV_click10_hold (B_CLICK|B_HOLD|B_PRESS|10)
+#define EV_click10_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|10)
+#define EV_click10_release (B_CLICK|B_RELEASE|10)
+#define EV_click10_complete (B_CLICK|B_TIMEOUT|10)
#define EV_10clicks EV_click10_complete
-Event EV_click10_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 11
+
+#define EV_click11_press (B_CLICK|B_PRESS|11)
+#define EV_click11_hold (B_CLICK|B_HOLD|B_PRESS|11)
+#define EV_click11_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|11)
+#define EV_click11_release (B_CLICK|B_RELEASE|11)
+#define EV_click11_complete (B_CLICK|B_TIMEOUT|11)
#define EV_11clicks EV_click11_complete
-Event EV_click11_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 12
+
+#define EV_click12_press (B_CLICK|B_PRESS|12)
+#define EV_click12_hold (B_CLICK|B_HOLD|B_PRESS|12)
+#define EV_click12_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|12)
+#define EV_click12_release (B_CLICK|B_RELEASE|12)
+#define EV_click12_complete (B_CLICK|B_TIMEOUT|12)
#define EV_12clicks EV_click12_complete
-Event EV_click12_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 13
+
+#define EV_click13_press (B_CLICK|B_PRESS|13)
+#define EV_click13_hold (B_CLICK|B_HOLD|B_PRESS|13)
+#define EV_click13_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|13)
+#define EV_click13_release (B_CLICK|B_RELEASE|13)
+#define EV_click13_complete (B_CLICK|B_TIMEOUT|13)
#define EV_13clicks EV_click13_complete
-Event EV_click13_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-#if MAX_CLICKS >= 14
+
+#define EV_click14_press (B_CLICK|B_PRESS|14)
+#define EV_click14_hold (B_CLICK|B_HOLD|B_PRESS|14)
+#define EV_click14_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|14)
+#define EV_click14_release (B_CLICK|B_RELEASE|14)
+#define EV_click14_complete (B_CLICK|B_TIMEOUT|14)
#define EV_14clicks EV_click14_complete
-Event EV_click14_complete[] = {
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_PRESS,
- A_RELEASE,
- A_RELEASE_TIMEOUT,
- 0 };
-#endif
-// ... and so on
-
-// A list of button event types for easy iteration
-// TODO: make this progmem-only?
-EventPtr event_sequences[] = {
- EV_click1_press,
- EV_release,
- EV_click1_release,
- EV_click1_complete,
- EV_click1_hold,
- EV_click1_hold_release,
- #if MAX_CLICKS >= 2
- EV_click2_press,
- EV_click2_hold,
- EV_click2_hold_release,
- EV_click2_release,
- EV_click2_complete,
- #endif
- #if MAX_CLICKS >= 3
- EV_click3_press,
- EV_click3_hold,
- EV_click3_hold_release,
- EV_click3_release,
- EV_click3_complete,
- #endif
- #if MAX_CLICKS >= 4
- EV_click4_complete,
- #endif
- #if MAX_CLICKS >= 5
- EV_click5_complete,
- #endif
- #if MAX_CLICKS >= 6
- EV_click6_complete,
- #endif
- #if MAX_CLICKS >= 7
- EV_click7_complete,
- #endif
- #if MAX_CLICKS >= 8
- EV_click8_complete,
- #endif
- #if MAX_CLICKS >= 9
- EV_click9_complete,
- #endif
- #if MAX_CLICKS >= 10
- EV_click10_complete,
- #endif
- #if MAX_CLICKS >= 11
- EV_click11_complete,
- #endif
- #if MAX_CLICKS >= 12
- EV_click12_complete,
- #endif
- #if MAX_CLICKS >= 13
- EV_click13_complete,
- #endif
- #if MAX_CLICKS >= 14
- EV_click14_complete,
- #endif
- // ...
-};
-
-#define events_match(a,b) compare_event_sequences(a,b)
+
+#define EV_click15_press (B_CLICK|B_PRESS|15)
+#define EV_click15_hold (B_CLICK|B_HOLD|B_PRESS|15)
+#define EV_click15_hold_release (B_CLICK|B_TIMEOUT|B_HOLD|B_RELEASE|15)
+#define EV_click15_release (B_CLICK|B_RELEASE|15)
+#define EV_click15_complete (B_CLICK|B_TIMEOUT|15)
+#define EV_15clicks EV_click15_complete
+
+
+#define events_match(a,b) (a == b)
// return 1 if (a == b), 0 otherwise
-uint8_t compare_event_sequences(uint8_t *a, const uint8_t *b);
+#define compare_event_sequences(a,b) (a == 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 append_emission(Event 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 emit_now(Event event, uint16_t arg);
+void emit(Event event, uint16_t arg);
+#define emit_current_event(arg) emit(current_event, arg)
uint8_t nice_delay_ms(uint16_t ms);
//uint8_t nice_delay_4ms(uint8_t ms);
diff --git a/spaghetti-monster/fsm-pcint.c b/spaghetti-monster/fsm-pcint.c
index a79572d..acb627d 100644
--- a/spaghetti-monster/fsm-pcint.c
+++ b/spaghetti-monster/fsm-pcint.c
@@ -75,9 +75,9 @@ void PCINT_inner(uint8_t pressed) {
uint8_t pushed;
if (pressed) {
- pushed = push_event(A_PRESS);
+ pushed = push_event(B_PRESS);
} else {
- pushed = push_event(A_RELEASE);
+ pushed = push_event(B_RELEASE);
}
// check if sequence matches any defined sequences
diff --git a/spaghetti-monster/fsm-states.c b/spaghetti-monster/fsm-states.c
index 09ae804..f91dc4b 100644
--- a/spaghetti-monster/fsm-states.c
+++ b/spaghetti-monster/fsm-states.c
@@ -32,7 +32,7 @@
// TODO: function to call stacked callbacks until one returns "handled"
void _set_state(StatePtr new_state, uint16_t arg,
- EventPtr exit_event, EventPtr enter_event) {
+ Event exit_event, Event enter_event) {
// call old state-exit hook (don't use stack)
if (current_state != NULL) current_state(exit_event, arg);
// set new state
@@ -82,7 +82,7 @@ uint8_t set_state(StatePtr new_state, uint16_t arg) {
#ifndef DONT_USE_DEFAULT_STATE
// bottom state on stack
// handles default actions for LVP, thermal regulation, etc
-uint8_t default_state(EventPtr event, uint16_t arg) {
+uint8_t default_state(Event event, uint16_t arg) {
if (0) {} // this should get compiled out
#ifdef USE_LVP
diff --git a/spaghetti-monster/fsm-states.h b/spaghetti-monster/fsm-states.h
index 6e4a2a0..7d9361b 100644
--- a/spaghetti-monster/fsm-states.h
+++ b/spaghetti-monster/fsm-states.h
@@ -23,7 +23,7 @@
#include "fsm-adc.h"
// typedefs
-typedef uint8_t State(EventPtr event, uint16_t arg);
+typedef uint8_t State(Event event, uint16_t arg);
typedef State * StatePtr;
// top of the stack
@@ -36,12 +36,12 @@ StatePtr state_stack[STATE_STACK_SIZE];
uint8_t state_stack_len = 0;
void _set_state(StatePtr new_state, uint16_t arg,
- EventPtr exit_event, EventPtr enter_event);
+ Event exit_event, Event enter_event);
int8_t push_state(StatePtr new_state, uint16_t arg);
StatePtr pop_state();
uint8_t set_state(StatePtr new_state, uint16_t arg);
#ifndef DONT_USE_DEFAULT_STATE
-uint8_t default_state(EventPtr event, uint16_t arg);
+uint8_t default_state(Event event, uint16_t arg);
#endif
#endif
diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c
index e8419bc..cfff1fa 100644
--- a/spaghetti-monster/fsm-wdt.c
+++ b/spaghetti-monster/fsm-wdt.c
@@ -85,15 +85,8 @@ ISR(WDT_vect) {
// append timeout to current event sequence, then
// send event to current state callback
- // preload recent events
- uint8_t le_num = last_event_num();
- uint8_t last_event = 0;
- uint8_t prev_event = 0;
- if (le_num >= 1) last_event = current_event[le_num-1];
- if (le_num >= 2) prev_event = current_event[le_num-2];
-
// callback on each timer tick
- if (last_event == A_HOLD) {
+ if ((current_event & B_FLAGS) == (B_HOLD | B_PRESS)) {
emit(EV_tick, 0); // override tick counter while holding button
}
else {
@@ -101,29 +94,32 @@ ISR(WDT_vect) {
}
// user held button long enough to count as a long click?
- if (last_event == A_PRESS) {
- if (ticks_since_last_event >= HOLD_TIMEOUT) {
- push_event(A_HOLD);
- emit_current_event(0);
+ if (current_event & B_PRESS) {
+ // during a "hold", send a hold event each tick, with a timer
+ if (current_event & B_HOLD) {
+ emit_current_event(ticks_since_last_event);
+ }
+ // has button been down long enough to become a "hold"?
+ else {
+ if (ticks_since_last_event >= HOLD_TIMEOUT) {
+ current_event |= B_HOLD;
+ emit_current_event(0);
+ }
}
}
- // user is still holding button, so tick
- else if (last_event == A_HOLD) {
- emit_current_event(ticks_since_last_event);
- }
-
- // detect completed button presses with expired timeout
- else if (last_event == A_RELEASE) {
+ // event in progress, but button not currently down
+ else if (current_event) {
+ // "hold" event just ended
// no timeout required when releasing a long-press
// TODO? move this logic to PCINT() and simplify things here?
- if (prev_event == A_HOLD) {
+ if (current_event & B_HOLD) {
//emit_current_event(0); // should have been emitted by PCINT
empty_event_sequence();
}
// end and clear event after release timeout
else if (ticks_since_last_event >= RELEASE_TIMEOUT) {
- push_event(A_RELEASE_TIMEOUT);
+ current_event |= B_TIMEOUT;
emit_current_event(0);
empty_event_sequence();
}