diff options
| author | Selene ToyKeeper | 2019-05-18 03:30:34 -0600 |
|---|---|---|
| committer | Selene ToyKeeper | 2019-05-18 03:30:34 -0600 |
| commit | 2f46400dd5c13bf715331695a699a21da57aeb7f (patch) | |
| tree | 6a00fdeaff532b558a7358b21c811ade29fe5a22 | |
| parent | Fixed an off-by-one error in lightning mode. (diff) | |
| parent | the lantern middle-tint power correction factor wasn't quite right... (diff) | |
| download | anduril-2f46400dd5c13bf715331695a699a21da57aeb7f.tar.gz anduril-2f46400dd5c13bf715331695a699a21da57aeb7f.tar.bz2 anduril-2f46400dd5c13bf715331695a699a21da57aeb7f.zip | |
merged in BLF Lantern branch, even though it's not quite finished, because it's a public project and long overdue for a merge
| -rw-r--r-- | spaghetti-monster/anduril/anduril.c | 176 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/cfg-blf-lantern.h | 78 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-misc.c | 7 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-misc.h | 3 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-ramping.c | 41 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-ramping.h | 5 |
6 files changed, 266 insertions, 44 deletions
diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 362dbeb..5878d47 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -145,6 +145,9 @@ typedef enum { ramp_discrete_ceil_e, ramp_discrete_steps_e, #endif + #ifdef USE_TINT_RAMPING + tint_e, + #endif #ifdef USE_STROBE_STATE strobe_type_e, #endif @@ -182,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" @@ -198,6 +207,10 @@ uint8_t steady_state(Event event, uint16_t arg); #ifdef USE_RAMP_CONFIG uint8_t ramp_config_state(Event event, uint16_t arg); #endif +#ifdef USE_TINT_RAMPING +// not actually a mode, more of a fallback under other modes +uint8_t tint_ramping_state(Event event, uint16_t arg); +#endif // party and tactical strobes #ifdef USE_STROBE_STATE uint8_t strobe_state(Event event, uint16_t arg); @@ -243,6 +256,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 @@ -255,6 +269,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 @@ -298,7 +315,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; @@ -376,6 +393,9 @@ volatile uint8_t bike_flasher_brightness = MAX_1x7135; #ifdef USE_CANDLE_MODE uint8_t candle_mode_state(Event event, uint16_t arg); uint8_t triangle_wave(uint8_t phase); +#ifndef CANDLE_AMPLITUDE +#define CANDLE_AMPLITUDE 25 +#endif #endif #ifdef USE_BEACON_MODE @@ -424,10 +444,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; @@ -605,8 +622,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; } @@ -657,8 +673,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) @@ -672,8 +687,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); @@ -719,8 +733,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) @@ -734,8 +747,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); @@ -806,10 +818,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) { @@ -837,10 +846,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); @@ -860,6 +866,69 @@ 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) { + // 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; + // remember tint after battery change + save_config(); + return EVENT_HANDLED; + } + + return EVENT_NOT_HANDLED; +} +#endif // ifdef USE_TINT_RAMPING + + #ifdef USE_STROBE_STATE uint8_t strobe_state(Event event, uint16_t arg) { // 'st' reduces ROM size by avoiding access to a volatile var @@ -1060,17 +1129,18 @@ inline void bike_flasher_iter() { #ifdef USE_CANDLE_MODE uint8_t candle_mode_state(Event event, uint16_t arg) { - // FIXME: make candle variance magnitude a compile-time option, - // since 20 is sometimes too much or too little, - // depending on the driver type and ramp shape - //#define MAX_CANDLE_LEVEL (RAMP_SIZE-8-6-4) - #define MAX_CANDLE_LEVEL (RAMP_SIZE/2) + #define MAX_CANDLE_LEVEL (RAMP_LENGTH-CANDLE_AMPLITUDE-15) static uint8_t candle_wave1 = 0; static uint8_t candle_wave2 = 0; static uint8_t candle_wave3 = 0; static uint8_t candle_wave2_speed = 0; - static uint8_t candle_wave2_depth = 7; - static uint8_t candle_wave3_depth = 4; + // these should add up to 100 + #define CANDLE_WAVE1_MAXDEPTH 30 + #define CANDLE_WAVE2_MAXDEPTH 45 + #define CANDLE_WAVE3_MAXDEPTH 25 + static const uint8_t candle_wave1_depth = CANDLE_WAVE1_MAXDEPTH * CANDLE_AMPLITUDE / 100; + static uint8_t candle_wave2_depth = CANDLE_WAVE2_MAXDEPTH * CANDLE_AMPLITUDE / 100; + static uint8_t candle_wave3_depth = CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100; static uint8_t candle_mode_brightness = 24; static uint8_t candle_mode_timer = 0; #define TICKS_PER_CANDLE_MINUTE 4096 // about 65 seconds @@ -1115,7 +1185,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { // self-timer dims the light during the final minute uint8_t subtract = 0; if (candle_mode_timer == 1) { - subtract = ((candle_mode_brightness+20) + subtract = ((candle_mode_brightness+CANDLE_AMPLITUDE) * ((arg & (TICKS_PER_CANDLE_MINUTE-1)) >> 4)) >> 8; } @@ -1132,7 +1202,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { } // 3-oscillator synth for a relatively organic pattern uint8_t add; - add = ((triangle_wave(candle_wave1) * 8) >> 8) + add = ((triangle_wave(candle_wave1) * candle_wave1_depth) >> 8) + ((triangle_wave(candle_wave2) * candle_wave2_depth) >> 8) + ((triangle_wave(candle_wave3) * candle_wave3_depth) >> 8); int8_t brightness = candle_mode_brightness + add - subtract; @@ -1140,6 +1210,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { set_level(brightness); // wave1: slow random LFO + // TODO: make wave slower and more erratic? if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; // wave2: medium-speed erratic LFO candle_wave2 += candle_wave2_speed; @@ -1152,8 +1223,10 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) candle_wave2_depth --; // random sawtooth retrigger - if ((pseudo_rand()) == 0) { - candle_wave2_depth = 7; + if (pseudo_rand() == 0) { + // random amplitude + //candle_wave2_depth = 2 + (pseudo_rand() % ((CANDLE_WAVE2_MAXDEPTH * CANDLE_AMPLITUDE / 100) - 2)); + candle_wave2_depth = pseudo_rand() % (CANDLE_WAVE2_MAXDEPTH * CANDLE_AMPLITUDE / 100); //candle_wave3_depth = 5; candle_wave2 = 0; } @@ -1161,17 +1234,13 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) candle_wave3_depth --; if ((pseudo_rand() & 0b01111111) == 0) - candle_wave3_depth = 5; + // random amplitude + //candle_wave3_depth = 2 + (pseudo_rand() % ((CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100) - 2)); + candle_wave3_depth = pseudo_rand() % (CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100); return MISCHIEF_MANAGED; } 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 @@ -1767,9 +1836,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 @@ -1901,6 +1970,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 @@ -1936,6 +2013,9 @@ void load_config() { ramp_discrete_ceil = eeprom[ramp_discrete_ceil_e]; ramp_discrete_steps = eeprom[ramp_discrete_steps_e]; #endif + #ifdef USE_TINT_RAMPING + tint = eeprom[tint_e]; + #endif #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) strobe_type = eeprom[strobe_type_e]; // TODO: move this to eeprom_wl? strobe_delays[0] = eeprom[strobe_delays_0_e]; @@ -1974,6 +2054,9 @@ void save_config() { eeprom[ramp_discrete_ceil_e] = ramp_discrete_ceil; eeprom[ramp_discrete_steps_e] = ramp_discrete_steps; #endif + #ifdef USE_TINT_RAMPING + eeprom[tint_e] = tint; + #endif #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) eeprom[strobe_type_e] = strobe_type; // TODO: move this to eeprom_wl? eeprom[strobe_delays_0_e] = strobe_delays[0]; @@ -2073,14 +2156,19 @@ void setup() { load_config(); + #ifdef USE_TINT_RAMPING + // add tint ramping underneath every other state + push_state(tint_ramping_state, 0); + #endif // ifdef USE_TINT_RAMPING + #ifdef USE_MUGGLE_MODE if (muggle_mode_active) push_state(muggle_state, (MUGGLE_FLOOR+MUGGLE_CEILING)/2); else #endif push_state(off_state, 0); - #endif + #endif // ifdef START_AT_MEMORIZED_LEVEL } diff --git a/spaghetti-monster/anduril/cfg-blf-lantern.h b/spaghetti-monster/anduril/cfg-blf-lantern.h new file mode 100644 index 0000000..9467397 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-blf-lantern.h @@ -0,0 +1,78 @@ +// BLF Lantern config options for Anduril +/* BLF Lantern pinout + * ---- + * Reset -|1 8|- VCC + * eswitch -|2 7|- powerbank enable? + * aux LED -|3 6|- PWM (5000K) + * GND -|4 5|- PWM (3000K) + * ---- + */ + +// basically the same as a Q8... sort of +#include "hwdef-BLF_Q8.h" + +// the button lights up +#define USE_INDICATOR_LED +// the button is visible while main LEDs are on +#define USE_INDICATOR_LED_WHILE_RAMPING +// enable blinking indicator LED while off +#define TICK_DURING_STANDBY +#define STANDBY_TICK_SPEED 3 // every 0.128 s +#define USE_FANCIER_BLINKING_INDICATOR +// off mode: high (2) +// lockout: blinking (3) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) + +// the lantern has two PWM channels, but they drive different sets of emitters +// (one channel for warm emitters, one channel for cold) +// so enable a special ramping mode which changes tint instead of brightness +#define USE_TINT_RAMPING + +#ifdef RAMP_LENGTH +#undef RAMP_LENGTH +#endif + +// level_calc.py 1 150 7135 1 30 800 +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,13,14,15,15,16,17,18,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,48,49,50,51,53,54,56,57,58,60,61,63,64,66,67,69,70,72,74,75,77,79,80,82,84,85,87,89,91,93,95,97,98,100,102,104,106,108,111,113,115,117,119,121,124,126,128,130,133,135,137,140,142,145,147,150,152,155,157,160,163,165,168,171,173,176,179,182,185,188,190,193,196,199,202,205,209,212,215,218,221,224,228,231,234,238,241,245,248,251,255 +#define MAX_1x7135 65 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 + +// the default of 26 looks a bit flat, so increase it +#define CANDLE_AMPLITUDE 40 + +// 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 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 5 + +// the sensor (attiny85) is nowhere near the emitters +// so thermal regulation can't work +#ifdef USE_THERMAL_REGULATION +#undef USE_THERMAL_REGULATION +#endif + +// also, the set_level_gradually() thing isn't compatible with tint ramping +// (but unsetting it here doesn't actually do anything, because the thermal +// regulation define enables it later... so this is mostly just a note to +// make this compatibility issue explicit) +#ifdef USE_SET_LEVEL_GRADUALLY +#undef USE_SET_LEVEL_GRADUALLY +#endif + +// don't blink while ramping +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#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/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 6cdf5e6..082f8c9 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -25,9 +25,11 @@ void set_level(uint8_t level) { actual_level = level; + #ifdef USE_SET_LEVEL_GRADUALLY gradual_target = level; #endif + #ifdef USE_INDICATOR_LED #ifdef USE_INDICATOR_LED_WHILE_RAMPING if (! go_to_standby) @@ -40,6 +42,7 @@ void set_level(uint8_t level) { indicator_led(0); #endif #endif + //TCCR0A = PHASE; if (level == 0) { #if PWM_CHANNELS >= 1 @@ -56,6 +59,42 @@ void set_level(uint8_t level) { #endif } else { level --; + + #ifdef USE_TINT_RAMPING + // calculate actual PWM levels based on a single-channel ramp + // and a global tint value + uint8_t brightness = pgm_read_byte(pwm1_levels + level); + uint8_t warm_PWM, 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; + #else + #if PWM_CHANNELS >= 1 PWM1_LVL = pgm_read_byte(pwm1_levels + level); #endif @@ -68,6 +107,8 @@ void set_level(uint8_t level) { #if PWM_CHANNELS >= 4 PWM4_LVL = pgm_read_byte(pwm4_levels + level); #endif + + #endif // ifdef USE_TINT_RAMPING } #ifdef USE_DYNAMIC_UNDERCLOCKING auto_clock_speed(); diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 14c8dae..dcc3b74 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -26,6 +26,11 @@ // actual_level: last ramp level set by set_level() volatile uint8_t actual_level = 0; +#ifdef USE_TINT_RAMPING +uint8_t tint = 128; +#define USE_TRIANGLE_WAVE +#endif + #ifdef USE_SET_LEVEL_GRADUALLY // adjust brightness very smoothly volatile uint8_t gradual_target; |
