aboutsummaryrefslogtreecommitdiff
path: root/spaghetti-monster
diff options
context:
space:
mode:
Diffstat (limited to 'spaghetti-monster')
-rw-r--r--spaghetti-monster/baton.c2
-rw-r--r--spaghetti-monster/fsm-events.c23
-rw-r--r--spaghetti-monster/fsm-events.h3
-rw-r--r--spaghetti-monster/fsm-main.c7
-rw-r--r--spaghetti-monster/momentary.c3
-rw-r--r--spaghetti-monster/ramping-ui.c77
-rw-r--r--spaghetti-monster/spaghetti-monster.h4
7 files changed, 84 insertions, 35 deletions
diff --git a/spaghetti-monster/baton.c b/spaghetti-monster/baton.c
index 6b694e4..2489f4e 100644
--- a/spaghetti-monster/baton.c
+++ b/spaghetti-monster/baton.c
@@ -226,3 +226,5 @@ void setup() {
push_state(off_state, 0);
}
+
+void loop() { }
diff --git a/spaghetti-monster/fsm-events.c b/spaghetti-monster/fsm-events.c
index 6dda236..4831df6 100644
--- a/spaghetti-monster/fsm-events.c
+++ b/spaghetti-monster/fsm-events.c
@@ -99,6 +99,29 @@ void delete_first_emission() {
emissions[i].arg = 0;
}
+void process_emissions() {
+ while (emissions[0].event != NULL) {
+ emit_now(emissions[0].event, emissions[0].arg);
+ delete_first_emission();
+ }
+}
+
+// like delay_ms, except it aborts on state change
+// return value:
+// 0: state changed
+// 1: normal completion
+uint8_t nice_delay_ms(uint16_t ms) {
+ StatePtr old_state = current_state;
+ while(ms-- > 0) {
+ _delay_loop_2(BOGOMIPS*98/100);
+ process_emissions();
+ if (old_state != current_state) {
+ return 0; // state changed; abort
+ }
+ }
+ return 1;
+}
+
// Call stacked callbacks for the given event until one handles it.
uint8_t emit_now(EventPtr event, uint16_t arg) {
for(int8_t i=state_stack_len-1; i>=0; i--) {
diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h
index 246a4ee..a14d7aa 100644
--- a/spaghetti-monster/fsm-events.h
+++ b/spaghetti-monster/fsm-events.h
@@ -209,9 +209,12 @@ 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);
+
#endif
diff --git a/spaghetti-monster/fsm-main.c b/spaghetti-monster/fsm-main.c
index 2faaeda..1a0c425 100644
--- a/spaghetti-monster/fsm-main.c
+++ b/spaghetti-monster/fsm-main.c
@@ -97,10 +97,9 @@ int main() {
// TODO: check voltage?
// TODO: check temperature?
// if event queue not empty, process and pop first item in queue?
- if (emissions[0].event != NULL) {
- emit_now(emissions[0].event, emissions[0].arg);
- delete_first_emission();
- }
+ process_emissions();
+
+ loop();
}
}
diff --git a/spaghetti-monster/momentary.c b/spaghetti-monster/momentary.c
index 23cc359..fc26db3 100644
--- a/spaghetti-monster/momentary.c
+++ b/spaghetti-monster/momentary.c
@@ -75,3 +75,6 @@ void setup() {
debug_blink(2);
push_state(momentary_state, 0);
}
+
+void loop() { }
+
diff --git a/spaghetti-monster/ramping-ui.c b/spaghetti-monster/ramping-ui.c
index 6eeb3b0..256c4cf 100644
--- a/spaghetti-monster/ramping-ui.c
+++ b/spaghetti-monster/ramping-ui.c
@@ -31,7 +31,7 @@
// FSM states
uint8_t off_state(EventPtr event, uint16_t arg);
uint8_t steady_state(EventPtr event, uint16_t arg);
-uint8_t party_strobe_state(EventPtr event, uint16_t arg);
+uint8_t strobe_state(EventPtr event, uint16_t arg);
// brightness control
uint8_t memorized_level = MAX_1x7135;
@@ -43,6 +43,11 @@ uint8_t ramp_step_size = 1;
uint8_t target_level = 0;
#endif
+// strobe timing
+volatile uint8_t strobe_delay = 67;
+volatile uint8_t strobe_type = 0; // 0 == party strobe, 1 == tactical strobe
+
+
uint8_t off_state(EventPtr event, uint16_t arg) {
// turn emitter off when entering state
if (event == EV_enter_state) {
@@ -74,7 +79,7 @@ uint8_t off_state(EventPtr event, uint16_t arg) {
}
// 3 clicks: strobe mode
else if (event == EV_3clicks) {
- set_state(party_strobe_state, 255);
+ set_state(strobe_state, 0);
return 0;
}
// hold: go to lowest level
@@ -90,7 +95,7 @@ uint8_t off_state(EventPtr event, uint16_t arg) {
set_state(steady_state, 1);
return 0;
}
- // click-release-hold: go to highest level (for ramping down)
+ // click, hold: go to highest level (for ramping down)
else if (event == EV_click2_hold) {
set_state(steady_state, MAX_LEVEL);
return 0;
@@ -98,6 +103,7 @@ uint8_t off_state(EventPtr event, uint16_t arg) {
return 1;
}
+
uint8_t steady_state(EventPtr event, uint16_t arg) {
// turn LED on when we first enter the mode
if (event == EV_enter_state) {
@@ -135,7 +141,7 @@ uint8_t steady_state(EventPtr event, uint16_t arg) {
}
// 3 clicks: go to strobe modes
else if (event == EV_3clicks) {
- set_state(party_strobe_state, 0xff);
+ set_state(strobe_state, 0);
return 0;
}
// 4 clicks: toggle smooth vs discrete ramping
@@ -170,7 +176,7 @@ uint8_t steady_state(EventPtr event, uint16_t arg) {
set_level(memorized_level);
return 0;
}
- // click-release-hold: change brightness (dimmer)
+ // click, hold: change brightness (dimmer)
else if (event == EV_click2_hold) {
// ramp slower in discrete mode
if (arg % ramp_step_size != 0) {
@@ -219,26 +225,9 @@ uint8_t steady_state(EventPtr event, uint16_t arg) {
return 1;
}
-uint8_t party_strobe_state(EventPtr event, uint16_t arg) {
- static volatile uint8_t frames = 0;
- static volatile uint8_t between = 2;
+
+uint8_t strobe_state(EventPtr event, uint16_t arg) {
if (event == EV_enter_state) {
- if (arg < 64) between = arg;
- frames = 0;
- return 0;
- }
- // tick: strobe the emitter
- else if (event == EV_tick) {
- if (frames == 0) {
- PWM1_LVL = 0;
- PWM2_LVL = 255;
- if (between < 3) delay_zero();
- else delay_ms(1);
- PWM2_LVL = 0;
- }
- //frames = (frames + 1) % between;
- frames++;
- if (frames > between) frames = 0;
return 0;
}
// 1 click: off
@@ -246,25 +235,37 @@ uint8_t party_strobe_state(EventPtr event, uint16_t arg) {
set_state(off_state, 0);
return 0;
}
- // 2 clicks: go back to regular modes
+ // 2 clicks: toggle party strobe vs tactical strobe
else if (event == EV_2clicks) {
+ strobe_type ^= 1;
+ return 0;
+ }
+ // 3 clicks: go back to regular modes
+ else if (event == EV_3clicks) {
set_state(steady_state, memorized_level);
return 0;
}
- // hold: change speed
+ // hold: change speed (go faster)
else if (event == EV_click1_hold) {
- if ((arg % HOLD_TIMEOUT) == 0) {
- between = (between+1)%6;
- frames = 0;
+ if ((arg & 1) == 0) {
+ if (strobe_delay > 8) strobe_delay --;
+ }
+ return 0;
+ }
+ // click, hold: change speed (go slower)
+ else if (event == EV_click2_hold) {
+ if ((arg & 1) == 0) {
+ if (strobe_delay < 255) strobe_delay ++;
}
return 0;
}
return 1;
}
+
void low_voltage() {
// "step down" from strobe to something low
- if (current_state == party_strobe_state) {
+ if (current_state == strobe_state) {
set_state(steady_state, RAMP_SIZE/6);
}
// in normal mode, step down by half or turn off
@@ -278,6 +279,7 @@ void low_voltage() {
}
}
+
void setup() {
set_level(RAMP_SIZE/8);
delay_4ms(3);
@@ -285,3 +287,18 @@ void setup() {
push_state(off_state, 0);
}
+
+
+void loop() {
+ if (current_state == strobe_state) {
+ set_level(MAX_LEVEL);
+ if (strobe_type == 0) { // party strobe
+ if (strobe_delay < 30) delay_zero();
+ else delay_ms(1);
+ } else { //tactical strobe
+ nice_delay_ms(strobe_delay >> 1);
+ }
+ set_level(0);
+ nice_delay_ms(strobe_delay);
+ }
+}
diff --git a/spaghetti-monster/spaghetti-monster.h b/spaghetti-monster/spaghetti-monster.h
index 2ba3208..7d26390 100644
--- a/spaghetti-monster/spaghetti-monster.h
+++ b/spaghetti-monster/spaghetti-monster.h
@@ -54,9 +54,11 @@ void debug_blink(uint8_t num) {
// TODO? new delay() functions which handle queue consumption?
// TODO? new interruptible delay() functions?
+// Define these in your SpaghettiMonster recipe
// boot-time tasks
-// Define this in your SpaghettiMonster recipe
void setup();
+// single loop iteration, runs continuously
+void loop();
// include executable functions too, for easier compiling
#include "fsm-states.c"
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.