aboutsummaryrefslogtreecommitdiff
path: root/spaghetti-monster
diff options
context:
space:
mode:
authorSelene ToyKeeper2019-05-23 15:30:08 -0600
committerSelene ToyKeeper2019-05-23 15:30:08 -0600
commita0ba6460f7b6742c7fa14ada0d4c72f53b213168 (patch)
treeee10fc3c698849c872e24a9edb04f15b3453c01a /spaghetti-monster
parentmerged from lantern branch, to get candle mode updates (diff)
parentD4S actually steps down a bit too fast, so... minimize that (diff)
downloadanduril-a0ba6460f7b6742c7fa14ada0d4c72f53b213168.tar.gz
anduril-a0ba6460f7b6742c7fa14ada0d4c72f53b213168.tar.bz2
anduril-a0ba6460f7b6742c7fa14ada0d4c72f53b213168.zip
merged from fsm branch to get lots of updates
Diffstat (limited to 'spaghetti-monster')
-rw-r--r--spaghetti-monster/anduril/anduril-manual.txt23
-rw-r--r--spaghetti-monster/anduril/anduril.c222
-rw-r--r--spaghetti-monster/anduril/cfg-blf-lantern.h10
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d18.h2
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d4.h2
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d4s.h2
-rw-r--r--spaghetti-monster/anduril/cfg-ff-pl47-219.h2
-rw-r--r--spaghetti-monster/anduril/cfg-ff-pl47.h6
-rw-r--r--spaghetti-monster/anduril/cfg-ff-rot66.h2
-rw-r--r--spaghetti-monster/anduril/cfg-fw3a-219.h9
-rw-r--r--spaghetti-monster/anduril/cfg-fw3a.h4
-rw-r--r--spaghetti-monster/fsm-adc.c111
-rw-r--r--spaghetti-monster/fsm-misc.c7
-rw-r--r--spaghetti-monster/fsm-misc.h3
-rw-r--r--spaghetti-monster/fsm-ramping.c27
-rw-r--r--spaghetti-monster/fsm-ramping.h1
16 files changed, 278 insertions, 155 deletions
diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt
index cd4fe3e..3684b50 100644
--- a/spaghetti-monster/anduril/anduril-manual.txt
+++ b/spaghetti-monster/anduril/anduril-manual.txt
@@ -223,11 +223,23 @@ Momentary Mode
Click 5 times from Off to enter Momentary mode. This locks the
flashlight into a single-mode interface where the LEDs are only on when
-the button is held down. It is intended for Morse code and other
-signalling tasks.
+the button is held down. It is intended for Morse code, light painting,
+and other tasks where the light should be on only for a short time and
+probably in a pattern.
-Brightness is the last-ramped level, so adjust that before entering
-momentary mode.
+Momentary mode does either a steady brightness level or a strobe. To
+select which one, go to the mode you want to use, adjust the brightness
+and speed and other settings, then turn the light off. Then click 5
+times to enter momentary mode.
+
+Supported momentary modes are steady (normal ramping mode) and strobes
+(everything in the "strobe" mode group).
+
+In steady mode, brightness is the last-ramped level, so adjust that
+before entering momentary mode.
+
+In momentary strobe mode, the settings are copied from the last-used
+strobe mode, such as party strobe, tactical strobe, or lightning.
To exit this mode, physically disconnect power by unscrewing the tailcap
or battery tube.
@@ -253,6 +265,9 @@ prevent children from exiting the mode by unscrewing the tailcap.
However, be sure to supervise children whenever they are using any
powerful tools, including a bright flashlight.
+Note: If the light steps down in muggle mode, it probably needs to have
+the temperature sensor calibrated. Use thermal config mode to do this.
+
Configuration Modes
-------------------
diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c
index e3ff0cb..f9509e7 100644
--- a/spaghetti-monster/anduril/anduril.c
+++ b/spaghetti-monster/anduril/anduril.c
@@ -185,6 +185,12 @@ typedef enum {
#define USE_PSEUDO_RAND
#endif
+#if defined(USE_CANDLE_MODE)
+#ifndef USE_TRIANGLE_WAVE
+#define USE_TRIANGLE_WAVE
+#endif
+#endif
+
#include "spaghetti-monster.h"
@@ -234,10 +240,12 @@ uint8_t beacon_config_state(Event event, uint16_t arg);
// soft lockout
#define MOON_DURING_LOCKOUT_MODE
// if enabled, 2nd lockout click goes to the other ramp's floor level
-//#define LOCKOUT_MOON_FANCY
+#define LOCKOUT_MOON_FANCY
uint8_t lockout_state(Event event, uint16_t arg);
// momentary / signalling mode
uint8_t momentary_state(Event event, uint16_t arg);
+uint8_t momentary_mode = 0; // 0 = ramping, 1 = strobe
+uint8_t momentary_active = 0; // boolean, true if active *right now*
#ifdef USE_MUGGLE_MODE
// muggle mode, super-simple, hard to exit
uint8_t muggle_state(Event event, uint16_t arg);
@@ -250,6 +258,7 @@ uint8_t number_entry_state(Event event, uint16_t arg);
volatile uint8_t number_entry_value;
void blink_confirm(uint8_t num);
+void blip();
#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY)
void indicator_blink(uint8_t arg);
#endif
@@ -262,6 +271,9 @@ void save_config_wl();
#endif
// default ramp options if not overridden earlier per-driver
+#ifndef RAMP_STYLE
+#define RAMP_STYLE 0 // smooth default
+#endif
#ifndef RAMP_SMOOTH_FLOOR
#define RAMP_SMOOTH_FLOOR 1
#endif
@@ -305,7 +317,7 @@ void save_config_wl();
#endif
uint8_t memorized_level = DEFAULT_LEVEL;
// smooth vs discrete ramping
-volatile uint8_t ramp_style = 0; // 0 = smooth, 1 = discrete
+volatile uint8_t ramp_style = RAMP_STYLE; // 0 = smooth, 1 = discrete
volatile uint8_t ramp_smooth_floor = RAMP_SMOOTH_FLOOR;
volatile uint8_t ramp_smooth_ceil = RAMP_SMOOTH_CEIL;
volatile uint8_t ramp_discrete_floor = RAMP_DISCRETE_FLOOR;
@@ -434,10 +446,7 @@ uint8_t off_state(Event event, uint16_t arg) {
#ifdef MOON_TIMING_HINT
if (arg == 0) {
// let the user know they can let go now to stay at moon
- uint8_t temp = actual_level;
- set_level(0);
- delay_4ms(3);
- set_level(temp);
+ blip();
} else
#endif
// don't start ramping immediately;
@@ -561,6 +570,7 @@ uint8_t steady_state(Event event, uint16_t arg) {
// turn LED on when we first enter the mode
if ((event == EV_enter_state) || (event == EV_reenter_state)) {
+ momentary_mode = 0; // 0 = ramping, 1 = strobes
// if we just got back from config mode, go back to memorized level
if (event == EV_reenter_state) {
arg = memorized_level;
@@ -615,8 +625,7 @@ uint8_t steady_state(Event event, uint16_t arg) {
#ifdef START_AT_MEMORIZED_LEVEL
save_config_wl();
#endif
- set_level(0);
- delay_4ms(20/4);
+ blip();
set_level(memorized_level);
return MISCHIEF_MANAGED;
}
@@ -667,8 +676,7 @@ uint8_t steady_state(Event event, uint16_t arg) {
|| (memorized_level == mode_min)
#endif
)) {
- set_level(0);
- delay_4ms(8/4);
+ blip();
}
#endif
#if defined(BLINK_AT_STEPS)
@@ -682,8 +690,7 @@ uint8_t steady_state(Event event, uint16_t arg) {
(memorized_level == nearest)
)
{
- set_level(0);
- delay_4ms(8/4);
+ blip();
}
#endif
set_level(memorized_level);
@@ -729,8 +736,7 @@ uint8_t steady_state(Event event, uint16_t arg) {
|| (memorized_level == mode_min)
#endif
)) {
- set_level(0);
- delay_4ms(8/4);
+ blip();
}
#endif
#if defined(BLINK_AT_STEPS)
@@ -744,8 +750,7 @@ uint8_t steady_state(Event event, uint16_t arg) {
(memorized_level == nearest)
)
{
- set_level(0);
- delay_4ms(8/4);
+ blip();
}
#endif
set_level(memorized_level);
@@ -816,10 +821,7 @@ uint8_t steady_state(Event event, uint16_t arg) {
// overheating: drop by an amount proportional to how far we are above the ceiling
else if (event == EV_temperature_high) {
#if 0
- uint8_t foo = actual_level;
- set_level(0);
- delay_4ms(2);
- set_level(foo);
+ blip();
#endif
#ifdef THERM_HARD_TURBO_DROP
if (actual_level > THERM_FASTER_LEVEL) {
@@ -847,10 +849,7 @@ uint8_t steady_state(Event event, uint16_t arg) {
// (proportional to how low we are)
else if (event == EV_temperature_low) {
#if 0
- uint8_t foo = actual_level;
- set_level(0);
- delay_4ms(2);
- set_level(foo);
+ blip();
#endif
if (actual_level < target_level) {
//int16_t stepup = actual_level + (arg>>1);
@@ -873,23 +872,53 @@ uint8_t steady_state(Event event, uint16_t arg) {
#ifdef USE_TINT_RAMPING
uint8_t tint_ramping_state(Event event, uint16_t arg) {
static int8_t tint_ramp_direction = 1;
+ static uint8_t prev_tint = 0;
+ // don't activate auto-tint modes unless the user hits the edge
+ // and keeps pressing for a while
+ static uint8_t past_edge_counter = 0;
+ // bugfix: click-click-hold from off to strobes would invoke tint ramping
+ // in addition to changing state... so ignore any tint-ramp events which
+ // don't look like they were meant to be here
+ static uint8_t active = 0;
// click, click, hold: change the tint
if (event == EV_click3_hold) {
- //if ((arg & 1) == 0) { // ramp slower
- if ((tint_ramp_direction > 0) && (tint < 255)) {
- tint += 1;
- }
- else if ((tint_ramp_direction < 0) && (tint > 0)) {
- tint -= 1;
- }
- set_level(actual_level);
- //}
+ // reset at beginning of movement
+ if (! arg) {
+ active = 1; // first frame means this is for us
+ past_edge_counter = 0; // doesn't start until user hits the edge
+ }
+ // ignore event if we weren't the ones who handled the first frame
+ if (! active) return EVENT_HANDLED;
+
+ // change normal tints
+ if ((tint_ramp_direction > 0) && (tint < 254)) {
+ tint += 1;
+ }
+ else if ((tint_ramp_direction < 0) && (tint > 1)) {
+ tint -= 1;
+ }
+ // if the user kept pressing long enough, go the final step
+ if (past_edge_counter == 64) {
+ past_edge_counter ++;
+ tint ^= 1; // 0 -> 1, 254 -> 255
+ blip();
+ }
+ // if tint change stalled, let user know we hit the edge
+ else if (prev_tint == tint) {
+ if (past_edge_counter == 0) blip();
+ // count up but don't wrap back to zero
+ if (past_edge_counter < 255) past_edge_counter ++;
+ }
+ prev_tint = tint;
+ set_level(actual_level);
return EVENT_HANDLED;
}
// click, click, hold, release: reverse direction for next ramp
else if (event == EV_click3_hold_release) {
+ active = 0; // ignore next hold if it wasn't meant for us
+ // reverse
tint_ramp_direction = -tint_ramp_direction;
if (tint == 0) tint_ramp_direction = 1;
else if (tint == 255) tint_ramp_direction = -1;
@@ -905,10 +934,14 @@ uint8_t tint_ramping_state(Event event, uint16_t arg) {
#ifdef USE_STROBE_STATE
uint8_t strobe_state(Event event, uint16_t arg) {
+ static int8_t ramp_direction = 1;
+
// 'st' reduces ROM size by avoiding access to a volatile var
// (maybe I should just make it nonvolatile?)
strobe_mode_te st = strobe_type;
+ momentary_mode = 1; // 0 = ramping, 1 = strobes
+
#ifdef USE_CANDLE_MODE
// pass all events to candle mode, when it's active
// (the code is in its own pseudo-state to keep things cleaner)
@@ -918,11 +951,11 @@ uint8_t strobe_state(Event event, uint16_t arg) {
#endif
if (0) {} // placeholder
- /* not used any more
+ // init anything which needs to be initialized
else if (event == EV_enter_state) {
+ ramp_direction = 1;
return MISCHIEF_MANAGED;
}
- */
// 1 click: off
else if (event == EV_1click) {
set_state(off_state, 0);
@@ -947,7 +980,11 @@ uint8_t strobe_state(Event event, uint16_t arg) {
else if (st == party_strobe_e) {
#endif
if ((arg & 1) == 0) {
- if (strobe_delays[st] > 8) strobe_delays[st] --;
+ uint8_t d = strobe_delays[st];
+ d -= ramp_direction;
+ if (d < 8) d = 8;
+ else if (d > 254) d = 254;
+ strobe_delays[st] = d;
}
}
#endif
@@ -958,17 +995,27 @@ uint8_t strobe_state(Event event, uint16_t arg) {
// biking mode brighter
#ifdef USE_BIKE_FLASHER_MODE
else if (st == bike_flasher_e) {
- if (bike_flasher_brightness < MAX_BIKING_LEVEL)
- bike_flasher_brightness ++;
+ bike_flasher_brightness += ramp_direction;
+ if (bike_flasher_brightness < 2) bike_flasher_brightness = 2;
+ else if (bike_flasher_brightness > MAX_BIKING_LEVEL) bike_flasher_brightness = MAX_BIKING_LEVEL;
set_level(bike_flasher_brightness);
}
#endif
return MISCHIEF_MANAGED;
}
+ // reverse ramp direction on hold release
+ // ... and save new strobe settings
+ else if (event == EV_click1_hold_release) {
+ ramp_direction = -ramp_direction;
+ save_config();
+ return MISCHIEF_MANAGED;
+ }
// click, hold: change speed (go slower)
// or change brightness (dimmer)
else if (event == EV_click2_hold) {
+ ramp_direction = 1;
+
if (0) {} // placeholder
// party / tactical strobe slower
@@ -999,14 +1046,16 @@ uint8_t strobe_state(Event event, uint16_t arg) {
return MISCHIEF_MANAGED;
}
// release hold: save new strobe settings
- else if ((event == EV_click1_hold_release)
- || (event == EV_click2_hold_release)) {
+ else if (event == EV_click2_hold_release) {
save_config();
return MISCHIEF_MANAGED;
}
#if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE)
// clock tick: bump the random seed
else if (event == EV_tick) {
+ // un-reverse after 1 second
+ if (arg == TICKS_PER_SECOND) ramp_direction = 1;
+
pseudo_rand_seed += arg;
return MISCHIEF_MANAGED;
}
@@ -1048,7 +1097,7 @@ inline void lightning_storm_iter() {
//rand_time = 1 << (pseudo_rand() % 7);
rand_time = pseudo_rand() & 63;
brightness = 1 << (pseudo_rand() % 7); // 1, 2, 4, 8, 16, 32, 64
- brightness += 1 << (pseudo_rand() & 0x03); // 2 to 80 now
+ brightness += 1 << (pseudo_rand() % 5); // 2 to 80 now
brightness += pseudo_rand() % brightness; // 2 to 159 now (w/ low bias)
if (brightness > MAX_LEVEL) brightness = MAX_LEVEL;
set_level(brightness);
@@ -1103,6 +1152,7 @@ inline void bike_flasher_iter() {
#ifdef USE_CANDLE_MODE
uint8_t candle_mode_state(Event event, uint16_t arg) {
+ static int8_t ramp_direction = 1;
#define MAX_CANDLE_LEVEL (RAMP_LENGTH-CANDLE_AMPLITUDE-15)
static uint8_t candle_wave1 = 0;
static uint8_t candle_wave2 = 0;
@@ -1122,6 +1172,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) {
if (event == EV_enter_state) {
candle_mode_timer = 0; // in case any time was left over from earlier
+ ramp_direction = 1;
return MISCHIEF_MANAGED;
}
// 2 clicks: cancel timer
@@ -1133,12 +1184,25 @@ uint8_t candle_mode_state(Event event, uint16_t arg) {
}
// hold: change brightness (brighter)
else if (event == EV_click1_hold) {
- if (candle_mode_brightness < MAX_CANDLE_LEVEL)
- candle_mode_brightness ++;
+ // ramp away from extremes
+ if (! arg) {
+ if (candle_mode_brightness >= MAX_CANDLE_LEVEL) { ramp_direction = -1; }
+ else if (candle_mode_brightness <= 1) { ramp_direction = 1; }
+ }
+ // change brightness, but not too far
+ candle_mode_brightness += ramp_direction;
+ if (candle_mode_brightness < 1) candle_mode_brightness = 1;
+ else if (candle_mode_brightness > MAX_CANDLE_LEVEL) candle_mode_brightness = MAX_CANDLE_LEVEL;
+ return MISCHIEF_MANAGED;
+ }
+ // reverse ramp direction on hold release
+ else if (event == EV_click1_hold_release) {
+ ramp_direction = -ramp_direction;
return MISCHIEF_MANAGED;
}
// click, hold: change brightness (dimmer)
else if (event == EV_click2_hold) {
+ ramp_direction = 1;
if (candle_mode_brightness > 1)
candle_mode_brightness --;
return MISCHIEF_MANAGED;
@@ -1156,6 +1220,9 @@ uint8_t candle_mode_state(Event event, uint16_t arg) {
}
// clock tick: animate candle brightness
else if (event == EV_tick) {
+ // un-reverse after 1 second
+ if (arg == TICKS_PER_SECOND) ramp_direction = 1;
+
// self-timer dims the light during the final minute
uint8_t subtract = 0;
if (candle_mode_timer == 1) {
@@ -1215,12 +1282,6 @@ uint8_t candle_mode_state(Event event, uint16_t arg) {
}
return EVENT_NOT_HANDLED;
}
-
-uint8_t triangle_wave(uint8_t phase) {
- uint8_t result = phase << 1;
- if (phase > 127) result = 255 - result;
- return result;
-}
#endif // #ifdef USE_CANDLE_MODE
@@ -1522,14 +1583,24 @@ uint8_t lockout_state(Event event, uint16_t arg) {
uint8_t momentary_state(Event event, uint16_t arg) {
// TODO: momentary strobe here? (for light painting)
+ // init strobe mode, if relevant
+ if ((event == EV_enter_state) && (momentary_mode == 1)) {
+ strobe_state(event, arg);
+ }
+
// light up when the button is pressed; go dark otherwise
// button is being held
if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) {
- set_level(memorized_level);
+ momentary_active = 1;
+ // 0 = ramping, 1 = strobes
+ if (momentary_mode == 0) {
+ set_level(memorized_level);
+ }
return MISCHIEF_MANAGED;
}
// button was released
else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) {
+ momentary_active = 0;
set_level(0);
//go_to_standby = 1; // sleep while light is off
return MISCHIEF_MANAGED;
@@ -1540,10 +1611,18 @@ uint8_t momentary_state(Event event, uint16_t arg) {
// with exiting via tailcap loosen+tighten unless you leave power
// disconnected for several seconds, so we want to be awake when that
// happens to speed up the process)
- 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?
+ else if (event == EV_tick) {
+ if (momentary_active) {
+ // 0 = ramping, 1 = strobes
+ if (momentary_mode == 1) {
+ return strobe_state(event, arg);
+ }
+ }
+ else {
+ 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;
}
@@ -1677,12 +1756,13 @@ uint8_t muggle_state(Event event, uint16_t arg) {
#ifdef USE_THERMAL_REGULATION
// overheating is handled specially in muggle mode
else if(event == EV_temperature_high) {
- // don't even try...
- // go immediately to the bottom, in case someone put the light on
- // maximum while wrapped in dark-colored flammable insulation
- // or something, because muggles are cool like that
- // memorized_level = MUGGLE_FLOOR; // override memory? maybe not
- set_level(MUGGLE_FLOOR);
+ #if 0
+ blip();
+ #endif
+ // step down proportional to the amount of overheating
+ uint8_t new = actual_level - arg;
+ if (new < MUGGLE_FLOOR) { new = MUGGLE_FLOOR; }
+ set_level(new);
return MISCHIEF_MANAGED;
}
#endif
@@ -1780,14 +1860,15 @@ void thermal_config_save() {
// calibrate room temperature
val = config_state_values[0];
if (val) {
- int8_t rawtemp = (temperature >> 1) - therm_cal_offset;
+ int8_t rawtemp = temperature - therm_cal_offset;
therm_cal_offset = val - rawtemp;
+ reset_thermal_history = 1; // invalidate all recent temperature data
}
val = config_state_values[1];
if (val) {
// set maximum heat limit
- therm_ceil = 30 + val;
+ therm_ceil = 30 + val - 1;
}
if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL;
}
@@ -1816,9 +1897,9 @@ uint8_t beacon_config_state(Event event, uint16_t arg) {
inline void beacon_mode_iter() {
// one iteration of main loop()
set_level(memorized_level);
- nice_delay_ms(500);
+ nice_delay_ms(100);
set_level(0);
- nice_delay_ms(((beacon_seconds) * 1000) - 500);
+ nice_delay_ms(((beacon_seconds) * 1000) - 100);
}
#endif // #ifdef USE_BEACON_MODE
@@ -1950,6 +2031,14 @@ void blink_confirm(uint8_t num) {
}
}
+// Just go dark for a moment to indicate to user that something happened
+void blip() {
+ uint8_t temp = actual_level;
+ set_level(0);
+ delay_4ms(3);
+ set_level(temp);
+}
+
#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY)
// beacon-like mode for the indicator LED
@@ -2151,7 +2240,8 @@ void loop() {
if (0) {}
#ifdef USE_STROBE_STATE
- else if (state == strobe_state) {
+ else if ((state == strobe_state)
+ || ((state == momentary_state) && (momentary_mode == 1) && (momentary_active)) ) { // also handle momentary strobes
uint8_t st = strobe_type;
switch(st) {
@@ -2215,7 +2305,7 @@ void loop() {
#ifdef USE_THERMAL_REGULATION
// TODO: blink out therm_ceil during thermal_config_state?
else if (state == tempcheck_state) {
- blink_num(temperature>>1);
+ blink_num(temperature);
nice_delay_ms(1000);
}
#endif
diff --git a/spaghetti-monster/anduril/cfg-blf-lantern.h b/spaghetti-monster/anduril/cfg-blf-lantern.h
index 3d4c762..9467397 100644
--- a/spaghetti-monster/anduril/cfg-blf-lantern.h
+++ b/spaghetti-monster/anduril/cfg-blf-lantern.h
@@ -44,9 +44,10 @@
// set floor and ceiling as far apart as possible
// because this lantern isn't overpowered
+#define RAMP_STYLE 1 // 0 = smooth, 1 = stepped
#define RAMP_SMOOTH_FLOOR 1
#define RAMP_SMOOTH_CEIL 150
-#define RAMP_DISCRETE_FLOOR 20
+#define RAMP_DISCRETE_FLOOR 10
#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL
#define RAMP_DISCRETE_STEPS 5
@@ -68,9 +69,10 @@
#ifdef BLINK_AT_RAMP_MIDDLE
#undef BLINK_AT_RAMP_MIDDLE
#endif
-#ifdef BLINK_AT_RAMP_CEILING
-#undef BLINK_AT_RAMP_CEILING
-#endif
#ifdef BLINK_AT_RAMP_FLOOR
#undef BLINK_AT_RAMP_FLOOR
#endif
+// except the top... blink at the top
+#ifndef BLINK_AT_RAMP_CEILING
+#define BLINK_AT_RAMP_CEILING
+#endif
diff --git a/spaghetti-monster/anduril/cfg-emisar-d18.h b/spaghetti-monster/anduril/cfg-emisar-d18.h
index fcea43a..16fbacd 100644
--- a/spaghetti-monster/anduril/cfg-emisar-d18.h
+++ b/spaghetti-monster/anduril/cfg-emisar-d18.h
@@ -43,4 +43,4 @@
// stop panicking at about ~40% power or ~5000 lm
#define THERM_FASTER_LEVEL 125
// optional, makes initial turbo step-down faster so first peak isn't as hot
-#define THERM_HARD_TURBO_DROP
+//#define THERM_HARD_TURBO_DROP
diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h
index 2f4df49..de8f796 100644
--- a/spaghetti-monster/anduril/cfg-emisar-d4.h
+++ b/spaghetti-monster/anduril/cfg-emisar-d4.h
@@ -13,7 +13,7 @@
// optional, makes initial turbo step-down faster so first peak isn't as hot
// the D4 runs very very hot, so be extra careful
-#define THERM_HARD_TURBO_DROP
+//#define THERM_HARD_TURBO_DROP
// stop panicking at ~30% power or ~1200 lm
#define THERM_FASTER_LEVEL 105
diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s.h b/spaghetti-monster/anduril/cfg-emisar-d4s.h
index e26634a..d19a514 100644
--- a/spaghetti-monster/anduril/cfg-emisar-d4s.h
+++ b/spaghetti-monster/anduril/cfg-emisar-d4s.h
@@ -36,7 +36,7 @@
#undef MIN_THERM_STEPDOWN // this should be lower, because 3x7135 instead of 1x7135
#endif
#define MIN_THERM_STEPDOWN 60 // lowest value it'll step down to
-#define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high
+#define THERM_FASTER_LEVEL (RAMP_SIZE-1) // don't throttle back faster when high
// no need to be extra-careful on this light
#ifdef THERM_HARD_TURBO_DROP
diff --git a/spaghetti-monster/anduril/cfg-ff-pl47-219.h b/spaghetti-monster/anduril/cfg-ff-pl47-219.h
index 3ded2aa..ad66adb 100644
--- a/spaghetti-monster/anduril/cfg-ff-pl47-219.h
+++ b/spaghetti-monster/anduril/cfg-ff-pl47-219.h
@@ -3,5 +3,7 @@
// to avoid destroying the LEDs
#include "cfg-ff-pl47.h"
+#undef PWM1_LEVELS
#undef PWM2_LEVELS
+#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,5,6,6,7,8,8,9,10,10,11,12,13,14,15,16,17,18,19,21,22,23,25,26,27,29,31,32,34,36,38,40,42,44,46,49,51,54,56,59,62,65,68,71,74,78,81,85,89,93,97,101,106,110,115,120,125,130,136,141,147,153,160,166,173,180,187,195,202,210,219,227,236,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
#define 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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,19,20,22,23,25,27,28,30,31,33,35,37,39,41,43,45,47,50,52,55,57,60,63,65,68,71,74,77,80,83,87,90,93,97,101,105,108,112,116,121,125,129,134,139,143,148,153,159,164,169
diff --git a/spaghetti-monster/anduril/cfg-ff-pl47.h b/spaghetti-monster/anduril/cfg-ff-pl47.h
index f9c8974..7a81c25 100644
--- a/spaghetti-monster/anduril/cfg-ff-pl47.h
+++ b/spaghetti-monster/anduril/cfg-ff-pl47.h
@@ -59,10 +59,12 @@
//#define MUGGLE_CEILING 90
// regulate down faster when the FET is active, slower otherwise
-#define THERM_FASTER_LEVEL 130 // throttle back faster when high
+#define THERM_FASTER_LEVEL 135 // throttle back faster when high
// play it safe, don't try to regulate above the recommended safe level
-#define THERM_HARD_TURBO_DROP
+#ifdef THERM_HARD_TURBO_DROP
+#undef THERM_HARD_TURBO_DROP
+#endif
// don't do this
#undef BLINK_AT_RAMP_MIDDLE
diff --git a/spaghetti-monster/anduril/cfg-ff-rot66.h b/spaghetti-monster/anduril/cfg-ff-rot66.h
index 6073ce0..2a90343 100644
--- a/spaghetti-monster/anduril/cfg-ff-rot66.h
+++ b/spaghetti-monster/anduril/cfg-ff-rot66.h
@@ -39,7 +39,7 @@
#define THERM_FASTER_LEVEL 130 // throttle back faster when high
// play it safe, don't try to regulate above the recommended safe level
-#define THERM_HARD_TURBO_DROP
+//#define THERM_HARD_TURBO_DROP
// don't do this
#undef BLINK_AT_RAMP_MIDDLE
diff --git a/spaghetti-monster/anduril/cfg-fw3a-219.h b/spaghetti-monster/anduril/cfg-fw3a-219.h
new file mode 100644
index 0000000..1d8e4a1
--- /dev/null
+++ b/spaghetti-monster/anduril/cfg-fw3a-219.h
@@ -0,0 +1,9 @@
+// FW3A-219 config options for Anduril
+#include "cfg-fw3a.h"
+
+#undef PWM1_LEVELS
+#undef PWM2_LEVELS
+#undef PWM3_LEVELS
+#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,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,255
+#define 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,2,4,6,8,10,13,15,17,19,22,24,26,29,31,34,37,39,42,45,48,51,54,57,60,64,67,70,74,77,81,85,88,92,96,100,104,108,112,116,121,125,130,134,139,143,148,153,158,163,168,173,179,184,189,195,201,206,212,218,224,230,236,243,249,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+#define 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,0,0,0,0,0,0,0,0,0,0,0,0,0,8,13,19,25,30,36,42,48,54,61,67,73,80,86,93,100,107,114,120,128
diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h
index dd77137..a28d12a 100644
--- a/spaghetti-monster/anduril/cfg-fw3a.h
+++ b/spaghetti-monster/anduril/cfg-fw3a.h
@@ -15,5 +15,5 @@
// stop panicking at about 3A or ~1100 lm, this light is a hotrod
#define THERM_FASTER_LEVEL MAX_Nx7135
-// optional, makes initial turbo step-down faster so first peak isn't as hot
-#define THERM_HARD_TURBO_DROP
+
+#define USE_TENCLICK_THERMAL_CONFIG
diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c
index 8decd9d..bcf49ed 100644
--- a/spaghetti-monster/fsm-adc.c
+++ b/spaghetti-monster/fsm-adc.c
@@ -89,20 +89,16 @@ ISR(ADC_vect) {
// thermal declarations
#ifdef USE_THERMAL_REGULATION
- #define NUM_THERMAL_VALUES 8
- #define NUM_THERMAL_VALUES_HISTORY 16
- #define NUM_THERMAL_PROJECTED_HISTORY 8
+ #define NUM_THERMAL_VALUES_HISTORY 8
#define ADC_STEPS 4
- static int16_t temperature_values[NUM_THERMAL_VALUES]; // last few readings in C
- static int16_t temperature_history[NUM_THERMAL_VALUES_HISTORY]; // 14.1 fixed-point
- static int16_t projected_temperature_history[NUM_THERMAL_PROJECTED_HISTORY]; // 14.1 fixed-point
- static uint8_t projected_temperature_history_counter = 0;
+ static uint8_t history_step = 0; // don't update history as often
+ static int16_t temperature_history[NUM_THERMAL_VALUES_HISTORY];
static uint8_t temperature_timer = 0;
static uint8_t overheat_lowpass = 0;
static uint8_t underheat_lowpass = 0;
#define TEMPERATURE_TIMER_START (THERMAL_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // N seconds between thermal regulation events
- #define OVERHEAT_LOWPASS_STRENGTH ADC_CYCLES_PER_SECOND // lowpass for one second
- #define UNDERHEAT_LOWPASS_STRENGTH ADC_CYCLES_PER_SECOND // lowpass for one second
+ #define OVERHEAT_LOWPASS_STRENGTH (ADC_CYCLES_PER_SECOND*2) // lowpass for 2 seconds
+ #define UNDERHEAT_LOWPASS_STRENGTH (ADC_CYCLES_PER_SECOND*2) // lowpass for 2 seconds
#else
#define ADC_STEPS 2
#endif
@@ -190,33 +186,17 @@ ISR(ADC_vect) {
// prime on first execution
if (reset_thermal_history) {
reset_thermal_history = 0;
- for(uint8_t i=0; i<NUM_THERMAL_VALUES; i++)
- temperature_values[i] = temp;
+ temperature = temp;
for(uint8_t i=0; i<NUM_THERMAL_VALUES_HISTORY; i++)
- temperature_history[i] = temp<<1;
- for(uint8_t i=0; i<NUM_THERMAL_PROJECTED_HISTORY; i++)
- projected_temperature_history[i] = temp<<1;
- temperature = temp<<1;
+ temperature_history[i] = temp;
} else { // update our current temperature estimate
- uint8_t i;
- int16_t total=0;
-
- // rotate array
- // FIXME: just move the index, don't move the values?
- for(i=0; i<NUM_THERMAL_VALUES-1; i++) {
- temperature_values[i] = temperature_values[i+1];
- total += temperature_values[i];
+ // crude lowpass filter
+ // (limit rate of change to 1 degree per measurement)
+ if (temp > temperature) {
+ temperature ++;
+ } else if (temp < temperature) {
+ temperature --;
}
- temperature_values[i] = temp;
- total += temp;
-
- // Divide back to original range:
- //temperature = total >> 2;
- // More precise method: use noise as extra precision
- // (values are now basically fixed-point, signed 13.2)
- //temperature = total;
- // 14.1 is less prone to overflows
- temperature = total >> 2;
}
// guess what the temperature will be in a few seconds
@@ -230,18 +210,20 @@ ISR(ADC_vect) {
// how far ahead should we predict?
#define THERM_PREDICTION_STRENGTH 4
// how proportional should the adjustments be?
- #define THERM_DIFF_ATTENUATION 3
// acceptable temperature window size in C
- #define THERM_WINDOW_SIZE 10
+ #define THERM_WINDOW_SIZE 5
// highest temperature allowed
- // (convert configured value to 14.1 fixed-point)
- #define THERM_CEIL (((int16_t)therm_ceil)<<1)
- // bottom of target temperature window (14.1 fixed-point)
- #define THERM_FLOOR (THERM_CEIL - (THERM_WINDOW_SIZE<<1))
-
- // rotate measurements and add a new one
- for (i=0; i<NUM_THERMAL_VALUES_HISTORY-1; i++) {
- temperature_history[i] = temperature_history[i+1];
+ #define THERM_CEIL ((int16_t)therm_ceil)
+ // bottom of target temperature window
+ #define THERM_FLOOR (THERM_CEIL - THERM_WINDOW_SIZE)
+
+ // if it's time to rotate the thermal history, do it
+ history_step ++;
+ if (0 == (history_step & 7)) {
+ // rotate measurements and add a new one
+ for (i=0; i<NUM_THERMAL_VALUES_HISTORY-1; i++) {
+ temperature_history[i] = temperature_history[i+1];
+ }
}
temperature_history[NUM_THERMAL_VALUES_HISTORY-1] = t;
@@ -249,25 +231,16 @@ ISR(ADC_vect) {
// diff = rate of temperature change
//diff = temperature_history[NUM_THERMAL_VALUES_HISTORY-1] - temperature_history[0];
diff = t - temperature_history[0];
+ // slight bias toward zero; ignore very small changes (noise)
+ for (uint8_t z=0; z<3; z++) {
+ if (diff < 0) diff ++;
+ if (diff > 0) diff --;
+ }
// projected_temperature = current temp extended forward by amplified rate of change
//projected_temperature = temperature_history[NUM_THERMAL_VALUES_HISTORY-1] + (diff<<THERM_PREDICTION_STRENGTH);
pt = projected_temperature = t + (diff<<THERM_PREDICTION_STRENGTH);
-
- // store prediction for later averaging
- projected_temperature_history[projected_temperature_history_counter] = pt;
- projected_temperature_history_counter = (projected_temperature_history_counter + 1) & (NUM_THERMAL_PROJECTED_HISTORY-1);
}
- // average prediction to reduce noise
- int16_t avg_projected_temperature = 0;
- uint8_t i;
- for (i = 0;
- (i < NUM_THERMAL_PROJECTED_HISTORY) && (avg_projected_temperature < 16000);
- i++)
- avg_projected_temperature += projected_temperature_history[i];
- avg_projected_temperature /= NUM_THERMAL_PROJECTED_HISTORY;
- //avg_projected_temperature /= i;
-
// cancel counters if appropriate
if (pt > THERM_FLOOR) {
underheat_lowpass = 0; // we're probably not too cold
@@ -280,7 +253,7 @@ ISR(ADC_vect) {
} else { // it has been long enough since the last warning
// Too hot?
- if (avg_projected_temperature > THERM_CEIL) {
+ if (pt > THERM_CEIL) {
if (overheat_lowpass < OVERHEAT_LOWPASS_STRENGTH) {
overheat_lowpass ++;
} else {
@@ -288,16 +261,14 @@ ISR(ADC_vect) {
overheat_lowpass = 0;
temperature_timer = TEMPERATURE_TIMER_START;
// how far above the ceiling?
- int16_t howmuch = (avg_projected_temperature - THERM_CEIL) >> THERM_DIFF_ATTENUATION;
- if (howmuch > 0) {
- // try to send out a warning
- emit(EV_temperature_high, howmuch);
- }
+ int16_t howmuch = pt - THERM_CEIL;
+ // try to send out a warning
+ emit(EV_temperature_high, howmuch);
}
}
// Too cold?
- else if (avg_projected_temperature < THERM_FLOOR) {
+ else if (pt < THERM_FLOOR) {
if (underheat_lowpass < UNDERHEAT_LOWPASS_STRENGTH) {
underheat_lowpass ++;
} else {
@@ -305,13 +276,11 @@ ISR(ADC_vect) {
underheat_lowpass = 0;
temperature_timer = TEMPERATURE_TIMER_START;
// how far below the floor?
- int16_t howmuch = (THERM_FLOOR - avg_projected_temperature) >> THERM_DIFF_ATTENUATION;
- if (howmuch > 0) {
- // try to send out a warning (unless voltage is low)
- // (LVP and underheat warnings fight each other)
- if (voltage > VOLTAGE_LOW)
- emit(EV_temperature_low, howmuch);
- }
+ int16_t howmuch = THERM_FLOOR - pt;
+ // try to send out a warning (unless voltage is low)
+ // (LVP and underheat warnings fight each other)
+ if (voltage > VOLTAGE_LOW)
+ emit(EV_temperature_low, howmuch);
}
}
}
diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c
index e61fe00..9f953fa 100644
--- a/spaghetti-monster/fsm-misc.c
+++ b/spaghetti-monster/fsm-misc.c
@@ -146,5 +146,12 @@ void indicator_led_auto() {
*/
#endif // USE_INDICATOR_LED
+#ifdef USE_TRIANGLE_WAVE
+uint8_t triangle_wave(uint8_t phase) {
+ uint8_t result = phase << 1;
+ if (phase > 127) result = 255 - result;
+ return result;
+}
+#endif
#endif
diff --git a/spaghetti-monster/fsm-misc.h b/spaghetti-monster/fsm-misc.h
index 4e0eb4f..6e41b6c 100644
--- a/spaghetti-monster/fsm-misc.h
+++ b/spaghetti-monster/fsm-misc.h
@@ -46,5 +46,8 @@ uint8_t blink(uint8_t num, uint8_t speed);
void indicator_led(uint8_t lvl);
#endif
+#ifdef USE_TRIANGLE_WAVE
+uint8_t triangle_wave(uint8_t phase);
+#endif
#endif
diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c
index ee816dd..082f8c9 100644
--- a/spaghetti-monster/fsm-ramping.c
+++ b/spaghetti-monster/fsm-ramping.c
@@ -65,8 +65,31 @@ void set_level(uint8_t level) {
// and a global tint value
uint8_t brightness = pgm_read_byte(pwm1_levels + level);
uint8_t warm_PWM, cool_PWM;
- cool_PWM = (((uint16_t)tint * (uint16_t)brightness) + 127) / 255;
- warm_PWM = brightness - cool_PWM;
+
+ // auto-tint modes
+ uint8_t mytint;
+ #if 1
+ // perceptual by ramp level
+ if (tint == 0) { mytint = 255 * (uint16_t)level / RAMP_SIZE; }
+ else if (tint == 255) { mytint = 255 - (255 * (uint16_t)level / RAMP_SIZE); }
+ #else
+ // linear with power level
+ //if (tint == 0) { mytint = brightness; }
+ //else if (tint == 255) { mytint = 255 - brightness; }
+ #endif
+ // stretch 1-254 to fit 0-255 range (hits every value except 98 and 198)
+ else { mytint = (tint * 100 / 99) - 1; }
+
+ // middle tints sag, so correct for that effect
+ uint16_t base_PWM = brightness;
+ // correction is only necessary when PWM is fast
+ if (level > HALFSPEED_LEVEL) {
+ base_PWM = brightness
+ + ((((uint16_t)brightness) * 26 / 64) * triangle_wave(mytint) / 255);
+ }
+
+ cool_PWM = (((uint16_t)mytint * (uint16_t)base_PWM) + 127) / 255;
+ warm_PWM = base_PWM - cool_PWM;
PWM1_LVL = warm_PWM;
PWM2_LVL = cool_PWM;
diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h
index 4ce8015..dcc3b74 100644
--- a/spaghetti-monster/fsm-ramping.h
+++ b/spaghetti-monster/fsm-ramping.h
@@ -28,6 +28,7 @@ volatile uint8_t actual_level = 0;
#ifdef USE_TINT_RAMPING
uint8_t tint = 128;
+#define USE_TRIANGLE_WAVE
#endif
#ifdef USE_SET_LEVEL_GRADUALLY
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.