aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSelene ToyKeeper2017-08-24 02:09:33 -0600
committerSelene ToyKeeper2017-08-24 02:09:33 -0600
commitbadf37072988156a4cee753b922306195ee45916 (patch)
tree8ad06bafce90d22b5fb95308af3900b7a55d78d8
parentAdded thermal regulation to SpaghettiMonster / Baton. (diff)
downloadanduril-badf37072988156a4cee753b922306195ee45916.tar.gz
anduril-badf37072988156a4cee753b922306195ee45916.tar.bz2
anduril-badf37072988156a4cee753b922306195ee45916.zip
Added a ramping UI example.
Added ramping support in general.
-rw-r--r--spaghetti-monster/fsm-adc.c2
-rw-r--r--spaghetti-monster/fsm-events.h7
-rw-r--r--spaghetti-monster/fsm-ramping.c62
-rw-r--r--spaghetti-monster/fsm-ramping.h85
-rw-r--r--spaghetti-monster/ramping-ui.c252
-rw-r--r--spaghetti-monster/spaghetti-monster.h2
6 files changed, 404 insertions, 6 deletions
diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c
index 8af3487..b3ae4e9 100644
--- a/spaghetti-monster/fsm-adc.c
+++ b/spaghetti-monster/fsm-adc.c
@@ -231,6 +231,8 @@ ISR(ADC_vect) {
if (underheat_lowpass < UNDERHEAT_LOWPASS_STRENGTH) {
underheat_lowpass ++;
} else {
+ // FIXME: don't warn about underheating when voltage is low
+ // (LVP and underheat warnings fight each other)
// how far below the floor?
int16_t howmuch = (THERM_FLOOR - projected_temperature) >> THERM_DIFF_ATTENUATION;
if (howmuch < 1) howmuch = 1;
diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h
index 434fa10..420baf1 100644
--- a/spaghetti-monster/fsm-events.h
+++ b/spaghetti-monster/fsm-events.h
@@ -116,6 +116,12 @@ Event EV_click2_press[] = {
A_RELEASE,
A_PRESS,
0 };
+Event EV_click2_hold[] = {
+ A_PRESS,
+ A_RELEASE,
+ A_PRESS,
+ A_HOLD,
+ 0 };
Event EV_click2_release[] = {
A_PRESS,
A_RELEASE,
@@ -166,6 +172,7 @@ EventPtr event_sequences[] = {
EV_click1_hold,
EV_click1_hold_release,
EV_click2_press,
+ EV_click2_hold,
EV_click2_release,
EV_click2_complete,
EV_click3_press,
diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c
new file mode 100644
index 0000000..ab7bd3c
--- /dev/null
+++ b/spaghetti-monster/fsm-ramping.c
@@ -0,0 +1,62 @@
+/*
+ * fsm-ramping.c: Ramping functions for SpaghettiMonster.
+ * Handles 1- to 4-channel smooth ramping on a single LED.
+ *
+ * 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_RAMPING_C
+#define FSM_RAMPING_C
+
+#ifdef USE_RAMPING
+
+void set_level(uint8_t level) {
+ actual_level = level;
+ //TCCR0A = PHASE;
+ if (level == 0) {
+ #if PWM_CHANNELS >= 1
+ PWM1_LVL = 0;
+ #endif
+ #if PWM_CHANNELS >= 2
+ PWM2_LVL = 0;
+ #endif
+ #if PWM_CHANNELS >= 3
+ PWM3_LVL = 0;
+ #endif
+ #if PWM_CHANNELS >= 4
+ PWM4_LVL = 0;
+ #endif
+ } else {
+ level --;
+ #if PWM_CHANNELS >= 1
+ PWM1_LVL = pgm_read_byte(pwm1_levels + level);
+ #endif
+ #if PWM_CHANNELS >= 2
+ PWM2_LVL = pgm_read_byte(pwm2_levels + level);
+ #endif
+ #if PWM_CHANNELS >= 3
+ PWM3_LVL = pgm_read_byte(pwm3_levels + level);
+ #endif
+ #if PWM_CHANNELS >= 4
+ PWM4_LVL = pgm_read_byte(pwm4_levels + level);
+ #endif
+ }
+}
+
+// TODO: set_lvl_smooth?
+
+#endif // ifdef USE_RAMPING
+#endif
diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h
index fd4d40b..a25ff8b 100644
--- a/spaghetti-monster/fsm-ramping.h
+++ b/spaghetti-monster/fsm-ramping.h
@@ -18,9 +18,82 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-// TODO: ramp tables
-// TODO: RAMP_SIZE / MAX_LVL
-// TODO: actual_lvl
-// TODO: target_lvl
-// TODO: set_lvl
-// TODO: set_lvl_smooth
+#ifndef FSM_RAMPING_H
+#define FSM_RAMPING_H
+
+#ifdef USE_RAMPING
+
+// actual_level: last ramp level set by set_level()
+volatile uint8_t actual_level = 0;
+
+// ramp tables
+#if PWM_CHANNELS == 1
+ #if RAMP_LENGTH == 50
+ // FIXME: These values are just an example
+ // ../../bin/level_calc.py 1 50 7135 3 0.25 980
+ PROGMEM const uint8_t pwm1_levels[] = { 3,3,3,3,4,4,4,5,5,6,7,8,9,11,12,14,16,18,20,23,25,28,32,35,39,43,47,52,57,62,68,74,80,87,94,102,110,118,127,136,146,156,167,178,189,201,214,227,241,255 };
+ #elif RAMP_LENGTH == 75
+ // FIXME: These values are just an example
+ // ../../bin/level_calc.py 1 75 7135 3 0.25 980
+ PROGMEM const uint8_t pwm1_levels[] = { 3,3,3,3,3,3,4,4,4,4,5,5,5,6,6,7,8,8,9,10,11,12,13,14,15,17,18,20,21,23,25,27,29,31,33,36,38,41,44,47,50,53,56,59,63,67,71,75,79,83,88,93,98,103,108,113,119,125,131,137,143,150,157,164,171,178,186,194,202,210,219,227,236,246,255 };
+ #elif RAMP_LENGTH == 150
+ // FIXME: These values are just an example
+ // ../../bin/level_calc.py 1 150 7135 3 0.25 980
+ PROGMEM const uint8_t pwm1_levels[] = { 3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,6,6,6,6,7,7,7,8,8,8,9,9,9,10,10,11,11,12,12,13,13,14,15,15,16,17,17,18,19,19,20,21,22,23,24,24,25,26,27,28,29,31,32,33,34,35,36,38,39,40,42,43,44,46,47,49,50,52,53,55,57,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,89,91,93,96,98,101,103,106,109,111,114,117,120,123,125,128,131,134,138,141,144,147,151,154,157,161,164,168,171,175,179,183,186,190,194,198,202,206,210,215,219,223,228,232,236,241,246,250,255 };
+ #endif
+#elif PWM_CHANNELS == 2
+ #if RAMP_LENGTH == 50
+ // ../../bin/level_calc.py 2 50 7135 4 0.33 150 FET 1 10 1500
+ PROGMEM const uint8_t pwm1_levels[] = { 4,5,6,8,10,13,17,22,28,35,44,54,65,78,93,109,128,149,171,197,224,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,11,15,20,26,31,37,44,51,58,65,73,82,91,100,110,121,132,143,155,168,181,194,209,224,239,255 };
+ #define MAX_1x7135 22
+ #elif RAMP_LENGTH == 75
+ // ../../bin/level_calc.py 2 75 7135 4 0.33 150 FET 1 10 1500
+ PROGMEM const uint8_t pwm1_levels[] = { 4,4,5,6,7,8,10,12,14,17,20,24,28,32,37,43,49,56,64,72,82,91,102,114,126,139,153,168,184,202,220,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,7,10,13,16,19,23,26,30,34,38,42,47,51,56,61,66,72,77,83,89,95,101,108,115,122,129,136,144,152,160,168,177,186,195,204,214,224,234,244,255 };
+ #define MAX_1x7135 33
+ #elif RAMP_LENGTH == 150
+ // ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500
+ PROGMEM const uint8_t pwm1_levels[] = { 4,4,4,5,5,5,6,6,7,7,8,9,10,11,12,13,14,15,17,18,20,21,23,25,27,30,32,34,37,40,43,46,49,52,56,59,63,67,71,76,80,85,90,95,100,106,112,118,124,130,137,144,151,158,166,173,181,190,198,207,216,225,235,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 };
+ #define MAX_1x7135 65
+ #endif
+#elif PWM_CHANNELS == 3
+ #if RAMP_LENGTH == 50
+ // FIXME: These values aren't tweaked or tested at all
+ // ../../bin/level_calc.py 3 50 7135 4 0.33 150 7135 4 1 840 FET 1 10 2000
+ PROGMEM const uint8_t pwm1_levels[] = { 4,5,6,8,11,15,20,26,34,43,54,67,82,99,118,140,165,192,221,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,17,25,33,42,52,62,73,85,97,111,125,140,157,174,192,210,230,251,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm3_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,34,54,76,98,122,146,172,198,226,255 };
+ #define MAX_1x7135 20
+ #define MAX_Nx7135 39
+ #elif RAMP_LENGTH == 75
+ // FIXME: These values aren't tweaked or tested at all
+ // ../../bin/level_calc.py 3 75 7135 4 0.33 150 7135 4 1 840 FET 1 10 2000
+ PROGMEM const uint8_t pwm1_levels[] = { 4,4,5,6,7,9,11,14,16,20,24,28,34,40,46,54,62,71,81,92,104,117,130,146,162,179,198,218,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,14,18,23,29,34,40,47,53,60,67,75,83,91,99,108,117,127,137,148,158,170,181,193,206,219,232,246,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm3_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,15,28,42,55,70,84,99,115,131,147,164,181,199,217,236,255 };
+ #define MAX_1x7135 30
+ #define MAX_Nx7135 59
+ #elif RAMP_LENGTH == 150
+ // FIXME: These values aren't tweaked or tested at all
+ // ../../bin/level_calc.py 3 150 7135 4 0.33 150 7135 4 1 840 FET 1 10 2000
+ PROGMEM const uint8_t pwm1_levels[] = { 4,4,4,5,5,6,6,7,7,8,9,10,11,12,13,15,16,18,20,22,24,26,28,31,33,36,39,42,46,49,53,57,61,65,70,75,80,85,90,96,102,108,115,121,128,136,143,151,159,167,176,185,194,204,214,224,235,246,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,6,8,10,13,15,17,20,22,25,28,30,33,36,39,42,45,48,51,55,58,62,65,69,73,76,80,84,88,92,97,101,105,110,115,119,124,129,134,139,144,149,155,160,166,171,177,183,189,195,201,207,214,220,227,234,241,248,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 };
+ PROGMEM const uint8_t pwm3_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,10,17,23,30,36,43,50,57,64,71,78,85,93,100,108,115,123,131,139,148,156,164,173,182,190,199,208,217,227,236,245,255 };
+ #define MAX_1x7135 59
+ #define MAX_Nx7135 117
+ #endif
+#elif PWM_CHANNELS == 4
+ 4-channel PWM not really supported yet, sorry.
+#endif
+
+// RAMP_SIZE / MAX_LVL
+#define RAMP_SIZE sizeof(pwm1_levels)
+#define MAX_LEVEL RAMP_SIZE
+
+void set_level(uint8_t level);
+//void set_level_smooth(uint8_t level);
+
+#endif // ifdef USE_RAMPING
+#endif
diff --git a/spaghetti-monster/ramping-ui.c b/spaghetti-monster/ramping-ui.c
new file mode 100644
index 0000000..b51d2f4
--- /dev/null
+++ b/spaghetti-monster/ramping-ui.c
@@ -0,0 +1,252 @@
+/*
+ * Ramping-UI: Ramping UI 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/>.
+ */
+
+#define FSM_EMISAR_D4_LAYOUT
+#define USE_LVP
+#define USE_THERMAL_REGULATION
+#define DEFAULT_THERM_CEIL 32
+#define USE_DEBUG_BLINK
+#define USE_DELAY_MS
+#define USE_DELAY_ZERO
+#define USE_RAMPING
+#define RAMP_LENGTH 150
+#include "spaghetti-monster.h"
+
+// 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);
+
+// brightness control
+uint8_t memorized_level = 1;
+#ifdef USE_THERMAL_REGULATION
+uint8_t target_level = 0;
+#endif
+
+uint8_t off_state(EventPtr event, uint16_t arg) {
+ // turn emitter off when entering state
+ if (event == EV_enter_state) {
+ set_level(0);
+ // sleep while off (lower power use)
+ //empty_event_sequence(); // just in case (but shouldn't be needed)
+ standby_mode();
+ return 0;
+ }
+ // hold (initially): go to lowest level, but allow abort for regular click
+ else if (event == EV_click1_press) {
+ set_level(1);
+ return 0;
+ }
+ // 1 click (before timeout): go to memorized level, but allow abort for double click
+ else if (event == EV_click1_release) {
+ set_level(memorized_level);
+ return 0;
+ }
+ // 1 click: regular mode
+ else if (event == EV_1click) {
+ set_state(steady_state, memorized_level);
+ return 0;
+ }
+ // 2 clicks: highest mode
+ else if (event == EV_2clicks) {
+ set_state(steady_state, MAX_LEVEL);
+ return 0;
+ }
+ // 3 clicks: strobe mode
+ else if (event == EV_3clicks) {
+ set_state(party_strobe_state, 255);
+ return 0;
+ }
+ // hold: go to lowest level
+ else if (event == EV_click1_hold) {
+ // don't start ramping immediately;
+ // give the user time to release at moon level
+ if (arg >= HOLD_TIMEOUT)
+ set_state(steady_state, 1);
+ return 0;
+ }
+ // hold, release quickly: go to lowest level
+ else if (event == EV_click1_hold_release) {
+ set_state(steady_state, 1);
+ return 0;
+ }
+ // click-release-hold: go to highest level (for ramping down)
+ else if (event == EV_click2_hold) {
+ set_state(steady_state, MAX_LEVEL);
+ return 0;
+ }
+ 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) {
+ // remember this level, unless it's moon or turbo
+ if ((arg > 1) && (arg < MAX_LEVEL))
+ memorized_level = arg;
+ // use the requested level even if not memorized
+ #ifdef USE_THERMAL_REGULATION
+ target_level = arg;
+ #endif
+ set_level(arg);
+ return 0;
+ }
+ // 1 click: off
+ else if (event == EV_1click) {
+ set_state(off_state, 0);
+ return 0;
+ }
+ // 2 clicks: go to/from highest level
+ else if (event == EV_2clicks) {
+ if (actual_level < MAX_LEVEL) {
+ memorized_level = actual_level; // in case we're on moon
+ #ifdef USE_THERMAL_REGULATION
+ target_level = MAX_LEVEL;
+ #endif
+ set_level(MAX_LEVEL);
+ }
+ else {
+ #ifdef USE_THERMAL_REGULATION
+ target_level = memorized_level;
+ #endif
+ set_level(memorized_level);
+ }
+ return 0;
+ }
+ // 3 clicks: go to strobe modes
+ else if (event == EV_3clicks) {
+ set_state(party_strobe_state, 0xff);
+ return 0;
+ }
+ // hold: change brightness (brighter)
+ else if (event == EV_click1_hold) {
+ // FIXME: make it ramp down instead, if already at max
+ if (actual_level < MAX_LEVEL)
+ memorized_level = (actual_level+1);
+ #ifdef USE_THERMAL_REGULATION
+ target_level = memorized_level;
+ #endif
+ // FIXME: only blink once
+ if ((memorized_level == MAX_1x7135) || (memorized_level == MAX_LEVEL)) {
+ set_level(0);
+ delay_ms(7);
+ }
+ set_level(memorized_level);
+ return 0;
+ }
+ // click-release-hold: change brightness (dimmer)
+ else if (event == EV_click2_hold) {
+ // FIXME: make it ramp up instead, if already at min
+ if (actual_level > 1)
+ memorized_level = (actual_level-1);
+ #ifdef USE_THERMAL_REGULATION
+ target_level = memorized_level;
+ #endif
+ // FIXME: only blink once
+ if ((memorized_level == MAX_1x7135) || (memorized_level == 1)) {
+ set_level(0);
+ delay_ms(7);
+ }
+ set_level(memorized_level);
+ return 0;
+ }
+ #ifdef USE_THERMAL_REGULATION
+ // FIXME: make thermal regulation work with ramping
+ // overheating: drop by 1 level
+ else if (event == EV_temperature_high) {
+ if (actual_level > 1) {
+ set_level(actual_level - 1);
+ }
+ return 0;
+ }
+ // underheating: increase by 1 level if we're lower than the target
+ else if (event == EV_temperature_low) {
+ if (actual_level < target_level) {
+ set_level(actual_level + 1);
+ }
+ return 0;
+ }
+ #endif
+ return 1;
+}
+
+uint8_t party_strobe_state(EventPtr event, uint16_t arg) {
+ static volatile uint8_t frames = 0;
+ static volatile uint8_t between = 2;
+ 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
+ else if (event == EV_1click) {
+ set_state(off_state, 0);
+ return 0;
+ }
+ // 2 clicks: go back to regular modes
+ else if (event == EV_2clicks) {
+ set_state(steady_state, memorized_level);
+ return 0;
+ }
+ // hold: change speed
+ else if (event == EV_click1_hold) {
+ if ((arg % HOLD_TIMEOUT) == 0) {
+ between = (between+1)%6;
+ frames = 0;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+void low_voltage() {
+ // "step down" from strobe to something low
+ if (current_state == party_strobe_state) {
+ set_state(steady_state, RAMP_SIZE/6);
+ }
+ // in normal mode, step down by half or turn off
+ else if (current_state == steady_state) {
+ if (actual_level > 1) {
+ set_level(actual_level >> 1);
+ }
+ else {
+ set_state(off_state, 0);
+ }
+ }
+}
+
+void setup() {
+ debug_blink(2);
+
+ push_state(off_state, 0);
+}
diff --git a/spaghetti-monster/spaghetti-monster.h b/spaghetti-monster/spaghetti-monster.h
index 4eeb7de..2ba3208 100644
--- a/spaghetti-monster/spaghetti-monster.h
+++ b/spaghetti-monster/spaghetti-monster.h
@@ -33,6 +33,7 @@
#include "fsm-wdt.h"
#include "fsm-pcint.h"
#include "fsm-standby.h"
+#include "fsm-ramping.h"
#include "fsm-main.h"
#ifdef USE_DEBUG_BLINK
@@ -64,4 +65,5 @@ void setup();
#include "fsm-wdt.c"
#include "fsm-pcint.c"
#include "fsm-standby.c"
+#include "fsm-ramping.c"
#include "fsm-main.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.