From 6df24c19ab413e4a15c6afd9e9d71c8145f8895c Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 9 May 2018 14:06:56 -0600 Subject: Documented how to configure indicator LED level while off. --- spaghetti-monster/anduril/anduril.txt | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/anduril.txt b/spaghetti-monster/anduril/anduril.txt index 531609d..fadd7d0 100644 --- a/spaghetti-monster/anduril/anduril.txt +++ b/spaghetti-monster/anduril/anduril.txt @@ -110,6 +110,9 @@ Discrete ramp config mode: Lockout mode: * Hold: momentary moon * 4 clicks: exit lockout (return to regular "off" mode) + * On hardware with an indicator LED... + * 3 clicks: Change button brightness used in lockout mode. (low/high/off) + * Click, click, hold: Change button brightness used in "off" mode. Momentary mode: * Press button: Light on (at memorized level). @@ -121,6 +124,26 @@ Muggle mode: * Hold: Ramp up / down. * 6 clicks: Exit muggle mode. +Indicator LED support: + + The indicator LED, if there is one, tracks the brightness of the main + LED(s) during use. It'll be off, low, or high depending on whether + the main emitter is off, using only the first power channel, or using + a higher level. + + The indicator LED can stay on when the light is in the "off" state or + lockout state. The user can configure each state to be low, high, or + off. To configure it: + + 1. Go to lockout mode. (4 clicks) + 2. Click 3 times, optionally holding the third press, to change the + value: + * 3 fast clicks: Change lockout mode button brightness. + * Hold the third click: Change regular "off" mode button + brightness. Let go when desired level is reached. + 3. Exit lockout mode. (4 clicks) + + TODO: * save settings in eeprom * decide on "hold until hot" or "click N times" for thermal config mode @@ -128,7 +151,10 @@ TODO: * improve thermal regulation - a way to blink out the firmware version? * indicator LED support - * a way to configure indicator LED behavior? + * a way to configure indicator LED behavior + * Go to lockout mode, then click three times. Hold the third click + to change regular "off" brightness, or make it a fast click to + change lockout mode brightness. * add goodnight mode? * add lightning mode? * muggle mode: smooth ramp -- cgit v1.2.3 From b178a530fa654f6af52912d75b0f1e8eafe59035 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 16 Jun 2018 23:59:02 -0600 Subject: Added dual-switch support (tail clicky + e-switch) to muggle mode. --- spaghetti-monster/anduril/anduril.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 26db6d8..4eba836 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -1040,13 +1040,25 @@ uint8_t muggle_state(EventPtr event, uint16_t arg) { // turn LED off when we first enter the mode if (event == EV_enter_state) { - muggle_mode_active = 1; - save_config(); - - muggle_off_mode = 1; ramp_direction = 1; - //memorized_level = MAX_1x7135; - memorized_level = (MUGGLE_FLOOR + MUGGLE_CEILING) / 2; + + #ifdef START_AT_MEMORIZED_LEVEL + memorized_level = arg; + muggle_off_mode = 0; + set_level(memorized_level); + + if (! muggle_mode_active) { // don't write eeprom at every boot + muggle_mode_active = 1; + save_config(); + } + #else + muggle_mode_active = 1; + save_config(); + + muggle_off_mode = 1; + //memorized_level = MAX_1x7135; + memorized_level = (MUGGLE_FLOOR + MUGGLE_CEILING) / 2; + #endif return MISCHIEF_MANAGED; } // initial press: moon hint @@ -1107,6 +1119,9 @@ uint8_t muggle_state(EventPtr event, uint16_t arg) { // reverse ramp direction on hold release else if (event == EV_click1_hold_release) { ramp_direction = -ramp_direction; + #ifdef START_AT_MEMORIZED_LEVEL + save_config_wl(); // momentary use should retain brightness level + #endif return MISCHIEF_MANAGED; } /* @@ -1513,6 +1528,12 @@ void setup() { // dual switch: e-switch + power clicky // power clicky acts as a momentary mode load_config(); + + #ifdef USE_MUGGLE_MODE + if (muggle_mode_active) + push_state(muggle_state, memorized_level); + else + #endif if (button_is_pressed()) // hold button to go to moon push_state(steady_state, 1); @@ -1520,7 +1541,7 @@ void setup() { // otherwise use memory push_state(steady_state, memorized_level); - #else + #else // if not START_AT_MEMORIZED_LEVEL // blink at power-on to let user know power is connected set_level(RAMP_SIZE/8); @@ -1531,7 +1552,7 @@ void setup() { #ifdef USE_MUGGLE_MODE if (muggle_mode_active) - push_state(muggle_state, 0); + push_state(muggle_state, (MUGGLE_FLOOR+MUGGLE_CEILING)/2); else #endif push_state(off_state, 0); -- cgit v1.2.3 From cfedb2eaf4a0d62969ff05307ac40d4f1cdab2d9 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 17 Jun 2018 18:18:38 -0600 Subject: Implemented halfsleep mode. Will probably change it quite a bit though, so I'm checking in changes first. Needs to be "tick during standby" instead of "half sleep". --- spaghetti-monster/fsm-events.h | 6 ++++++ spaghetti-monster/fsm-standby.c | 38 +++++++++++++++++++++++++++++++------- spaghetti-monster/fsm-standby.h | 7 +++++-- spaghetti-monster/fsm-wdt.c | 17 +++++++++++++++++ spaghetti-monster/fsm-wdt.h | 4 ++++ 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h index 2721303..84e9ea2 100644 --- a/spaghetti-monster/fsm-events.h +++ b/spaghetti-monster/fsm-events.h @@ -64,6 +64,7 @@ static volatile uint16_t ticks_since_last_event = 0; #define A_OVERHEATING 9 #define A_UNDERHEATING 10 #define A_VOLTAGE_LOW 11 +#define A_HALFSLEEP_TICK 12 //#define A_VOLTAGE_CRITICAL 12 #define A_DEBUG 255 // test event for debugging @@ -83,6 +84,11 @@ Event EV_reenter_state[] = { Event EV_tick[] = { A_TICK, 0 } ; +#ifdef USE_HALFSLEEP_MODE +Event EV_halfsleep_tick[] = { + A_HALFSLEEP_TICK, + 0 } ; +#endif #ifdef USE_LVP Event EV_voltage_low[] = { A_VOLTAGE_LOW, diff --git a/spaghetti-monster/fsm-standby.c b/spaghetti-monster/fsm-standby.c index b90ccea..8e51dda 100644 --- a/spaghetti-monster/fsm-standby.c +++ b/spaghetti-monster/fsm-standby.c @@ -31,7 +31,17 @@ #define standby_mode sleep_until_eswitch_pressed void sleep_until_eswitch_pressed() { + #ifdef USE_HALFSLEEP_MODE + //uint16_t sleep_counter = 0; + if (halfsleep_mode) { + // set WDT to slow mode + wdt_reset(); + WDTCR |= (1<> 2; + #ifdef TICK_DURING_STANDBY + mode = (mode + 1) & 3; + #else mode = (mode + 1) % 3; + #endif indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); indicator_led(mode); save_config(); @@ -978,9 +1004,20 @@ uint8_t lockout_state(EventPtr event, uint16_t arg) { } // click, click, hold: rotate through indicator LED modes (off mode) else if (event == EV_click3_hold) { + #ifdef TICK_DURING_STANDBY + uint8_t mode = (arg >> 5) & 3; + #else uint8_t mode = (arg >> 5) % 3; + #endif indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; + #ifdef TICK_DURING_STANDBY + if (mode == 3) + indicator_led(mode & (arg&3)); + else + indicator_led(mode); + #else indicator_led(mode); + #endif //save_config(); return MISCHIEF_MANAGED; } @@ -1407,6 +1444,19 @@ void blink_confirm(uint8_t num) { } +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +// beacon-like mode for the indicator LED +void indicator_blink(uint8_t arg) { + if (! (arg & 7)) { + indicator_led(2); + } + else { + indicator_led(0); + } +} +#endif + + #ifdef USE_PSEUDO_RAND uint8_t pseudo_rand() { static uint16_t offset = 1024; diff --git a/spaghetti-monster/anduril/anduril.txt b/spaghetti-monster/anduril/anduril.txt index fadd7d0..e74ce87 100644 --- a/spaghetti-monster/anduril/anduril.txt +++ b/spaghetti-monster/anduril/anduril.txt @@ -84,7 +84,7 @@ Discrete ramp config mode: Beacon mode: * 1 click: off * 2 clicks: tempcheck mode - * 3 clicks: configure time between pulses + * 4 clicks: configure time between pulses Beacon config mode: * At buzz, click N times to set beacon frequency to N seconds. @@ -92,7 +92,7 @@ Discrete ramp config mode: Tempcheck mode: * 1 click: off * 2 clicks: battcheck mode - * 3 clicks: thermal config mode + * 4 clicks: thermal config mode - Hold: thermal calibration mode Thermal config mode: diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h index 84e9ea2..4a67347 100644 --- a/spaghetti-monster/fsm-events.h +++ b/spaghetti-monster/fsm-events.h @@ -42,10 +42,9 @@ typedef struct Emission { #define EV_MAX_LEN ((MAX_CLICKS*2)+3) uint8_t current_event[EV_MAX_LEN]; // at 0.016 ms per tick, 255 ticks = 4.08 s -// TODO: 16 bits? static volatile uint16_t ticks_since_last_event = 0; -// timeout durations in ticks (each tick 1/60th s) +// timeout durations in ticks (each tick 1/62th s) #ifndef HOLD_TIMEOUT #define HOLD_TIMEOUT 24 #endif @@ -57,15 +56,15 @@ static volatile uint16_t ticks_since_last_event = 0; #define A_LEAVE_STATE 2 #define A_REENTER_STATE 3 #define A_TICK 4 -#define A_PRESS 5 -#define A_HOLD 6 -#define A_RELEASE 7 -#define A_RELEASE_TIMEOUT 8 -#define A_OVERHEATING 9 -#define A_UNDERHEATING 10 -#define A_VOLTAGE_LOW 11 -#define A_HALFSLEEP_TICK 12 -//#define A_VOLTAGE_CRITICAL 12 +#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 types @@ -84,9 +83,9 @@ Event EV_reenter_state[] = { Event EV_tick[] = { A_TICK, 0 } ; -#ifdef USE_HALFSLEEP_MODE -Event EV_halfsleep_tick[] = { - A_HALFSLEEP_TICK, +#ifdef TICK_DURING_STANDBY +Event EV_sleep_tick[] = { + A_SLEEP_TICK, 0 } ; #endif #ifdef USE_LVP diff --git a/spaghetti-monster/fsm-main.c b/spaghetti-monster/fsm-main.c index 8f21846..b0b44fb 100644 --- a/spaghetti-monster/fsm-main.c +++ b/spaghetti-monster/fsm-main.c @@ -126,7 +126,6 @@ int main() { PWM4_LVL = 255; // inverted :( #endif #endif - go_to_standby = 0; standby_mode(); } diff --git a/spaghetti-monster/fsm-standby.c b/spaghetti-monster/fsm-standby.c index 8e51dda..7d60c1d 100644 --- a/spaghetti-monster/fsm-standby.c +++ b/spaghetti-monster/fsm-standby.c @@ -31,16 +31,11 @@ #define standby_mode sleep_until_eswitch_pressed void sleep_until_eswitch_pressed() { - #ifdef USE_HALFSLEEP_MODE - //uint16_t sleep_counter = 0; - if (halfsleep_mode) { - // set WDT to slow mode - wdt_reset(); - WDTCR |= (1< 0) + (level > MAX_1x7135)); //if (level > MAX_1x7135) indicator_led(2); //else if (level > 0) indicator_led(1); //else if (! go_to_standby) indicator_led(0); + #else + indicator_led(0); + #endif #endif //TCCR0A = PHASE; if (level == 0) { -- cgit v1.2.3 From 55e75b9da0c435ad89165ef6c0eb38e9dd9c65fb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 17 Jun 2018 19:46:02 -0600 Subject: Made thermal response faster at high levels. Not yet tested. --- spaghetti-monster/anduril/anduril.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index b64d487..ca8a138 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -29,6 +29,11 @@ #define USE_THERMAL_REGULATION #define DEFAULT_THERM_CEIL 50 #define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#ifdef MAX_Nx7135 +#define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 // throttle back faster when high +#else +#define THERM_DOUBLE_SPEED_LEVEL (RAMP_LENGTH*4/5) // throttle back faster when high +#endif #define USE_SET_LEVEL_GRADUALLY #define BLINK_AT_CHANNEL_BOUNDARIES //#define BLINK_AT_RAMP_FLOOR @@ -586,12 +591,22 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { // make thermal adjustment speed scale with magnitude if (arg & 1) return MISCHIEF_MANAGED; // adjust slower // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] - uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; + //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; + // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 132, 71, 38, 20, 10, 5, 3}; + // [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)] + uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2}; uint8_t diff; static uint8_t ticks_since_adjust = 0; ticks_since_adjust ++; if (target_level > actual_level) diff = target_level - actual_level; - else diff = actual_level - target_level; + else { + diff = actual_level - target_level; + // if we're on a really high mode, drop faster + if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { + diff <<= 1; + } + } uint8_t magnitude = 0; while (diff) { magnitude ++; -- cgit v1.2.3 From f1871e8e1ee4461a51ed331ce0ba3b51b42b32e5 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 23 Jun 2018 02:08:08 -0600 Subject: Don't auto-shutoff indicator LED when entering standby mode. --- spaghetti-monster/fsm-ramping.c | 1 + 1 file changed, 1 insertion(+) diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index 01df46a..6cdf5e6 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -36,6 +36,7 @@ void set_level(uint8_t level) { //else if (level > 0) indicator_led(1); //else if (! go_to_standby) indicator_led(0); #else + if (! go_to_standby) indicator_led(0); #endif #endif -- cgit v1.2.3 From e2f73d62df6e7b79483b571cd744701e233cf94a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 23 Jun 2018 02:10:12 -0600 Subject: Moved pseudo_rand() into its own header, and made it gather entropy from ADC readings to improve randomness. Adjusted candle mode to use lower bits instead of upper bits, because the lower bits are more random. (also, the lower-bit method is slightly smaller in ROM) --- spaghetti-monster/anduril/anduril.c | 36 ++++++++++------------------------- spaghetti-monster/anduril/anduril.txt | 3 ++- spaghetti-monster/fsm-adc.c | 5 +++++ spaghetti-monster/fsm-random.c | 33 ++++++++++++++++++++++++++++++++ spaghetti-monster/fsm-random.h | 29 ++++++++++++++++++++++++++++ spaghetti-monster/spaghetti-monster.h | 2 ++ 6 files changed, 81 insertions(+), 27 deletions(-) create mode 100644 spaghetti-monster/fsm-random.c create mode 100644 spaghetti-monster/fsm-random.h diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index ca8a138..2ee18e8 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -253,11 +253,6 @@ volatile uint8_t strobe_type = 4; // bike mode config options volatile uint8_t bike_flasher_brightness = MAX_1x7135; -#ifdef USE_PSEUDO_RAND -volatile uint8_t pseudo_rand_seed = 0; -uint8_t pseudo_rand(); -#endif - #ifdef USE_CANDLE_MODE uint8_t triangle_wave(uint8_t phase); #endif @@ -821,16 +816,16 @@ uint8_t strobe_state(EventPtr event, uint16_t arg) { set_level(brightness); // wave1: slow random LFO - if ((arg & 1) == 0) candle_wave1 += pseudo_rand()&1; + if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; // wave2: medium-speed erratic LFO candle_wave2 += candle_wave2_speed; // wave3: erratic fast wave - candle_wave3 += pseudo_rand()%37; + candle_wave3 += pseudo_rand() % 37; // S&H on wave2 frequency to make it more erratic - if ((pseudo_rand()>>2) == 0) - candle_wave2_speed = pseudo_rand()%13; + if ((pseudo_rand() & 0b00111111) == 0) + candle_wave2_speed = pseudo_rand() % 13; // downward sawtooth on wave2 depth to simulate stabilizing - if ((candle_wave2_depth > 0) && ((pseudo_rand()>>2) == 0)) + if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) candle_wave2_depth --; // random sawtooth retrigger if ((pseudo_rand()) == 0) { @@ -839,9 +834,9 @@ uint8_t strobe_state(EventPtr event, uint16_t arg) { candle_wave2 = 0; } // downward sawtooth on wave3 depth to simulate stabilizing - if ((candle_wave3_depth > 2) && ((pseudo_rand()>>3) == 0)) + if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) candle_wave3_depth --; - if ((pseudo_rand()>>1) == 0) + if ((pseudo_rand() & 0b01111111) == 0) candle_wave3_depth = 5; } #endif @@ -1475,17 +1470,6 @@ void indicator_blink(uint8_t arg) { #endif -#ifdef USE_PSEUDO_RAND -uint8_t pseudo_rand() { - static uint16_t offset = 1024; - // loop from 1024 to 4095 - offset = ((offset + 1) & 0x0fff) | 0x0400; - pseudo_rand_seed += 0b01010101; // 85 - return pgm_read_byte(offset) + pseudo_rand_seed; -} -#endif - - #ifdef USE_CANDLE_MODE uint8_t triangle_wave(uint8_t phase) { uint8_t result = phase << 1; @@ -1688,7 +1672,7 @@ void loop() { //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() & 0x03); // 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); @@ -1717,8 +1701,8 @@ void loop() { // turn the emitter off, // for a random amount of time between 1ms and 8192ms // (with a low bias) - rand_time = 1<<(pseudo_rand()%13); - rand_time += pseudo_rand()%rand_time; + rand_time = 1 << (pseudo_rand() % 13); + rand_time += pseudo_rand() % rand_time; set_level(0); nice_delay_ms(rand_time); diff --git a/spaghetti-monster/anduril/anduril.txt b/spaghetti-monster/anduril/anduril.txt index e74ce87..9cbef68 100644 --- a/spaghetti-monster/anduril/anduril.txt +++ b/spaghetti-monster/anduril/anduril.txt @@ -161,6 +161,7 @@ TODO: * refactor to make config modes smaller * move all config menus to four clicks * candle mode timer, with three clicks to add 30 minutes - - diagram updates for 3-click special actions + * diagram updates for 3-click special actions - candle mode: smoother adjustments? - make sunset mode timer and brightness configurable? + - make beacon mode actually sleep between pulses diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 6e9f19b..2ec630c 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -109,6 +109,11 @@ ISR(ADC_vect) { uint16_t measurement = ADC; // latest 10-bit ADC reading + #ifdef USE_PSEUDO_RAND + // real-world entropy makes this a true random, not pseudo + pseudo_rand_seed += measurement; + #endif + adc_step = (adc_step + 1) & (ADC_STEPS-1); #ifdef USE_LVP diff --git a/spaghetti-monster/fsm-random.c b/spaghetti-monster/fsm-random.c new file mode 100644 index 0000000..1f83bce --- /dev/null +++ b/spaghetti-monster/fsm-random.c @@ -0,0 +1,33 @@ +/* + * fsm-random.c: Random number generator 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 . + */ + +#ifndef FSM_RANDOM_C +#define FSM_RANDOM_C + +#ifdef USE_PSEUDO_RAND +uint8_t pseudo_rand() { + static uint16_t offset = 1024; + // loop from 1024 to 4095 + offset = ((offset + 1) & 0x0fff) | 0x0400; + pseudo_rand_seed += 0b01010101; // 85 + return pgm_read_byte(offset) + pseudo_rand_seed; +} +#endif + +#endif diff --git a/spaghetti-monster/fsm-random.h b/spaghetti-monster/fsm-random.h new file mode 100644 index 0000000..720f6f2 --- /dev/null +++ b/spaghetti-monster/fsm-random.h @@ -0,0 +1,29 @@ +/* + * fsm-random.h: Random number generator 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 . + */ + +#ifndef FSM_RANDOM_H +#define FSM_RANDOM_H + +#ifdef USE_PSEUDO_RAND +uint8_t pseudo_rand(); +// TODO: test without "volatile", in case it's not needed +volatile uint8_t pseudo_rand_seed = 0; +#endif + +#endif diff --git a/spaghetti-monster/spaghetti-monster.h b/spaghetti-monster/spaghetti-monster.h index 5599bca..08690b4 100644 --- a/spaghetti-monster/spaghetti-monster.h +++ b/spaghetti-monster/spaghetti-monster.h @@ -34,6 +34,7 @@ #include "fsm-pcint.h" #include "fsm-standby.h" #include "fsm-ramping.h" +#include "fsm-random.h" #ifdef USE_EEPROM #include "fsm-eeprom.h" #endif @@ -71,6 +72,7 @@ void loop(); #include "fsm-pcint.c" #include "fsm-standby.c" #include "fsm-ramping.c" +#include "fsm-random.c" #ifdef USE_EEPROM #include "fsm-eeprom.c" #endif -- cgit v1.2.3 From bb419e016d98b611a1ed5303737a966050605f52 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 24 Jun 2018 18:05:38 -0600 Subject: Added script to build all supported Anduril targets. --- bin/build-25.sh | 8 ++++++-- bin/build-85.sh | 8 ++++++-- bin/build.sh | 8 ++++++-- spaghetti-monster/anduril/anduril.c | 10 +++++----- spaghetti-monster/anduril/build-all.sh | 12 ++++++++++++ 5 files changed, 35 insertions(+), 11 deletions(-) create mode 100755 spaghetti-monster/anduril/build-all.sh diff --git a/bin/build-25.sh b/bin/build-25.sh index 2c58db5..2be8269 100755 --- a/bin/build-25.sh +++ b/bin/build-25.sh @@ -3,7 +3,7 @@ # Instead of using a Makefile, since most of the firmwares here build in the # same exact way, here's a script to do the same thing -export PROGRAM=$1 +export PROGRAM=$1 ; shift export ATTINY=25 export MCU=attiny$ATTINY export CC=avr-gcc @@ -14,13 +14,17 @@ export LDFLAGS= export OBJCOPYFLAGS='--set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex' export OBJS=$PROGRAM.o +for arg in "$*" ; do + OTHERFLAGS="$OTHERFLAGS $arg" +done + function run () { echo $* $* if [ x"$?" != x0 ]; then exit 1 ; fi } -run $CC $CFLAGS -o $PROGRAM.o -c $PROGRAM.c +run $CC $OTHERFLAGS $CFLAGS -o $PROGRAM.o -c $PROGRAM.c run $CC $OFLAGS $LDFLAGS -o $PROGRAM.elf $PROGRAM.o run $OBJCOPY $OBJCOPYFLAGS $PROGRAM.elf $PROGRAM.hex run avr-size -C --mcu=$MCU $PROGRAM.elf | grep Full diff --git a/bin/build-85.sh b/bin/build-85.sh index 8b2937d..8e3704b 100755 --- a/bin/build-85.sh +++ b/bin/build-85.sh @@ -3,7 +3,7 @@ # Instead of using a Makefile, since most of the firmwares here build in the # same exact way, here's a script to do the same thing -export PROGRAM=$1 +export PROGRAM=$1 ; shift export ATTINY=85 export MCU=attiny$ATTINY export CC=avr-gcc @@ -14,13 +14,17 @@ export LDFLAGS= export OBJCOPYFLAGS='--set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex' export OBJS=$PROGRAM.o +for arg in "$*" ; do + OTHERFLAGS="$OTHERFLAGS $arg" +done + function run () { echo $* $* if [ x"$?" != x0 ]; then exit 1 ; fi } -run $CC $CFLAGS -o $PROGRAM.o -c $PROGRAM.c +run $CC $OTHERFLAGS $CFLAGS -o $PROGRAM.o -c $PROGRAM.c run $CC $OFLAGS $LDFLAGS -o $PROGRAM.elf $PROGRAM.o run $OBJCOPY $OBJCOPYFLAGS $PROGRAM.elf $PROGRAM.hex run avr-size -C --mcu=$MCU $PROGRAM.elf | grep Full diff --git a/bin/build.sh b/bin/build.sh index 68f981d..86afd1d 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -3,7 +3,7 @@ # Instead of using a Makefile, since most of the firmwares here build in the # same exact way, here's a script to do the same thing -export PROGRAM=$1 +export PROGRAM=$1 ; shift export ATTINY=13 export MCU=attiny$ATTINY export CC=avr-gcc @@ -14,13 +14,17 @@ export LDFLAGS= export OBJCOPYFLAGS='--set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex' export OBJS=$PROGRAM.o +for arg in "$*" ; do + OTHERFLAGS="$OTHERFLAGS $arg" +done + function run () { echo $* $* if [ x"$?" != x0 ]; then exit 1 ; fi } -run $CC $CFLAGS -o $PROGRAM.o -c $PROGRAM.c +run $CC $OTHERFLAGS $CFLAGS -o $PROGRAM.o -c $PROGRAM.c run $CC $OFLAGS $LDFLAGS -o $PROGRAM.elf $PROGRAM.o run $OBJCOPY $OBJCOPYFLAGS $PROGRAM.elf $PROGRAM.hex run avr-size -C --mcu=$MCU $PROGRAM.elf | grep Full diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 2ee18e8..3d25c8c 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -19,8 +19,8 @@ */ /********* User-configurable options *********/ -// Physical driver type -#define FSM_EMISAR_D4_DRIVER +// Physical driver type (uncomment one of the following or define it at the gcc command line) +//#define FSM_EMISAR_D4_DRIVER //#define FSM_BLF_Q8_DRIVER //#define FSM_FW3A_DRIVER //#define FSM_BLF_GT_DRIVER @@ -1644,7 +1644,7 @@ void loop() { set_level(bike_flasher_brightness); if (! nice_delay_ms(65)) return; } - if (! nice_delay_ms(720)) return; + nice_delay_ms(720); // no return check necessary on final delay } // party / tactical strobe else if (st < 3) { @@ -1659,7 +1659,7 @@ void loop() { nice_delay_ms(del >> 1); } set_level(0); - nice_delay_ms(del); + nice_delay_ms(del); // no return check necessary on final delay } #ifdef USE_LIGHTNING_MODE // lightning storm @@ -1704,7 +1704,7 @@ void loop() { rand_time = 1 << (pseudo_rand() % 13); rand_time += pseudo_rand() % rand_time; set_level(0); - nice_delay_ms(rand_time); + nice_delay_ms(rand_time); // no return check necessary on final delay } #endif diff --git a/spaghetti-monster/anduril/build-all.sh b/spaghetti-monster/anduril/build-all.sh new file mode 100755 index 0000000..4100805 --- /dev/null +++ b/spaghetti-monster/anduril/build-all.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +for TARGET in \ + BLF_GT \ + BLF_Q8 \ + EMISAR_D4 \ + FW3A \ + ; do + echo "===== $TARGET =====" + ../../../bin/build-85.sh anduril "-DFSM_${TARGET}_DRIVER" + mv -f anduril.hex anduril.$TARGET.hex +done -- cgit v1.2.3 From 80967413d823d7d23a2b44caf715c850b38169ea Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 24 Jun 2018 18:08:59 -0600 Subject: Initial D4S support for Anduril. (but only the parts which can't be public yet) --- spaghetti-monster/anduril/anduril.c | 19 +++++++++++++++++-- spaghetti-monster/fsm-ramping.h | 20 ++++++++++++++++++++ tk-attiny.h | 6 ++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 3d25c8c..2fec5b4 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -21,6 +21,7 @@ /********* User-configurable options *********/ // Physical driver type (uncomment one of the following or define it at the gcc command line) //#define FSM_EMISAR_D4_DRIVER +//#define FSM_EMISAR_D4S_DRIVER //#define FSM_BLF_Q8_DRIVER //#define FSM_FW3A_DRIVER //#define FSM_BLF_GT_DRIVER @@ -71,6 +72,16 @@ #define TICK_DURING_STANDBY #define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#elif defined(FSM_EMISAR_D4S_DRIVER) +#define USE_INDICATOR_LED +#define TICK_DURING_STANDBY +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +#define RAMP_SMOOTH_CEIL (MAX_LEVEL*4/5) +#undef MIN_THERM_STEPDOWN // this should be lower, because 3x7135 instead of 1x7135 +#define MIN_THERM_STEPDOWN 60 // lowest value it'll step down to +#undef THERM_DOUBLE_SPEED_LEVEL // this should be lower too, because this light is a hot rod +#define THERM_DOUBLE_SPEED_LEVEL (RAMP_LENGTH*2/3) // throttle back faster when high + #elif defined(FSM_EMISAR_D4_DRIVER) #define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V @@ -227,8 +238,12 @@ uint8_t ramp_discrete_step_size; // don't set this // bits 0-1 control "off" mode // modes are: 0=off, 1=low, 2=high // (TODO: 3=blinking) -//uint8_t indicator_led_mode = (1<<2) + 2; -uint8_t indicator_led_mode = (2<<2) + 1; +#ifdef FSM_EMISAR_D4S_DRIVER +uint8_t indicator_led_mode = (3<<2) + 1; +#else +uint8_t indicator_led_mode = (1<<2) + 2; +//uint8_t indicator_led_mode = (2<<2) + 1; +#endif #endif // calculate the nearest ramp level which would be valid at the moment diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 86742f6..d530f6a 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -73,6 +73,26 @@ void gradual_tick(); #define MAX_1x7135 60 // where it switches from PWM to current control #define HALFSPEED_LEVEL 17 #define QUARTERSPEED_LEVEL 6 + #elif defined(FSM_EMISAR_D4S_DRIVER) + // 3x7135 + FET + #if 0 + // ../../bin/level_calc.py 2 150 7135 1 6 450 FET 1 10 1810 + // (because it made the ramp look better than accurate values) + PROGMEM const uint8_t pwm1_levels[] = { 1,1,2,2,3,3,4,5,5,6,7,7,8,9,10,11,12,13,14,15,16,18,19,20,22,23,25,26,28,30,32,33,35,37,39,42,44,46,48,51,53,56,58,61,64,67,70,73,76,79,83,86,89,93,97,100,104,108,112,116,121,125,129,134,139,143,148,153,158,163,169,174,180,185,191,197,203,209,215,222,228,235,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,255,255,255,255,255,255,255,255,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,6,9,11,14,16,19,22,24,27,30,33,36,39,42,45,48,51,54,57,61,64,67,71,74,78,82,85,89,93,96,100,104,108,112,116,121,125,129,133,138,142,147,151,156,160,165,170,175,180,185,190,195,200,205,210,216,221,227,232,238,243,249,255 }; + #define MAX_1x7135 85 + #define HALFSPEED_LEVEL 11 + #define QUARTERSPEED_LEVEL 5 + #else + // ../../bin/level_calc.py 2 150 7135 1 11.2 450 FET 1 10 4000 + // (with a x**9 curve instead of x**3) + // (because it made the ramp look better than accurate values) + PROGMEM const uint8_t 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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,10,11,13,14,16,18,19,21,23,25,27,29,31,34,36,38,41,43,46,48,51,54,57,60,63,66,69,72,76,79,83,87,91,95,99,103,107,112,116,121,126,131,136,141,146,152,158,163,169,175,182,188,195,202,209,216,223,231,239,247,255 }; + #define MAX_1x7135 83 + #define HALFSPEED_LEVEL 13 + #define QUARTERSPEED_LEVEL 6 + #endif #else // ../../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 }; diff --git a/tk-attiny.h b/tk-attiny.h index d81468b..347acc7 100644 --- a/tk-attiny.h +++ b/tk-attiny.h @@ -174,6 +174,12 @@ #endif +// D4S driver is the same as a D4, basically +#ifdef FSM_EMISAR_D4S_DRIVER +#define FSM_EMISAR_D4_DRIVER +#endif + + #ifdef FSM_EMISAR_D4_DRIVER #define DRIVER_TYPE_DEFINED /* -- cgit v1.2.3 From 809a397855a2a5ff9fdb327a7a30aa639f829b51 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 24 Jun 2018 18:55:19 -0600 Subject: Moved driver-specific details to separate header files. General code cleanup and notes. Fixed build when thermal regulation is turned off. May have fixed (or at least improved) issue with main LED interfering with aux LEDs during aux LED config. --- spaghetti-monster/anduril/anduril.c | 87 ++++++++++++++++++------------- spaghetti-monster/anduril/cfg-blf-gt.h | 25 +++++++++ spaghetti-monster/anduril/cfg-blf-q8.h | 9 ++++ spaghetti-monster/anduril/cfg-emisar-d4.h | 2 + spaghetti-monster/anduril/cfg-fw3a.h | 2 + 5 files changed, 88 insertions(+), 37 deletions(-) create mode 100644 spaghetti-monster/anduril/cfg-blf-gt.h create mode 100644 spaghetti-monster/anduril/cfg-blf-q8.h create mode 100644 spaghetti-monster/anduril/cfg-emisar-d4.h create mode 100644 spaghetti-monster/anduril/cfg-fw3a.h diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 3d25c8c..abd3ed8 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -25,7 +25,8 @@ //#define FSM_FW3A_DRIVER //#define FSM_BLF_GT_DRIVER -#define USE_LVP +#define USE_LVP // FIXME: won't build when this option is turned off + #define USE_THERMAL_REGULATION #define DEFAULT_THERM_CEIL 50 #define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to @@ -34,19 +35,35 @@ #else #define THERM_DOUBLE_SPEED_LEVEL (RAMP_LENGTH*4/5) // throttle back faster when high #endif -#define USE_SET_LEVEL_GRADUALLY +#ifdef USE_THERMAL_REGULATION +#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments +#endif + +// short blips while ramping #define BLINK_AT_CHANNEL_BOUNDARIES //#define BLINK_AT_RAMP_FLOOR #define BLINK_AT_RAMP_CEILING -//#define BLINK_AT_STEPS +//#define BLINK_AT_STEPS // whenever a discrete ramp mode is passed in smooth mode + +// ramp down via regular button hold if a ramp-up ended <1s ago +// ("hold, release, hold" ramps down instead of up) +#define USE_REVERSING + +// battery readout style (pick one) #define BATTCHECK_VpT +//#define BATTCHECK_8bars // FIXME: breaks build +//#define BATTCHECK_4bars // FIXME: breaks build + +// enable/disable various modes #define USE_LIGHTNING_MODE #define USE_CANDLE_MODE +#define USE_MUGGLE_MODE + #define GOODNIGHT_TIME 60 // minutes (approximately) #define GOODNIGHT_LEVEL 24 // ~11 lm -#define USE_REVERSING + +// dual-switch support (second switch is a tail clicky) //#define START_AT_MEMORIZED_LEVEL -#define USE_MUGGLE_MODE /********* Configure SpaghettiMonster *********/ #define USE_DELAY_ZERO @@ -61,35 +78,29 @@ #else #define MAX_CLICKS 5 #endif -#define USE_IDLE_MODE +#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending #define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency +// full FET strobe can be a bit much... use max regulated level instead, +// if there's a bright enough regulated level +#ifdef MAX_Nx7135 +#define STROBE_BRIGHTNESS MAX_Nx7135 +#else +#define STROBE_BRIGHTNESS MAX_LEVEL +#endif + // specific settings for known driver types -#ifdef FSM_BLF_Q8_DRIVER -#define USE_INDICATOR_LED -#define USE_INDICATOR_LED_WHILE_RAMPING -#define TICK_DURING_STANDBY -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#if defined(FSM_BLF_GT_DRIVER) +#include "cfg-blf-gt.h" + +#elif FSM_BLF_Q8_DRIVER +#include "cfg-blf-q8.h" #elif defined(FSM_EMISAR_D4_DRIVER) -#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +#include "cfg-emisar-d4.h" #elif defined(FSM_FW3A_DRIVER) -#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V - -#elif defined(FSM_BLF_GT_DRIVER) -#define USE_INDICATOR_LED -#define USE_INDICATOR_LED_WHILE_RAMPING -#define TICK_DURING_STANDBY -#undef BLINK_AT_CHANNEL_BOUNDARIES -#undef BLINK_AT_RAMP_CEILING -#undef BLINK_AT_RAMP_FLOOR -//#undef USE_SET_LEVEL_GRADUALLY -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL POWER_80PX -#define RAMP_DISCRETE_FLOOR 1 -#define RAMP_DISCRETE_CEIL POWER_80PX -#define RAMP_DISCRETE_STEPS 7 +#include "cfg-fw3a.h" #endif @@ -126,14 +137,6 @@ #endif #define NUM_STROBES (NUM_STROBES_BASE+ADD_LIGHTNING_STROBE+ADD_CANDLE_MODE) -// full FET strobe can be a bit much... use max regulated level instead, -// if there's a bright enough regulated level -#ifdef MAX_Nx7135 -#define STROBE_BRIGHTNESS MAX_Nx7135 -#else -#define STROBE_BRIGHTNESS MAX_LEVEL -#endif - #include "spaghetti-monster.h" @@ -225,8 +228,7 @@ uint8_t ramp_discrete_step_size; // don't set this #ifdef USE_INDICATOR_LED // bits 2-3 control lockout mode // bits 0-1 control "off" mode -// modes are: 0=off, 1=low, 2=high -// (TODO: 3=blinking) +// modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) //uint8_t indicator_led_mode = (1<<2) + 2; uint8_t indicator_led_mode = (2<<2) + 1; #endif @@ -671,6 +673,9 @@ uint8_t strobe_state(EventPtr event, uint16_t arg) { // (maybe I should just make it nonvolatile?) uint8_t st = strobe_type; #ifdef USE_CANDLE_MODE + // 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) static uint8_t candle_wave1 = 0; @@ -954,6 +959,8 @@ uint8_t lockout_state(EventPtr event, uint16_t arg) { // momentary(ish) moon mode during lockout // not all presses will be counted; // it depends on what is in the master event_sequences table + // FIXME: maybe do this only if arg == 0? + // (so it'll only get turned on once, instead of every frame) uint8_t last = 0; for(uint8_t i=0; pgm_read_byte(event + i) && (i> 5) & 3; #else diff --git a/spaghetti-monster/anduril/cfg-blf-gt.h b/spaghetti-monster/anduril/cfg-blf-gt.h new file mode 100644 index 0000000..e5ce2a1 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-blf-gt.h @@ -0,0 +1,25 @@ +// 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 + +// not relevant for this driver type +//#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V + +// don't blink during ramp, it's irrelevant and annoying on this light +#undef BLINK_AT_CHANNEL_BOUNDARIES +#undef BLINK_AT_RAMP_CEILING +#undef BLINK_AT_RAMP_FLOOR + +//#undef USE_SET_LEVEL_GRADUALLY + +// use 2.0 A as the ceiling, 2.5 A only for turbo +// start both ramps at the bottom; even moon throws a long way on the GT +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL POWER_80PX +#define RAMP_DISCRETE_FLOOR 1 +#define RAMP_DISCRETE_CEIL POWER_80PX +#define RAMP_DISCRETE_STEPS 7 + diff --git a/spaghetti-monster/anduril/cfg-blf-q8.h b/spaghetti-monster/anduril/cfg-blf-q8.h new file mode 100644 index 0000000..379fca2 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-blf-q8.h @@ -0,0 +1,9 @@ +// 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 + +// average drop across diode on this hardware +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h new file mode 100644 index 0000000..4074f01 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -0,0 +1,2 @@ +// average drop across diode on this hardware +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h new file mode 100644 index 0000000..4074f01 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -0,0 +1,2 @@ +// average drop across diode on this hardware +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V -- cgit v1.2.3 From 0870da1dcbb2b446851bfcf507d4535f9eded417 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 24 Jun 2018 19:57:42 -0600 Subject: Refactored driver/hardware definition code to be one file per driver type. --- hwdef-BLF_GT.h | 40 +++++ hwdef-BLF_Q8.h | 16 ++ hwdef-Emisar_D4.h | 36 ++++ hwdef-FET_7135.h | 32 ++++ hwdef-FW3A.h | 35 ++++ hwdef-Ferrero_Rocher.h | 11 ++ hwdef-TK_Saber.h | 33 ++++ hwdef-Tripledown.h | 33 ++++ hwdef-nanjg.h | 16 ++ spaghetti-monster/anduril/cfg-blf-gt.h | 5 +- spaghetti-monster/anduril/cfg-blf-q8.h | 4 +- spaghetti-monster/anduril/cfg-emisar-d4.h | 3 +- spaghetti-monster/anduril/cfg-fw3a.h | 3 +- tk-attiny.h | 282 +++--------------------------- 14 files changed, 280 insertions(+), 269 deletions(-) create mode 100644 hwdef-BLF_GT.h create mode 100644 hwdef-BLF_Q8.h create mode 100644 hwdef-Emisar_D4.h create mode 100644 hwdef-FET_7135.h create mode 100644 hwdef-FW3A.h create mode 100644 hwdef-Ferrero_Rocher.h create mode 100644 hwdef-TK_Saber.h create mode 100644 hwdef-Tripledown.h create mode 100644 hwdef-nanjg.h diff --git a/hwdef-BLF_GT.h b/hwdef-BLF_GT.h new file mode 100644 index 0000000..1a05741 --- /dev/null +++ b/hwdef-BLF_GT.h @@ -0,0 +1,40 @@ +/* BLF GT driver layout + * ---- + * Reset -|1 8|- VCC (unused) + * eswitch -|2 7|- Voltage divider + * AUX LED -|3 6|- Current control (buck level) + * GND -|4 5|- PWM (buck output on/off) + * ---- + */ + +#define PWM_CHANNELS 2 + +#define AUXLED_PIN PB4 // pin 3 + +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt + +#define PWM1_PIN PB0 // pin 5, 1x7135 PWM +#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 +#define PWM2_PIN PB1 // pin 6, FET PWM +#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 + +#define USE_VOLTAGE_DIVIDER // use a voltage divider on pin 7, not VCC +#define VOLTAGE_PIN PB2 // pin 7, voltage ADC +#define VOLTAGE_CHANNEL 0x01 // MUX 01 corresponds with PB2 +// 1.1V reference, left-adjust, ADC1/PB2 +//#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | (1 << ADLAR) | VOLTAGE_CHANNEL) +// 1.1V reference, no left-adjust, ADC1/PB2 +#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) +#define VOLTAGE_ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 +#define ADC_PRSCL 0x06 // clk/64 + +// Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) +#define ADC_44 184 +#define ADC_22 92 + +#define TEMP_CHANNEL 0b00001111 + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + diff --git a/hwdef-BLF_Q8.h b/hwdef-BLF_Q8.h new file mode 100644 index 0000000..f00c392 --- /dev/null +++ b/hwdef-BLF_Q8.h @@ -0,0 +1,16 @@ +/* BLF Q8 driver layout + */ +// Q8 driver is the same as a D4, basically +#include "hwdef-Emisar_D4.h" + +// ... except the Q8 has a lighted button +#ifndef AUXLED_PIN +#define AUXLED_PIN PB4 // pin 3 +#endif + +// average drop across diode on this hardware +#ifdef VOLTAGE_FUDGE_FACTOR +#undef VOLTAGE_FUDGE_FACTOR +#endif +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V + diff --git a/hwdef-Emisar_D4.h b/hwdef-Emisar_D4.h new file mode 100644 index 0000000..105d3b9 --- /dev/null +++ b/hwdef-Emisar_D4.h @@ -0,0 +1,36 @@ +/* Emisar D4 driver layout + * ---- + * Reset -|1 8|- VCC + * eswitch -|2 7|- + * AUX LED -|3 6|- PWM (FET) + * GND -|4 5|- PWM (1x7135) + * ---- + */ + +#define PWM_CHANNELS 2 + +#define AUXLED_PIN PB4 // pin 3 + +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt + +#define PWM1_PIN PB0 // pin 5, 1x7135 PWM +#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 +#define PWM2_PIN PB1 // pin 6, FET PWM +#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 + +// (FIXME: remove? not used?) +#define VOLTAGE_PIN PB2 // pin 7, voltage ADC +#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 +#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 +#define ADC_PRSCL 0x06 // clk/64 + +// average drop across diode on this hardware +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V + +//#define TEMP_DIDR ADC4D +#define TEMP_CHANNEL 0b00001111 + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + diff --git a/hwdef-FET_7135.h b/hwdef-FET_7135.h new file mode 100644 index 0000000..58df7b2 --- /dev/null +++ b/hwdef-FET_7135.h @@ -0,0 +1,32 @@ +/* FET + 7135 driver layout + * ---- + * Reset -|1 8|- VCC + * OTC -|2 7|- Voltage ADC + * Star 3 -|3 6|- PWM (FET) + * GND -|4 5|- PWM (1x7135) + * ---- + */ + +#define STAR2_PIN PB0 // If this pin isn't used for ALT_PWM +#define STAR3_PIN PB4 // pin 3 + +#define CAP_PIN PB3 // pin 2, OTC +#define CAP_CHANNEL 0x03 // MUX 03 corresponds with PB3 (Star 4) +#define CAP_DIDR ADC3D // Digital input disable bit corresponding with PB3 + +#define PWM_PIN PB1 // pin 6, FET PWM +#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1 +#define ALT_PWM_PIN PB0 // pin 5, 1x7135 PWM +#define ALT_PWM_LVL OCR0A // OCR0A is the output compare register for PB0 + +#define VOLTAGE_PIN PB2 // pin 7, voltage ADC +#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 +#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 +#define ADC_PRSCL 0x06 // clk/64 + +//#define TEMP_DIDR ADC4D +#define TEMP_CHANNEL 0b00001111 + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + diff --git a/hwdef-FW3A.h b/hwdef-FW3A.h new file mode 100644 index 0000000..5e253c7 --- /dev/null +++ b/hwdef-FW3A.h @@ -0,0 +1,35 @@ +/* BLF/TLF FW3A driver layout + * ---- + * Reset -|1 8|- VCC + * eswitch -|2 7|- optic nerve + * FET -|3 6|- 7x7135 + * GND -|4 5|- 1x7135 + * ---- + */ + +#define PWM_CHANNELS 3 + +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt + +#define PWM1_PIN PB0 // pin 5, 1x7135 PWM +#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 +#define PWM2_PIN PB1 // pin 6, FET PWM +#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 +#define PWM3_PIN PB4 // pin 3 +#define PWM3_LVL OCR1B + +#define VISION_PIN PB2 // pin 7, optic nerve +#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 +#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 +#define ADC_PRSCL 0x06 // clk/64 + +// average drop across diode on this hardware +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V + +//#define TEMP_DIDR ADC4D +#define TEMP_CHANNEL 0b00001111 + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + diff --git a/hwdef-Ferrero_Rocher.h b/hwdef-Ferrero_Rocher.h new file mode 100644 index 0000000..a46f19d --- /dev/null +++ b/hwdef-Ferrero_Rocher.h @@ -0,0 +1,11 @@ +/* Ferrero Rocher driver layout + * ---- + * Reset -|1 8|- VCC + * E-switch -|2 7|- Voltage ADC + * Red LED -|3 6|- PWM + * GND -|4 5|- Green LED + * ---- + */ +// TODO: fill in this section, update Ferrero_Rocher code to use it. +#define FAST 0x23 // fast PWM channel 1 only +#define PHASE 0x21 // phase-correct PWM channel 1 only diff --git a/hwdef-TK_Saber.h b/hwdef-TK_Saber.h new file mode 100644 index 0000000..e90d5dd --- /dev/null +++ b/hwdef-TK_Saber.h @@ -0,0 +1,33 @@ +/* TK 4-color lightsaber driver layout + * ---- + * Reset -|1 8|- VCC + * PWM 4 (A) -|2 7|- e-switch + * PWM 3 (G) -|3 6|- PWM 2 (B) + * GND -|4 5|- PWM 1 (R) + * ---- + */ + +#define PWM_CHANNELS 4 +#define PWM1_PIN PB0 // pin 5 +#define PWM1_LVL OCR0A +#define PWM2_PIN PB1 // pin 6 +#define PWM2_LVL OCR0B +#define PWM3_PIN PB4 // pin 3 +#define PWM3_LVL OCR1B +#define PWM4_PIN PB3 // pin 2 +#define PWM4_LVL OCR1A + +#define SWITCH_PIN PB2 // pin 7 +#define SWITCH_PCINT PCINT2 // pin 7 pin change interrupt + +#define ADC_PRSCL 0x06 // clk/64 (no need to be super fast) + +// average drop across diode on this hardware +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V + +//#define TEMP_DIDR ADC4D +#define TEMP_CHANNEL 0b00001111 + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + diff --git a/hwdef-Tripledown.h b/hwdef-Tripledown.h new file mode 100644 index 0000000..4676e69 --- /dev/null +++ b/hwdef-Tripledown.h @@ -0,0 +1,33 @@ +/* Tripledown driver layout + * ---- + * Reset -|1 8|- VCC + * OTC -|2 7|- Voltage ADC + * PWM (FET) -|3 6|- PWM (6x7135) + * GND -|4 5|- PWM (1x7135) + * ---- + */ + +#define STAR2_PIN PB0 // If this pin isn't used for ALT_PWM + +#define CAP_PIN PB3 // pin 2, OTC +#define CAP_CHANNEL 0x03 // MUX 03 corresponds with PB3 (Star 4) +#define CAP_DIDR ADC3D // Digital input disable bit corresponding with PB3 + +#define PWM_PIN PB1 // pin 6, 6x7135 PWM +#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1 +#define ALT_PWM_PIN PB0 // pin 5, 1x7135 PWM +#define ALT_PWM_LVL OCR0A // OCR0A is the output compare register for PB0 +#define FET_PWM_PIN PB4 // pin 3 +#define FET_PWM_LVL OCR1B // output compare register for PB4 + +#define VOLTAGE_PIN PB2 // pin 7, voltage ADC +#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 +#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 +#define ADC_PRSCL 0x06 // clk/64 + +//#define TEMP_DIDR ADC4D +#define TEMP_CHANNEL 0b00001111 + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + diff --git a/hwdef-nanjg.h b/hwdef-nanjg.h new file mode 100644 index 0000000..add10d1 --- /dev/null +++ b/hwdef-nanjg.h @@ -0,0 +1,16 @@ +/* NANJG driver layout + */ +#define STAR2_PIN PB0 +#define STAR3_PIN PB4 +#define STAR4_PIN PB3 +#define PWM_PIN PB1 +#define VOLTAGE_PIN PB2 +#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 +#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 +#define ADC_PRSCL 0x06 // clk/64 + +#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1 + +#define FAST 0x23 // fast PWM channel 1 only +#define PHASE 0x21 // phase-correct PWM channel 1 only + diff --git a/spaghetti-monster/anduril/cfg-blf-gt.h b/spaghetti-monster/anduril/cfg-blf-gt.h index e5ce2a1..904668a 100644 --- a/spaghetti-monster/anduril/cfg-blf-gt.h +++ b/spaghetti-monster/anduril/cfg-blf-gt.h @@ -1,3 +1,5 @@ +// BLF GT config options for Anduril + // the button lights up #define USE_INDICATOR_LED // the button is visible while main LEDs are on @@ -5,9 +7,6 @@ // enable blinking indicator LED while off #define TICK_DURING_STANDBY -// not relevant for this driver type -//#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V - // don't blink during ramp, it's irrelevant and annoying on this light #undef BLINK_AT_CHANNEL_BOUNDARIES #undef BLINK_AT_RAMP_CEILING diff --git a/spaghetti-monster/anduril/cfg-blf-q8.h b/spaghetti-monster/anduril/cfg-blf-q8.h index 379fca2..929fb55 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8.h +++ b/spaghetti-monster/anduril/cfg-blf-q8.h @@ -1,3 +1,5 @@ +// BLF Q8 config options for Anduril + // the button lights up #define USE_INDICATOR_LED // the button is visible while main LEDs are on @@ -5,5 +7,3 @@ // enable blinking indicator LED while off #define TICK_DURING_STANDBY -// average drop across diode on this hardware -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h index 4074f01..5421110 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -1,2 +1 @@ -// average drop across diode on this hardware -#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +// Emisar D4 config options for Anduril diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h index 4074f01..420eaeb 100644 --- a/spaghetti-monster/anduril/cfg-fw3a.h +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -1,2 +1 @@ -// average drop across diode on this hardware -#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +// FW3A config options for Anduril diff --git a/tk-attiny.h b/tk-attiny.h index d81468b..b3edb6d 100644 --- a/tk-attiny.h +++ b/tk-attiny.h @@ -61,276 +61,38 @@ #include /******************** I/O pin and register layout ************************/ -#ifdef FET_7135_LAYOUT -#define DRIVER_TYPE_DEFINED -/* - * ---- - * Reset -|1 8|- VCC - * OTC -|2 7|- Voltage ADC - * Star 3 -|3 6|- PWM (FET) - * GND -|4 5|- PWM (1x7135) - * ---- - */ - -#define STAR2_PIN PB0 // If this pin isn't used for ALT_PWM -#define STAR3_PIN PB4 // pin 3 - -#define CAP_PIN PB3 // pin 2, OTC -#define CAP_CHANNEL 0x03 // MUX 03 corresponds with PB3 (Star 4) -#define CAP_DIDR ADC3D // Digital input disable bit corresponding with PB3 - -#define PWM_PIN PB1 // pin 6, FET PWM -#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1 -#define ALT_PWM_PIN PB0 // pin 5, 1x7135 PWM -#define ALT_PWM_LVL OCR0A // OCR0A is the output compare register for PB0 - -#define VOLTAGE_PIN PB2 // pin 7, voltage ADC -#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 -#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 -#define ADC_PRSCL 0x06 // clk/64 - -//#define TEMP_DIDR ADC4D -#define TEMP_CHANNEL 0b00001111 - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#endif // FET_7135_LAYOUT - -#ifdef TRIPLEDOWN_LAYOUT -#define DRIVER_TYPE_DEFINED -/* - * ---- - * Reset -|1 8|- VCC - * OTC -|2 7|- Voltage ADC - * PWM (FET) -|3 6|- PWM (6x7135) - * GND -|4 5|- PWM (1x7135) - * ---- - */ - -#define STAR2_PIN PB0 // If this pin isn't used for ALT_PWM - -#define CAP_PIN PB3 // pin 2, OTC -#define CAP_CHANNEL 0x03 // MUX 03 corresponds with PB3 (Star 4) -#define CAP_DIDR ADC3D // Digital input disable bit corresponding with PB3 - -#define PWM_PIN PB1 // pin 6, 6x7135 PWM -#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1 -#define ALT_PWM_PIN PB0 // pin 5, 1x7135 PWM -#define ALT_PWM_LVL OCR0A // OCR0A is the output compare register for PB0 -#define FET_PWM_PIN PB4 // pin 3 -#define FET_PWM_LVL OCR1B // output compare register for PB4 - -#define VOLTAGE_PIN PB2 // pin 7, voltage ADC -#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 -#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 -#define ADC_PRSCL 0x06 // clk/64 - -//#define TEMP_DIDR ADC4D -#define TEMP_CHANNEL 0b00001111 - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#endif // TRIPLEDOWN_LAYOUT - -#ifdef FERRERO_ROCHER_LAYOUT -#define DRIVER_TYPE_DEFINED -/* - * ---- - * Reset -|1 8|- VCC - * E-switch -|2 7|- Voltage ADC - * Red LED -|3 6|- PWM - * GND -|4 5|- Green LED - * ---- - */ -// TODO: fill in this section, update Ferrero_Rocher code to use it. -#define FAST 0x23 // fast PWM channel 1 only -#define PHASE 0x21 // phase-correct PWM channel 1 only -#endif // FERRERO_ROCHER_LAYOUT - -#ifdef NANJG_LAYOUT -#define DRIVER_TYPE_DEFINED -#define STAR2_PIN PB0 -#define STAR3_PIN PB4 -#define STAR4_PIN PB3 -#define PWM_PIN PB1 -#define VOLTAGE_PIN PB2 -#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 -#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 -#define ADC_PRSCL 0x06 // clk/64 - -#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1 - -#define FAST 0x23 // fast PWM channel 1 only -#define PHASE 0x21 // phase-correct PWM channel 1 only - -#endif // NANJG_LAYOUT - - -// Q8 driver is the same as a D4, basically -#ifdef FSM_BLF_Q8_DRIVER -#define FSM_EMISAR_D4_DRIVER -#endif - - -#ifdef FSM_EMISAR_D4_DRIVER -#define DRIVER_TYPE_DEFINED -/* - * ---- - * Reset -|1 8|- VCC - * eswitch -|2 7|- - * AUX LED -|3 6|- PWM (FET) - * GND -|4 5|- PWM (1x7135) - * ---- - */ - -#define PWM_CHANNELS 2 - -#define AUXLED_PIN PB4 // pin 3 +#if 0 // placeholder -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt +#elif defined(NANJG_LAYOUT) +#include "hwdef-nanjg.h" -#define PWM1_PIN PB0 // pin 5, 1x7135 PWM -#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 -#define PWM2_PIN PB1 // pin 6, FET PWM -#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 +#elif defined(FET_7135_LAYOUT) +#include "hwdef-FET_7135.h" -// (FIXME: remove? not used?) -#define VOLTAGE_PIN PB2 // pin 7, voltage ADC -#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 -#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 -#define ADC_PRSCL 0x06 // clk/64 +#elif defined(TRIPLEDOWN_LAYOUT) +#include "hwdef-Tripledown.h" -//#define TEMP_DIDR ADC4D -#define TEMP_CHANNEL 0b00001111 +#elif defined(FERRERO_ROCHER_LAYOUT) +#include "hwdef-Ferrero_Rocher.h" -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels +#elif defined(FSM_BLF_GT_DRIVER) +#include "hwdef-BLF_GT.h" -#endif // ifdef FSM_EMISAR_D4_DRIVER +#elif defined(FSM_BLF_Q8_DRIVER) +#include "hwdef-BLF_Q8.h" +#elif defined(FSM_EMISAR_D4_DRIVER) +#include "hwdef-Emisar_D4.h" -#ifdef FSM_FW3A_DRIVER -#define DRIVER_TYPE_DEFINED -/* - * ---- - * Reset -|1 8|- VCC - * eswitch -|2 7|- optic nerve - * FET -|3 6|- 7x7135 - * GND -|4 5|- 1x7135 - * ---- - */ - -#define PWM_CHANNELS 3 - -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt - -#define PWM1_PIN PB0 // pin 5, 1x7135 PWM -#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 -#define PWM2_PIN PB1 // pin 6, FET PWM -#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 -#define PWM3_PIN PB4 // pin 3 -#define PWM3_LVL OCR1B - -#define VISION_PIN PB2 // pin 7, optic nerve -#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 -#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 -#define ADC_PRSCL 0x06 // clk/64 - -//#define TEMP_DIDR ADC4D -#define TEMP_CHANNEL 0b00001111 - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#endif // ifdef FSM_FW3A_DRIVER - - -#ifdef FSM_BLF_GT_DRIVER -#define DRIVER_TYPE_DEFINED -/* - * ---- - * Reset -|1 8|- VCC (unused) - * eswitch -|2 7|- Voltage divider - * AUX LED -|3 6|- Current control (buck level) - * GND -|4 5|- PWM (buck output on/off) - * ---- - */ - -#define PWM_CHANNELS 2 - -#define AUXLED_PIN PB4 // pin 3 - -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt - -#define PWM1_PIN PB0 // pin 5, 1x7135 PWM -#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 -#define PWM2_PIN PB1 // pin 6, FET PWM -#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 - -#define USE_VOLTAGE_DIVIDER // use a voltage divider on pin 7, not VCC -#define VOLTAGE_PIN PB2 // pin 7, voltage ADC -#define VOLTAGE_CHANNEL 0x01 // MUX 01 corresponds with PB2 -// 1.1V reference, left-adjust, ADC1/PB2 -//#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | (1 << ADLAR) | VOLTAGE_CHANNEL) -// 1.1V reference, no left-adjust, ADC1/PB2 -#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) -#define VOLTAGE_ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 -#define ADC_PRSCL 0x06 // clk/64 +#elif defined(FSM_FW3A_DRIVER) +#include "hwdef-FW3A.h" -// Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) -#define ADC_44 184 -#define ADC_22 92 +#elif defined(FSM_TKSABER_DRIVER) +#include "hwdef-TK_Saber.h" -#define TEMP_CHANNEL 0b00001111 - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#endif // ifdef FSM_BLF_GT_DRIVER - - -#ifdef FSM_TKSABER_DRIVER -#define DRIVER_TYPE_DEFINED -/* - * ---- - * Reset -|1 8|- VCC - * PWM 4 (A) -|2 7|- e-switch - * PWM 3 (G) -|3 6|- PWM 2 (B) - * GND -|4 5|- PWM 1 (R) - * ---- - */ - -#define PWM_CHANNELS 4 -#define PWM1_PIN PB0 // pin 5 -#define PWM1_LVL OCR0A -#define PWM2_PIN PB1 // pin 6 -#define PWM2_LVL OCR0B -#define PWM3_PIN PB4 // pin 3 -#define PWM3_LVL OCR1B -#define PWM4_PIN PB3 // pin 2 -#define PWM4_LVL OCR1A - -#define SWITCH_PIN PB2 // pin 7 -#define SWITCH_PCINT PCINT2 // pin 7 pin change interrupt - -#define ADC_PRSCL 0x06 // clk/64 (no need to be super fast) - -//#define TEMP_DIDR ADC4D -#define TEMP_CHANNEL 0b00001111 - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#endif // TKSABER_DRIVER - - -#ifndef DRIVER_TYPE_DEFINED +#else #error Hey, you need to define an I/O pin layout. -#endif + +#endif // no more recognized driver types #endif // TK_ATTINY_H -- cgit v1.2.3 From d1e7bf6bfb2198e671b1b4a64566d1345fd812ef Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 24 Jun 2018 20:00:05 -0600 Subject: Added D4S to the build-all script. --- spaghetti-monster/anduril/build-all.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/spaghetti-monster/anduril/build-all.sh b/spaghetti-monster/anduril/build-all.sh index 4100805..9c7a07d 100755 --- a/spaghetti-monster/anduril/build-all.sh +++ b/spaghetti-monster/anduril/build-all.sh @@ -4,6 +4,7 @@ for TARGET in \ BLF_GT \ BLF_Q8 \ EMISAR_D4 \ + EMISAR_D4S \ FW3A \ ; do echo "===== $TARGET =====" -- cgit v1.2.3 From 44884c8b4e3c3beb15fa06e3ec7eb5c2f32ab35a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 24 Jun 2018 20:17:15 -0600 Subject: re-applied D4S-specific config, got lost in the merge --- spaghetti-monster/anduril/anduril.c | 9 ++++++--- spaghetti-monster/anduril/cfg-emisar-d4s.h | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 spaghetti-monster/anduril/cfg-emisar-d4s.h diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index a79220b..c96301c 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -100,6 +100,9 @@ #elif defined(FSM_EMISAR_D4_DRIVER) #include "cfg-emisar-d4.h" +#elif defined(FSM_EMISAR_D4S_DRIVER) +#include "cfg-emisar-d4s.h" + #elif defined(FSM_FW3A_DRIVER) #include "cfg-fw3a.h" @@ -230,11 +233,11 @@ uint8_t ramp_discrete_step_size; // don't set this // bits 2-3 control lockout mode // bits 0-1 control "off" mode // modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) -#ifdef FSM_EMISAR_D4S_DRIVER -uint8_t indicator_led_mode = (3<<2) + 1; -#else +#ifdef USE_INDICATOR_LED_WHILE_RAMPING //uint8_t indicator_led_mode = (1<<2) + 2; uint8_t indicator_led_mode = (2<<2) + 1; +#else +uint8_t indicator_led_mode = (3<<2) + 1; #endif #endif diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s.h b/spaghetti-monster/anduril/cfg-emisar-d4s.h new file mode 100644 index 0000000..676ac83 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-emisar-d4s.h @@ -0,0 +1,20 @@ +// Emisar D4S config options for Anduril + +// the button lights up +#define USE_INDICATOR_LED +// the aux LEDs are behind the main LEDs +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif +// enable blinking indicator LED while off +#define TICK_DURING_STANDBY + +// ceiling is level 120/150 +#define RAMP_SMOOTH_CEIL (MAX_LEVEL*4/5) + +// thermal regulation parameters +#undef MIN_THERM_STEPDOWN // this should be lower, because 3x7135 instead of 1x7135 +#define MIN_THERM_STEPDOWN 60 // lowest value it'll step down to +#undef THERM_DOUBLE_SPEED_LEVEL // this should be lower too, because this light is a hot rod +#define THERM_DOUBLE_SPEED_LEVEL (RAMP_LENGTH*2/3) // throttle back faster when high + -- cgit v1.2.3 From c69cec3512564003a249e5dc3760412834d6dc3e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 26 Jun 2018 19:18:24 -0600 Subject: Copied anduril to rampingiosv3 so I can start removing features. --- spaghetti-monster/anduril/rampingiosv3.c | 1753 ++++++++++++++++++++++++++++++ 1 file changed, 1753 insertions(+) create mode 100644 spaghetti-monster/anduril/rampingiosv3.c diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c new file mode 100644 index 0000000..c96301c --- /dev/null +++ b/spaghetti-monster/anduril/rampingiosv3.c @@ -0,0 +1,1753 @@ +/* + * Anduril: Narsil-inspired UI for SpaghettiMonster. + * (Anduril is Aragorn's sword, the blade Narsil reforged) + * + * 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 . + */ + +/********* User-configurable options *********/ +// Physical driver type (uncomment one of the following or define it at the gcc command line) +//#define FSM_EMISAR_D4_DRIVER +//#define FSM_EMISAR_D4S_DRIVER +//#define FSM_BLF_Q8_DRIVER +//#define FSM_FW3A_DRIVER +//#define FSM_BLF_GT_DRIVER + +#define USE_LVP // FIXME: won't build when this option is turned off + +#define USE_THERMAL_REGULATION +#define DEFAULT_THERM_CEIL 50 +#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#ifdef MAX_Nx7135 +#define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 // throttle back faster when high +#else +#define THERM_DOUBLE_SPEED_LEVEL (RAMP_LENGTH*4/5) // throttle back faster when high +#endif +#ifdef USE_THERMAL_REGULATION +#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments +#endif + +// short blips while ramping +#define BLINK_AT_CHANNEL_BOUNDARIES +//#define BLINK_AT_RAMP_FLOOR +#define BLINK_AT_RAMP_CEILING +//#define BLINK_AT_STEPS // whenever a discrete ramp mode is passed in smooth mode + +// ramp down via regular button hold if a ramp-up ended <1s ago +// ("hold, release, hold" ramps down instead of up) +#define USE_REVERSING + +// battery readout style (pick one) +#define BATTCHECK_VpT +//#define BATTCHECK_8bars // FIXME: breaks build +//#define BATTCHECK_4bars // FIXME: breaks build + +// enable/disable various modes +#define USE_LIGHTNING_MODE +#define USE_CANDLE_MODE +#define USE_MUGGLE_MODE + +#define GOODNIGHT_TIME 60 // minutes (approximately) +#define GOODNIGHT_LEVEL 24 // ~11 lm + +// dual-switch support (second switch is a tail clicky) +//#define START_AT_MEMORIZED_LEVEL + +/********* Configure SpaghettiMonster *********/ +#define USE_DELAY_ZERO +#define USE_RAMPING +#define RAMP_LENGTH 150 +#define MAX_BIKING_LEVEL 120 // should be 127 or less +#define USE_BATTCHECK +#ifdef USE_MUGGLE_MODE +#define MAX_CLICKS 6 +#define MUGGLE_FLOOR 22 +#define MUGGLE_CEILING (MAX_1x7135+20) +#else +#define MAX_CLICKS 5 +#endif +#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending +#define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency + +// full FET strobe can be a bit much... use max regulated level instead, +// if there's a bright enough regulated level +#ifdef MAX_Nx7135 +#define STROBE_BRIGHTNESS MAX_Nx7135 +#else +#define STROBE_BRIGHTNESS MAX_LEVEL +#endif + +// specific settings for known driver types +#if defined(FSM_BLF_GT_DRIVER) +#include "cfg-blf-gt.h" + +#elif FSM_BLF_Q8_DRIVER +#include "cfg-blf-q8.h" + +#elif defined(FSM_EMISAR_D4_DRIVER) +#include "cfg-emisar-d4.h" + +#elif defined(FSM_EMISAR_D4S_DRIVER) +#include "cfg-emisar-d4s.h" + +#elif defined(FSM_FW3A_DRIVER) +#include "cfg-fw3a.h" + +#endif + +// try to auto-detect how many eeprom bytes +// FIXME: detect this better, and assign offsets better, for various configs +#define USE_EEPROM +#ifdef USE_INDICATOR_LED +#define EEPROM_BYTES 15 +#elif defined(USE_THERMAL_REGULATION) +#define EEPROM_BYTES 14 +#else +#define EEPROM_BYTES 12 +#endif +#ifdef START_AT_MEMORIZED_LEVEL +#define USE_EEPROM_WL +#define EEPROM_WL_BYTES 1 +#endif + +// auto-configure other stuff... +#if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) +#define USE_PSEUDO_RAND +#endif +// count the strobe modes (seems like there should be an easier way to do this) +#define NUM_STROBES_BASE 3 +#ifdef USE_LIGHTNING_MODE +#define ADD_LIGHTNING_STROBE 1 +#else +#define ADD_LIGHTNING_STROBE 0 +#endif +#ifdef USE_CANDLE_MODE +#define ADD_CANDLE_MODE 1 +#else +#define ADD_CANDLE_MODE 0 +#endif +#define NUM_STROBES (NUM_STROBES_BASE+ADD_LIGHTNING_STROBE+ADD_CANDLE_MODE) + +#include "spaghetti-monster.h" + + +// FSM states +uint8_t off_state(EventPtr event, uint16_t arg); +// simple numeric entry config menu +uint8_t config_state_base(EventPtr 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); +// party and tactical strobes +uint8_t strobe_state(EventPtr event, uint16_t arg); +#ifdef USE_BATTCHECK +uint8_t battcheck_state(EventPtr 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); +#endif +// 1-hour ramp down from low, then automatic off +uint8_t goodnight_state(EventPtr 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); +// soft lockout +#define MOON_DURING_LOCKOUT_MODE +uint8_t lockout_state(EventPtr event, uint16_t arg); +// momentary / signalling mode +uint8_t momentary_state(EventPtr 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_mode_active = 0; +#endif + +// general helper function for config modes +uint8_t number_entry_state(EventPtr event, uint16_t arg); +// return value from number_entry_state() +volatile uint8_t number_entry_value; + +void blink_confirm(uint8_t num); +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +void indicator_blink(uint8_t arg); +#endif + +// remember stuff even after battery was changed +void load_config(); +void save_config(); +#ifdef START_AT_MEMORIZED_LEVEL +void save_config_wl(); +#endif + +// default ramp options if not overridden earlier per-driver +#ifndef RAMP_SMOOTH_FLOOR + #define RAMP_SMOOTH_FLOOR 1 +#endif +#ifndef RAMP_SMOOTH_CEIL + #if PWM_CHANNELS == 3 + #define RAMP_SMOOTH_CEIL MAX_Nx7135 + #else + #define RAMP_SMOOTH_CEIL MAX_LEVEL - 30 + #endif +#endif +#ifndef RAMP_DISCRETE_FLOOR + #define RAMP_DISCRETE_FLOOR 20 +#endif +#ifndef RAMP_DISCRETE_CEIL + #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#endif +#ifndef RAMP_DISCRETE_STEPS + #define RAMP_DISCRETE_STEPS 7 +#endif + +// brightness control +uint8_t memorized_level = MAX_1x7135; +// smooth vs discrete ramping +volatile uint8_t ramp_style = 0; // 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; +volatile uint8_t ramp_discrete_ceil = RAMP_DISCRETE_CEIL; +volatile uint8_t ramp_discrete_steps = RAMP_DISCRETE_STEPS; +uint8_t ramp_discrete_step_size; // don't set this + +#ifdef USE_INDICATOR_LED +// bits 2-3 control lockout mode +// bits 0-1 control "off" mode +// modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +//uint8_t indicator_led_mode = (1<<2) + 2; +uint8_t indicator_led_mode = (2<<2) + 1; +#else +uint8_t indicator_led_mode = (3<<2) + 1; +#endif +#endif + +// calculate the nearest ramp level which would be valid at the moment +// (is a no-op for smooth ramp, but limits discrete ramp to only the +// correct levels for the user's config) +uint8_t nearest_level(int16_t target); + +#ifdef USE_THERMAL_REGULATION +// brightness before thermal step-down +uint8_t target_level = 0; +#endif + +// strobe timing +volatile uint8_t strobe_delays[] = { 40, 67 }; // party strobe, tactical strobe +// 0 == bike flasher +// 1 == party strobe +// 2 == tactical strobe +// 3 == lightning storm +// 4 == candle mode +volatile uint8_t strobe_type = 4; + +// bike mode config options +volatile uint8_t bike_flasher_brightness = MAX_1x7135; + +#ifdef USE_CANDLE_MODE +uint8_t triangle_wave(uint8_t phase); +#endif + +// beacon timing +volatile uint8_t beacon_seconds = 2; + + +uint8_t off_state(EventPtr event, uint16_t arg) { + // turn emitter off when entering state + if (event == EV_enter_state) { + set_level(0); + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode & 0x03); + #endif + // sleep while off (lower power use) + go_to_standby = 1; + return MISCHIEF_MANAGED; + } + // go back to sleep eventually if we got bumped but didn't leave "off" state + else if (event == EV_tick) { + if (arg > TICKS_PER_SECOND*2) { + go_to_standby = 1; + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode & 0x03); + #endif + } + return MISCHIEF_MANAGED; + } + #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) + // blink the indicator LED, maybe + else if (event == EV_sleep_tick) { + if ((indicator_led_mode & 0b00000011) == 0b00000011) { + indicator_blink(arg); + } + return MISCHIEF_MANAGED; + } + #endif + // hold (initially): go to lowest level, but allow abort for regular click + else if (event == EV_click1_press) { + set_level(nearest_level(1)); + return MISCHIEF_MANAGED; + } + // 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 MISCHIEF_MANAGED; + } + // hold, release quickly: go to lowest level + else if (event == EV_click1_hold_release) { + set_state(steady_state, 1); + return MISCHIEF_MANAGED; + } + // 1 click (before timeout): go to memorized level, but allow abort for double click + else if (event == EV_click1_release) { + set_level(nearest_level(memorized_level)); + return MISCHIEF_MANAGED; + } + // 1 click: regular mode + else if (event == EV_1click) { + set_state(steady_state, memorized_level); + return MISCHIEF_MANAGED; + } + // 2 clicks (initial press): off, to prep for later events + else if (event == EV_click2_press) { + set_level(0); + return MISCHIEF_MANAGED; + } + // click, hold: go to highest level (for ramping down) + else if (event == EV_click2_hold) { + set_state(steady_state, MAX_LEVEL); + return MISCHIEF_MANAGED; + } + // 2 clicks: highest mode + else if (event == EV_2clicks) { + set_state(steady_state, nearest_level(MAX_LEVEL)); + return MISCHIEF_MANAGED; + } + #ifdef USE_BATTCHECK + // 3 clicks: battcheck mode / blinky mode group 1 + else if (event == EV_3clicks) { + set_state(battcheck_state, 0); + return MISCHIEF_MANAGED; + } + #endif + // click, click, long-click: strobe mode + else if (event == EV_click3_hold) { + set_state(strobe_state, 0); + return MISCHIEF_MANAGED; + } + // 4 clicks: soft lockout + else if (event == EV_4clicks) { + blink_confirm(2); + set_state(lockout_state, 0); + return MISCHIEF_MANAGED; + } + // 5 clicks: momentary mode + else if (event == EV_5clicks) { + blink_confirm(1); + set_state(momentary_state, 0); + return MISCHIEF_MANAGED; + } + #ifdef USE_MUGGLE_MODE + // 6 clicks: muggle mode + else if (event == EV_6clicks) { + blink_confirm(1); + set_state(muggle_state, 0); + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +uint8_t steady_state(EventPtr event, uint16_t arg) { + uint8_t mode_min = ramp_smooth_floor; + uint8_t mode_max = ramp_smooth_ceil; + uint8_t ramp_step_size = 1; + #ifdef USE_REVERSING + static int8_t ramp_direction = 1; + #endif + if (ramp_style) { + mode_min = ramp_discrete_floor; + mode_max = ramp_discrete_ceil; + ramp_step_size = ramp_discrete_step_size; + } + + // turn LED on when we first enter the mode + if ((event == EV_enter_state) || (event == EV_reenter_state)) { + // if we just got back from config mode, go back to memorized level + if (event == EV_reenter_state) { + arg = memorized_level; + } + // remember this level, unless it's moon or turbo + if ((arg > mode_min) && (arg < mode_max)) + memorized_level = arg; + // use the requested level even if not memorized + #ifdef USE_THERMAL_REGULATION + target_level = arg; + #endif + set_level(nearest_level(arg)); + #ifdef USE_REVERSING + ramp_direction = 1; + #endif + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: go to/from highest level + else if (event == EV_2clicks) { + if (actual_level < MAX_LEVEL) { + #ifdef USE_THERMAL_REGULATION + target_level = MAX_LEVEL; + #endif + // true turbo, not the mode-specific ceiling + set_level(MAX_LEVEL); + } + else { + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + set_level(memorized_level); + } + return MISCHIEF_MANAGED; + } + // 3 clicks: toggle smooth vs discrete ramping + else if (event == EV_3clicks) { + ramp_style = !ramp_style; + memorized_level = nearest_level(memorized_level); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #ifdef USE_SET_LEVEL_GRADUALLY + //set_level_gradually(lvl); + #endif + #endif + save_config(); + #ifdef START_AT_MEMORIZED_LEVEL + save_config_wl(); + #endif + set_level(0); + delay_4ms(20/4); + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + // 4 clicks: configure this ramp mode + else if (event == EV_4clicks) { + push_state(ramp_config_state, 0); + return MISCHIEF_MANAGED; + } + // hold: change brightness (brighter) + else if (event == EV_click1_hold) { + // ramp slower in discrete mode + if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + return MISCHIEF_MANAGED; + } + #ifdef USE_REVERSING + // make it ramp down instead, if already at max + if ((arg <= 1) && (actual_level >= mode_max)) { + ramp_direction = -1; + } + memorized_level = nearest_level((int16_t)actual_level \ + + (ramp_step_size * ramp_direction)); + #else + memorized_level = nearest_level((int16_t)actual_level + ramp_step_size); + #endif + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + // only blink once for each threshold + if ((memorized_level != actual_level) && ( + 0 // for easier syntax below + #ifdef BLINK_AT_CHANNEL_BOUNDARIES + || (memorized_level == MAX_1x7135) + #if PWM_CHANNELS >= 3 + || (memorized_level == MAX_Nx7135) + #endif + #endif + #ifdef BLINK_AT_RAMP_CEILING + || (memorized_level == mode_max) + #endif + #if defined(USE_REVERSING) && defined(BLINK_AT_RAMP_FLOOR) + || (memorized_level == mode_min) + #endif + )) { + set_level(0); + delay_4ms(8/4); + } + #endif + #if defined(BLINK_AT_STEPS) + uint8_t foo = ramp_style; + ramp_style = 1; + uint8_t nearest = nearest_level((int16_t)actual_level); + ramp_style = foo; + // only blink once for each threshold + if ((memorized_level != actual_level) && + (ramp_style == 0) && + (memorized_level == nearest) + ) + { + set_level(0); + delay_4ms(8/4); + } + #endif + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + #if defined(USE_REVERSING) || defined(START_AT_MEMORIZED_LEVEL) + // reverse ramp direction on hold release + else if (event == EV_click1_hold_release) { + #ifdef USE_REVERSING + ramp_direction = -ramp_direction; + #endif + #ifdef START_AT_MEMORIZED_LEVEL + save_config_wl(); + #endif + return MISCHIEF_MANAGED; + } + #endif + // click, hold: change brightness (dimmer) + else if (event == EV_click2_hold) { + #ifdef USE_REVERSING + ramp_direction = 1; + #endif + // ramp slower in discrete mode + if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + return MISCHIEF_MANAGED; + } + // TODO? make it ramp up instead, if already at min? + memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + // only blink once for each threshold + if ((memorized_level != actual_level) && ( + 0 // for easier syntax below + #ifdef BLINK_AT_CHANNEL_BOUNDARIES + || (memorized_level == MAX_1x7135) + #if PWM_CHANNELS >= 3 + || (memorized_level == MAX_Nx7135) + #endif + #endif + #ifdef BLINK_AT_RAMP_FLOOR + || (memorized_level == mode_min) + #endif + )) { + set_level(0); + delay_4ms(8/4); + } + #endif + #if defined(BLINK_AT_STEPS) + uint8_t foo = ramp_style; + ramp_style = 1; + uint8_t nearest = nearest_level((int16_t)actual_level); + ramp_style = foo; + // only blink once for each threshold + if ((memorized_level != actual_level) && + (ramp_style == 0) && + (memorized_level == nearest) + ) + { + set_level(0); + delay_4ms(8/4); + } + #endif + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + #ifdef START_AT_MEMORIZED_LEVEL + // click, release, hold, release: save new ramp level (if necessary) + else if (event == EV_click2_hold_release) { + save_config_wl(); + return MISCHIEF_MANAGED; + } + #endif + #if defined(USE_SET_LEVEL_GRADUALLY) || defined(USE_REVERSING) + else if (event == EV_tick) { + #ifdef USE_REVERSING + // un-reverse after 1 second + if (arg == TICKS_PER_SECOND) ramp_direction = 1; + #endif + #ifdef USE_SET_LEVEL_GRADUALLY + // make thermal adjustment speed scale with magnitude + if (arg & 1) return MISCHIEF_MANAGED; // adjust slower + // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; + // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 132, 71, 38, 20, 10, 5, 3}; + // [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)] + uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2}; + uint8_t diff; + static uint8_t ticks_since_adjust = 0; + ticks_since_adjust ++; + if (target_level > actual_level) diff = target_level - actual_level; + else { + diff = actual_level - target_level; + // if we're on a really high mode, drop faster + if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { + diff <<= 1; + } + } + uint8_t magnitude = 0; + while (diff) { + magnitude ++; + diff >>= 1; + } + uint8_t ticks_per_adjust = intervals[magnitude]; + if (ticks_since_adjust > ticks_per_adjust) + { + gradual_tick(); + ticks_since_adjust = 0; + } + //if (!(arg % ticks_per_adjust)) gradual_tick(); + #endif + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_THERMAL_REGULATION + // 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); + #endif + if (actual_level > MIN_THERM_STEPDOWN) { + int16_t stepdown = actual_level - arg; + if (stepdown < MIN_THERM_STEPDOWN) stepdown = MIN_THERM_STEPDOWN; + else if (stepdown > MAX_LEVEL) stepdown = MAX_LEVEL; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepdown); + #else + set_level(stepdown); + #endif + } + return MISCHIEF_MANAGED; + } + // underheating: increase slowly if we're lower than the target + // (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); + #endif + if (actual_level < target_level) { + //int16_t stepup = actual_level + (arg>>1); + int16_t stepup = actual_level + arg; + if (stepup > target_level) stepup = target_level; + else if (stepup < MIN_THERM_STEPDOWN) stepup = MIN_THERM_STEPDOWN; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepup); + #else + set_level(stepup); + #endif + } + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +uint8_t strobe_state(EventPtr event, uint16_t arg) { + // 'st' reduces ROM size by avoiding access to a volatile var + // (maybe I should just make it nonvolatile?) + uint8_t st = strobe_type; + #ifdef USE_CANDLE_MODE + // 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) + 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; + static uint8_t candle_mode_brightness = 24; + static uint8_t candle_mode_timer = 0; + #define TICKS_PER_CANDLE_MINUTE 4096 // about 65 seconds + #define MINUTES_PER_CANDLE_HALFHOUR 27 // ish + #endif + + if (event == EV_enter_state) { + #ifdef USE_CANDLE_MODE + candle_mode_timer = 0; // in case any time was left over from earlier + #endif + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: rotate through strobe/flasher modes + else if (event == EV_2clicks) { + strobe_type = (st + 1) % NUM_STROBES; + #ifdef USE_CANDLE_MODE + candle_mode_timer = 0; // in case any time was left over from earlier + #endif + interrupt_nice_delays(); + save_config(); + return MISCHIEF_MANAGED; + } + // hold: change speed (go faster) + // or change brightness (brighter) + else if (event == EV_click1_hold) { + // biking mode brighter + if (st == 0) { + if (bike_flasher_brightness < MAX_BIKING_LEVEL) + bike_flasher_brightness ++; + set_level(bike_flasher_brightness); + } + // strobe faster + else if (st < 3) { + if ((arg & 1) == 0) { + if (strobe_delays[st-1] > 8) strobe_delays[st-1] --; + } + } + // lightning has no adjustments + // else if (st == 3) {} + #ifdef USE_CANDLE_MODE + // candle mode brighter + else if (st == 4) { + if (candle_mode_brightness < MAX_CANDLE_LEVEL) + candle_mode_brightness ++; + } + #endif + return MISCHIEF_MANAGED; + } + // click, hold: change speed (go slower) + // or change brightness (dimmer) + else if (event == EV_click2_hold) { + // biking mode dimmer + if (st == 0) { + if (bike_flasher_brightness > 2) + bike_flasher_brightness --; + set_level(bike_flasher_brightness); + } + // strobe slower + else if (st < 3) { + if ((arg & 1) == 0) { + if (strobe_delays[st-1] < 255) strobe_delays[st-1] ++; + } + } + // lightning has no adjustments + // else if (st == 3) {} + #ifdef USE_CANDLE_MODE + // candle mode dimmer + else if (st == 4) { + if (candle_mode_brightness > 1) + candle_mode_brightness --; + } + #endif + return MISCHIEF_MANAGED; + } + // release hold: save new strobe settings + else if ((event == EV_click1_hold_release) + || (event == EV_click2_hold_release)) { + save_config(); + return MISCHIEF_MANAGED; + } + #if defined(USE_CANDLE_MODE) + // 3 clicks: add 30m to candle timer + else if (event == EV_3clicks) { + // candle mode only + if (st == 4) { + if (candle_mode_timer < (255 - MINUTES_PER_CANDLE_HALFHOUR)) { + // add 30m to the timer + candle_mode_timer += MINUTES_PER_CANDLE_HALFHOUR; + // blink to confirm + set_level(actual_level + 32); + delay_4ms(2); + } + } + return MISCHIEF_MANAGED; + } + #endif + #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) + // clock tick: bump the random seed + else if (event == EV_tick) { + #ifdef USE_LIGHTNING_MODE + pseudo_rand_seed += arg; + #endif + #ifdef USE_CANDLE_MODE + if (st == 4) { + // self-timer dims the light during the final minute + uint8_t subtract = 0; + if (candle_mode_timer == 1) { + subtract = ((candle_mode_brightness+20) + * ((arg & (TICKS_PER_CANDLE_MINUTE-1)) >> 4)) + >> 8; + } + // we passed a minute mark, decrease timer if it's running + if ((arg & (TICKS_PER_CANDLE_MINUTE-1)) == (TICKS_PER_CANDLE_MINUTE - 1)) { + if (candle_mode_timer > 0) { + candle_mode_timer --; + //set_level(0); delay_4ms(2); + // if the timer ran out, shut off + if (! candle_mode_timer) { + set_state(off_state, 0); + } + } + } + // 3-oscillator synth for a relatively organic pattern + uint8_t add; + add = ((triangle_wave(candle_wave1) * 8) >> 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; + if (brightness < 0) { brightness = 0; } + set_level(brightness); + + // wave1: slow random LFO + if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; + // wave2: medium-speed erratic LFO + candle_wave2 += candle_wave2_speed; + // wave3: erratic fast wave + candle_wave3 += pseudo_rand() % 37; + // S&H on wave2 frequency to make it more erratic + if ((pseudo_rand() & 0b00111111) == 0) + candle_wave2_speed = pseudo_rand() % 13; + // downward sawtooth on wave2 depth to simulate stabilizing + if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) + candle_wave2_depth --; + // random sawtooth retrigger + if ((pseudo_rand()) == 0) { + candle_wave2_depth = 7; + //candle_wave3_depth = 5; + candle_wave2 = 0; + } + // downward sawtooth on wave3 depth to simulate stabilizing + if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) + candle_wave3_depth --; + if ((pseudo_rand() & 0b01111111) == 0) + candle_wave3_depth = 5; + } + #endif + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +#ifdef USE_BATTCHECK +uint8_t battcheck_state(EventPtr event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: goodnight mode + else if (event == EV_2clicks) { + set_state(goodnight_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} +#endif + +#ifdef USE_THERMAL_REGULATION +uint8_t tempcheck_state(EventPtr event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: battcheck mode + else if (event == EV_2clicks) { + set_state(battcheck_state, 0); + return MISCHIEF_MANAGED; + } + // 4 clicks: thermal config mode + else if (event == EV_4clicks) { + push_state(thermal_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} +#endif + + +uint8_t beacon_state(EventPtr event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: tempcheck mode + else if (event == EV_2clicks) { + #ifdef USE_THERMAL_REGULATION + set_state(tempcheck_state, 0); + #else + set_state(battcheck_state, 0); + #endif + return MISCHIEF_MANAGED; + } + // 4 clicks: beacon config mode + else if (event == EV_4clicks) { + push_state(beacon_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +#define GOODNIGHT_TICKS_PER_STEPDOWN (GOODNIGHT_TIME*TICKS_PER_SECOND*60L/GOODNIGHT_LEVEL) +uint8_t goodnight_state(EventPtr event, uint16_t arg) { + static uint16_t ticks_since_stepdown = 0; + // blink on start + if (event == EV_enter_state) { + ticks_since_stepdown = 0; + blink_confirm(2); + set_level(GOODNIGHT_LEVEL); + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: beacon mode + else if (event == EV_2clicks) { + set_state(beacon_state, 0); + return MISCHIEF_MANAGED; + } + // tick: step down (maybe) or off (maybe) + else if (event == EV_tick) { + if (++ticks_since_stepdown > GOODNIGHT_TICKS_PER_STEPDOWN) { + ticks_since_stepdown = 0; + set_level(actual_level-1); + if (! actual_level) { + #if 0 // test blink, to help measure timing + set_level(MAX_LEVEL>>2); + delay_4ms(8/2); + set_level(0); + #endif + set_state(off_state, 0); + } + } + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +uint8_t lockout_state(EventPtr 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 + // FIXME: maybe do this only if arg == 0? + // (so it'll only get turned on once, instead of every frame) + uint8_t last = 0; + for(uint8_t i=0; pgm_read_byte(event + i) && (i> 2); + } else + #endif + if (event == EV_tick) { + if (arg > TICKS_PER_SECOND*2) { + go_to_standby = 1; + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode >> 2); + #endif + } + return MISCHIEF_MANAGED; + } + #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) + else if (event == EV_sleep_tick) { + if ((indicator_led_mode & 0b00001100) == 0b00001100) { + indicator_blink(arg); + } + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_INDICATOR_LED + // 3 clicks: rotate through indicator LED modes (lockout mode) + else if (event == EV_3clicks) { + uint8_t mode = indicator_led_mode >> 2; + #ifdef TICK_DURING_STANDBY + mode = (mode + 1) & 3; + #else + mode = (mode + 1) % 3; + #endif + indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); + indicator_led(mode); + save_config(); + return MISCHIEF_MANAGED; + } + // click, click, hold: rotate through indicator LED modes (off mode) + else if (event == EV_click3_hold) { + #ifndef USE_INDICATOR_LED_WHILE_RAMPING + // if main LED obscures aux LEDs, turn it off + // FIXME: might not work, since it was turned on just a few clock + // cycles ago at beginning of this function + set_level(0); + #endif + #ifdef TICK_DURING_STANDBY + uint8_t mode = (arg >> 5) & 3; + #else + uint8_t mode = (arg >> 5) % 3; + #endif + indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; + #ifdef TICK_DURING_STANDBY + if (mode == 3) + indicator_led(mode & (arg&3)); + else + indicator_led(mode); + #else + indicator_led(mode); + #endif + //save_config(); + return MISCHIEF_MANAGED; + } + // click, click, hold, release: save indicator LED mode (off mode) + else if (event == EV_click3_hold_release) { + save_config(); + return MISCHIEF_MANAGED; + } + #endif + // 4 clicks: exit + else if (event == EV_4clicks) { + blink_confirm(1); + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} + + +uint8_t momentary_state(EventPtr event, uint16_t arg) { + // TODO: momentary strobe here? (for light painting) + if (event == EV_click1_press) { + set_level(memorized_level); + empty_event_sequence(); // don't attempt to parse multiple clicks + return MISCHIEF_MANAGED; + } + + else if (event == EV_release) { + set_level(0); + empty_event_sequence(); // don't attempt to parse multiple clicks + //go_to_standby = 1; // sleep while light is off + // TODO: lighted button should use lockout config? + return MISCHIEF_MANAGED; + } + + // Sleep, dammit! (but wait a few seconds first) + // (because standby mode uses such little power that it can interfere + // 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 + } + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} + + +#ifdef USE_MUGGLE_MODE +uint8_t muggle_state(EventPtr event, uint16_t arg) { + static int8_t ramp_direction; + static int8_t muggle_off_mode; + + // turn LED off when we first enter the mode + if (event == EV_enter_state) { + ramp_direction = 1; + + #ifdef START_AT_MEMORIZED_LEVEL + memorized_level = arg; + muggle_off_mode = 0; + set_level(memorized_level); + + if (! muggle_mode_active) { // don't write eeprom at every boot + muggle_mode_active = 1; + save_config(); + } + #else + muggle_mode_active = 1; + save_config(); + + muggle_off_mode = 1; + //memorized_level = MAX_1x7135; + memorized_level = (MUGGLE_FLOOR + MUGGLE_CEILING) / 2; + #endif + return MISCHIEF_MANAGED; + } + // initial press: moon hint + else if (event == EV_click1_press) { + if (muggle_off_mode) + set_level(MUGGLE_FLOOR); + } + // initial release: direct to memorized level + else if (event == EV_click1_release) { + if (muggle_off_mode) + set_level(memorized_level); + } + // if the user keeps pressing, turn off + else if (event == EV_click2_press) { + muggle_off_mode = 1; + set_level(0); + } + // 1 click: on/off + else if (event == EV_1click) { + muggle_off_mode ^= 1; + if (muggle_off_mode) { + set_level(0); + } + /* + else { + set_level(memorized_level); + } + */ + return MISCHIEF_MANAGED; + } + // hold: change brightness + else if (event == EV_click1_hold) { + // ramp at half speed + if (arg & 1) return MISCHIEF_MANAGED; + + // if off, start at bottom + if (muggle_off_mode) { + muggle_off_mode = 0; + ramp_direction = 1; + set_level(MUGGLE_FLOOR); + } + else { + uint8_t m; + m = actual_level; + // ramp down if already at ceiling + if ((arg <= 1) && (m >= MUGGLE_CEILING)) ramp_direction = -1; + // ramp + m += ramp_direction; + if (m < MUGGLE_FLOOR) + m = MUGGLE_FLOOR; + if (m > MUGGLE_CEILING) + m = MUGGLE_CEILING; + memorized_level = m; + set_level(m); + } + return MISCHIEF_MANAGED; + } + // reverse ramp direction on hold release + else if (event == EV_click1_hold_release) { + ramp_direction = -ramp_direction; + #ifdef START_AT_MEMORIZED_LEVEL + save_config_wl(); // momentary use should retain brightness level + #endif + return MISCHIEF_MANAGED; + } + /* + // click, hold: change brightness (dimmer) + else if (event == EV_click2_hold) { + ramp_direction = 1; + if (memorized_level > MUGGLE_FLOOR) + memorized_level = actual_level - 1; + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + */ + // 6 clicks: exit muggle mode + else if (event == EV_6clicks) { + blink_confirm(1); + muggle_mode_active = 0; + save_config(); + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // tick: housekeeping + else if (event == EV_tick) { + // un-reverse after 1 second + if (arg == TICKS_PER_SECOND) ramp_direction = 1; + + // turn off, but don't go to the main "off" state + if (muggle_off_mode) { + if (arg > TICKS_PER_SECOND*1) { // sleep after 1 second + go_to_standby = 1; // sleep while light is off + } + } + return MISCHIEF_MANAGED; + } + // low voltage is handled specially in muggle mode + else if(event == EV_voltage_low) { + uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); + if (lvl >= MUGGLE_FLOOR) { + set_level(lvl); + } else { + muggle_off_mode = 1; + } + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} +#endif + + +// 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 num_config_steps, + void (*savefunc)()) { + static uint8_t config_step; + if (event == EV_enter_state) { + config_step = 0; + set_level(0); + return MISCHIEF_MANAGED; + } + // advance forward through config steps + else if (event == EV_tick) { + if (config_step < num_config_steps) { + push_state(number_entry_state, config_step + 1); + } + else { + // TODO: blink out some sort of success pattern + savefunc(); + //set_state(retstate, retval); + pop_state(); + } + return MISCHIEF_MANAGED; + } + // an option was set (return from number_entry_state) + else if (event == EV_reenter_state) { + config_state_values[config_step] = number_entry_value; + config_step ++; + return MISCHIEF_MANAGED; + } + //return EVENT_NOT_HANDLED; + // eat all other events; don't pass any through to parent + return EVENT_HANDLED; +} + +void ramp_config_save() { + // parse values + uint8_t val; + if (ramp_style) { // discrete / stepped ramp + + val = config_state_values[0]; + if (val) { ramp_discrete_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_discrete_ceil = MAX_LEVEL + 1 - val; } + + val = config_state_values[2]; + if (val) ramp_discrete_steps = val; + + } else { // smooth ramp + + val = config_state_values[0]; + if (val) { ramp_smooth_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_smooth_ceil = MAX_LEVEL + 1 - val; } + + } +} + +uint8_t ramp_config_state(EventPtr event, uint16_t arg) { + uint8_t num_config_steps; + num_config_steps = 2 + ramp_style; + return config_state_base(event, arg, + num_config_steps, ramp_config_save); +} + + +#ifdef USE_THERMAL_REGULATION +void thermal_config_save() { + // parse values + uint8_t val; + + // calibrate room temperature + val = config_state_values[0]; + if (val) { + int8_t rawtemp = (temperature >> 1) - therm_cal_offset; + therm_cal_offset = val - rawtemp; + } + + val = config_state_values[1]; + if (val) { + // set maximum heat limit + therm_ceil = 30 + val; + } + if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; +} + +uint8_t thermal_config_state(EventPtr event, uint16_t arg) { + return config_state_base(event, arg, + 2, thermal_config_save); +} +#endif + + +void beacon_config_save() { + // parse values + uint8_t val = config_state_values[0]; + if (val) { + beacon_seconds = val; + } +} + +uint8_t beacon_config_state(EventPtr event, uint16_t arg) { + return config_state_base(event, arg, + 1, beacon_config_save); +} + + +uint8_t number_entry_state(EventPtr event, uint16_t arg) { + static uint8_t value; + static uint8_t blinks_left; + static uint8_t entry_step; + static uint16_t wait_ticks; + if (event == EV_enter_state) { + value = 0; + blinks_left = arg; + entry_step = 0; + wait_ticks = 0; + return MISCHIEF_MANAGED; + } + // advance through the process: + // 0: wait a moment + // 1: blink out the 'arg' value + // 2: wait a moment + // 3: "buzz" while counting clicks + // 4: save and exit + else if (event == EV_tick) { + // wait a moment + if ((entry_step == 0) || (entry_step == 2)) { + if (wait_ticks < TICKS_PER_SECOND/2) + wait_ticks ++; + else { + entry_step ++; + wait_ticks = 0; + } + } + // blink out the option number + else if (entry_step == 1) { + if (blinks_left) { + if ((wait_ticks & 31) == 10) { + set_level(RAMP_SIZE/4); + } + else if ((wait_ticks & 31) == 20) { + set_level(0); + } + else if ((wait_ticks & 31) == 31) { + blinks_left --; + } + wait_ticks ++; + } + else { + entry_step ++; + wait_ticks = 0; + } + } + else if (entry_step == 3) { // buzz while waiting for a number to be entered + wait_ticks ++; + // buzz for N seconds after last event + if ((wait_ticks & 3) == 0) { + set_level(RAMP_SIZE/6); + } + else if ((wait_ticks & 3) == 2) { + set_level(RAMP_SIZE/8); + } + // time out after 3 seconds + if (wait_ticks > TICKS_PER_SECOND*3) { + //number_entry_value = value; + set_level(0); + entry_step ++; + } + } + else if (entry_step == 4) { + number_entry_value = value; + pop_state(); + } + return MISCHIEF_MANAGED; + } + // count clicks + else if (event == EV_click1_release) { + empty_event_sequence(); + if (entry_step == 3) { // only count during the "buzz" + value ++; + wait_ticks = 0; + // flash briefly + set_level(RAMP_SIZE/2); + delay_4ms(8/2); + set_level(0); + } + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +// find the ramp level closest to the target, +// using only the levels which are allowed in the current state +uint8_t nearest_level(int16_t target) { + // bounds check + // using int16_t here saves us a bunch of logic elsewhere, + // by allowing us to correct for numbers < 0 or > 255 in one central place + uint8_t mode_min = ramp_smooth_floor; + uint8_t mode_max = ramp_smooth_ceil; + if (ramp_style) { + mode_min = ramp_discrete_floor; + mode_max = ramp_discrete_ceil; + } + if (target < mode_min) return mode_min; + if (target > mode_max) return mode_max; + // the rest isn't relevant for smooth ramping + if (! ramp_style) return target; + + uint8_t ramp_range = ramp_discrete_ceil - ramp_discrete_floor; + ramp_discrete_step_size = ramp_range / (ramp_discrete_steps-1); + uint8_t this_level = ramp_discrete_floor; + + for(uint8_t i=0; i>1)) + return this_level; + } + return this_level; +} + + +void blink_confirm(uint8_t num) { + for (; num>0; num--) { + set_level(MAX_LEVEL/4); + delay_4ms(10/4); + set_level(0); + delay_4ms(100/4); + } +} + + +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +// beacon-like mode for the indicator LED +void indicator_blink(uint8_t arg) { + if (! (arg & 7)) { + indicator_led(2); + } + else { + indicator_led(0); + } +} +#endif + + +#ifdef USE_CANDLE_MODE +uint8_t triangle_wave(uint8_t phase) { + uint8_t result = phase << 1; + if (phase > 127) result = 255 - result; + return result; +} +#endif + + +void load_config() { + if (load_eeprom()) { + ramp_style = eeprom[0]; + ramp_smooth_floor = eeprom[1]; + ramp_smooth_ceil = eeprom[2]; + ramp_discrete_floor = eeprom[3]; + ramp_discrete_ceil = eeprom[4]; + ramp_discrete_steps = eeprom[5]; + strobe_type = eeprom[6]; // TODO: move this to eeprom_wl? + strobe_delays[0] = eeprom[7]; + strobe_delays[1] = eeprom[8]; + bike_flasher_brightness = eeprom[9]; + beacon_seconds = eeprom[10]; + #ifdef USE_MUGGLE_MODE + muggle_mode_active = eeprom[11]; + #endif + #ifdef USE_THERMAL_REGULATION + therm_ceil = eeprom[12]; + therm_cal_offset = eeprom[13]; + #endif + #ifdef USE_INDICATOR_LED + indicator_led_mode = eeprom[14]; + #endif + } + #ifdef START_AT_MEMORIZED_LEVEL + if (load_eeprom_wl()) { + memorized_level = eeprom_wl[0]; + } + #endif +} + +void save_config() { + eeprom[0] = ramp_style; + eeprom[1] = ramp_smooth_floor; + eeprom[2] = ramp_smooth_ceil; + eeprom[3] = ramp_discrete_floor; + eeprom[4] = ramp_discrete_ceil; + eeprom[5] = ramp_discrete_steps; + eeprom[6] = strobe_type; // TODO: move this to eeprom_wl? + eeprom[7] = strobe_delays[0]; + eeprom[8] = strobe_delays[1]; + eeprom[9] = bike_flasher_brightness; + eeprom[10] = beacon_seconds; + #ifdef USE_MUGGLE_MODE + eeprom[11] = muggle_mode_active; + #endif + #ifdef USE_THERMAL_REGULATION + eeprom[12] = therm_ceil; + eeprom[13] = therm_cal_offset; + #endif + #ifdef USE_INDICATOR_LED + eeprom[14] = indicator_led_mode; + #endif + + save_eeprom(); +} + +#ifdef START_AT_MEMORIZED_LEVEL +void save_config_wl() { + eeprom_wl[0] = memorized_level; + save_eeprom_wl(); +} +#endif + +void low_voltage() { + StatePtr state = current_state; + + // "step down" from strobe to something low + if (state == strobe_state) { + set_state(steady_state, RAMP_SIZE/6); + } + // in normal or muggle mode, step down or turn off + //else if ((state == steady_state) || (state == muggle_state)) { + else if (state == steady_state) { + if (actual_level > 1) { + uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); + set_level(lvl); + #ifdef USE_THERMAL_REGULATION + target_level = lvl; + #ifdef USE_SET_LEVEL_GRADUALLY + // not needed? + //set_level_gradually(lvl); + #endif + #endif + } + else { + set_state(off_state, 0); + } + } + // all other modes, just turn off when voltage is low + else { + set_state(off_state, 0); + } +} + + +void setup() { + #ifdef START_AT_MEMORIZED_LEVEL + // dual switch: e-switch + power clicky + // power clicky acts as a momentary mode + load_config(); + + #ifdef USE_MUGGLE_MODE + if (muggle_mode_active) + push_state(muggle_state, memorized_level); + else + #endif + if (button_is_pressed()) + // hold button to go to moon + push_state(steady_state, 1); + else + // otherwise use memory + push_state(steady_state, memorized_level); + + #else // if not START_AT_MEMORIZED_LEVEL + + // blink at power-on to let user know power is connected + set_level(RAMP_SIZE/8); + delay_4ms(3); + set_level(0); + + load_config(); + + #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 + +} + + +void loop() { + + StatePtr state = current_state; + + #ifdef USE_DYNAMIC_UNDERCLOCKING + auto_clock_speed(); + #endif + if (0) {} + + #ifdef USE_IDLE_MODE + else if ( (state == steady_state) + || (state == off_state) + || (state == lockout_state) + || (state == goodnight_state) ) { + // doze until next clock tick + idle_mode(); + } + #endif + + if (state == strobe_state) { + uint8_t st = strobe_type; + // bike flasher + if (st == 0) { + uint8_t burst = bike_flasher_brightness << 1; + if (burst > MAX_LEVEL) burst = MAX_LEVEL; + for(uint8_t i=0; i<4; i++) { + set_level(burst); + if (! nice_delay_ms(5)) return; + set_level(bike_flasher_brightness); + if (! nice_delay_ms(65)) return; + } + nice_delay_ms(720); // no return check necessary on final delay + } + // party / tactical strobe + else if (st < 3) { + uint8_t del = strobe_delays[st-1]; + // TODO: make tac strobe brightness configurable? + set_level(STROBE_BRIGHTNESS); + CLKPR = 1<> 1); + } + set_level(0); + nice_delay_ms(del); // no return check necessary on final delay + } + #ifdef USE_LIGHTNING_MODE + // lightning storm + else if (st == 3) { + int16_t brightness; + uint16_t rand_time; + + // turn the emitter on at a random level, + // for a random amount of time between 1ms and 32ms + //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 += pseudo_rand() % brightness; // 2 to 159 now (w/ low bias) + if (brightness > MAX_LEVEL) brightness = MAX_LEVEL; + set_level(brightness); + if (! nice_delay_ms(rand_time)) return; + + // decrease the brightness somewhat more gradually, like lightning + uint8_t stepdown = brightness >> 3; + if (stepdown < 1) stepdown = 1; + while(brightness > 1) { + if (! nice_delay_ms(rand_time)) return; + brightness -= stepdown; + if (brightness < 0) brightness = 0; + set_level(brightness); + /* + if ((brightness < MAX_LEVEL/2) && (! (pseudo_rand() & 15))) { + brightness <<= 1; + set_level(brightness); + } + */ + if (! (pseudo_rand() & 3)) { + if (! nice_delay_ms(rand_time)) return; + set_level(brightness>>1); + } + } + + // turn the emitter off, + // for a random amount of time between 1ms and 8192ms + // (with a low bias) + rand_time = 1 << (pseudo_rand() % 13); + rand_time += pseudo_rand() % rand_time; + set_level(0); + nice_delay_ms(rand_time); // no return check necessary on final delay + + } + #endif + } + + #ifdef USE_BATTCHECK + else if (state == battcheck_state) { + battcheck(); + } + #endif + #ifdef USE_THERMAL_REGULATION + // TODO: blink out therm_ceil during thermal_config_state + else if (state == tempcheck_state) { + blink_num(temperature>>1); + nice_delay_ms(1000); + } + #endif + + else if (state == beacon_state) { + set_level(memorized_level); + if (! nice_delay_ms(500)) return; + set_level(0); + nice_delay_ms(((beacon_seconds) * 1000) - 500); + } +} -- cgit v1.2.3 From 7b0acb53733723721afd6ad0bd89f382d142a131 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 26 Jun 2018 19:18:57 -0600 Subject: Started removing features to match Emisar UI. --- spaghetti-monster/anduril/rampingiosv3.c | 43 ++++++++++++++------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c index c96301c..ac49444 100644 --- a/spaghetti-monster/anduril/rampingiosv3.c +++ b/spaghetti-monster/anduril/rampingiosv3.c @@ -1,8 +1,7 @@ /* - * Anduril: Narsil-inspired UI for SpaghettiMonster. - * (Anduril is Aragorn's sword, the blade Narsil reforged) + * RampingIOS V3: FSM-based version of RampingIOS V2 UI, with upgrades. * - * Copyright (C) 2017 Selene ToyKeeper + * Copyright (C) 2018 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 @@ -21,7 +20,7 @@ /********* User-configurable options *********/ // Physical driver type (uncomment one of the following or define it at the gcc command line) //#define FSM_EMISAR_D4_DRIVER -//#define FSM_EMISAR_D4S_DRIVER +#define FSM_EMISAR_D4S_DRIVER //#define FSM_BLF_Q8_DRIVER //#define FSM_FW3A_DRIVER //#define FSM_BLF_GT_DRIVER @@ -56,12 +55,15 @@ //#define BATTCHECK_4bars // FIXME: breaks build // enable/disable various modes -#define USE_LIGHTNING_MODE -#define USE_CANDLE_MODE -#define USE_MUGGLE_MODE +//#define USE_LIGHTNING_MODE +//#define USE_CANDLE_MODE +//#define USE_GOODNIGHT_MODE +//#define USE_MUGGLE_MODE +#ifdef USE_GOODNIGHT_MODE #define GOODNIGHT_TIME 60 // minutes (approximately) #define GOODNIGHT_LEVEL 24 // ~11 lm +#endif // dual-switch support (second switch is a tail clicky) //#define START_AT_MEMORIZED_LEVEL @@ -164,8 +166,10 @@ uint8_t battcheck_state(EventPtr event, uint16_t arg); uint8_t tempcheck_state(EventPtr event, uint16_t arg); uint8_t thermal_config_state(EventPtr event, uint16_t arg); #endif +#ifdef USE_GOODNIGHT_MODE // 1-hour ramp down from low, then automatic off uint8_t goodnight_state(EventPtr event, uint16_t arg); +#endif // 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); @@ -867,9 +871,9 @@ uint8_t battcheck_state(EventPtr event, uint16_t arg) { set_state(off_state, 0); return MISCHIEF_MANAGED; } - // 2 clicks: goodnight mode + // 2 clicks: tempcheck mode else if (event == EV_2clicks) { - set_state(goodnight_state, 0); + set_state(tempcheck_state, 0); return MISCHIEF_MANAGED; } return EVENT_NOT_HANDLED; @@ -883,11 +887,6 @@ uint8_t tempcheck_state(EventPtr event, uint16_t arg) { set_state(off_state, 0); return MISCHIEF_MANAGED; } - // 2 clicks: battcheck mode - else if (event == EV_2clicks) { - set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; - } // 4 clicks: thermal config mode else if (event == EV_4clicks) { push_state(thermal_config_state, 0); @@ -904,15 +903,6 @@ uint8_t beacon_state(EventPtr event, uint16_t arg) { set_state(off_state, 0); return MISCHIEF_MANAGED; } - // 2 clicks: tempcheck mode - else if (event == EV_2clicks) { - #ifdef USE_THERMAL_REGULATION - set_state(tempcheck_state, 0); - #else - set_state(battcheck_state, 0); - #endif - return MISCHIEF_MANAGED; - } // 4 clicks: beacon config mode else if (event == EV_4clicks) { push_state(beacon_config_state, 0); @@ -922,6 +912,7 @@ uint8_t beacon_state(EventPtr event, uint16_t arg) { } +#ifdef USE_GOODNIGHT_MODE #define GOODNIGHT_TICKS_PER_STEPDOWN (GOODNIGHT_TIME*TICKS_PER_SECOND*60L/GOODNIGHT_LEVEL) uint8_t goodnight_state(EventPtr event, uint16_t arg) { static uint16_t ticks_since_stepdown = 0; @@ -960,6 +951,7 @@ uint8_t goodnight_state(EventPtr event, uint16_t arg) { } return EVENT_NOT_HANDLED; } +#endif uint8_t lockout_state(EventPtr event, uint16_t arg) { @@ -1647,7 +1639,10 @@ void loop() { else if ( (state == steady_state) || (state == off_state) || (state == lockout_state) - || (state == goodnight_state) ) { + #ifdef USE_GOODNIGHT_MODE + || (state == goodnight_state) + #endif + ) { // doze until next clock tick idle_mode(); } -- cgit v1.2.3 From a59a93326bffc24725f44499415e96c16ea6b541 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 26 Jun 2018 19:49:12 -0600 Subject: Mostly got Emisar UI working... I think. Not yet tested. --- spaghetti-monster/anduril/rampingiosv3.c | 685 +++---------------------------- spaghetti-monster/fsm-events.h | 74 ++++ 2 files changed, 130 insertions(+), 629 deletions(-) diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c index ac49444..12550cc 100644 --- a/spaghetti-monster/anduril/rampingiosv3.c +++ b/spaghetti-monster/anduril/rampingiosv3.c @@ -54,44 +54,15 @@ //#define BATTCHECK_8bars // FIXME: breaks build //#define BATTCHECK_4bars // FIXME: breaks build -// enable/disable various modes -//#define USE_LIGHTNING_MODE -//#define USE_CANDLE_MODE -//#define USE_GOODNIGHT_MODE -//#define USE_MUGGLE_MODE - -#ifdef USE_GOODNIGHT_MODE -#define GOODNIGHT_TIME 60 // minutes (approximately) -#define GOODNIGHT_LEVEL 24 // ~11 lm -#endif - -// dual-switch support (second switch is a tail clicky) -//#define START_AT_MEMORIZED_LEVEL - /********* Configure SpaghettiMonster *********/ #define USE_DELAY_ZERO #define USE_RAMPING #define RAMP_LENGTH 150 -#define MAX_BIKING_LEVEL 120 // should be 127 or less #define USE_BATTCHECK -#ifdef USE_MUGGLE_MODE -#define MAX_CLICKS 6 -#define MUGGLE_FLOOR 22 -#define MUGGLE_CEILING (MAX_1x7135+20) -#else -#define MAX_CLICKS 5 -#endif +#define MAX_CLICKS 14 #define USE_IDLE_MODE // reduce power use while awake and no tasks are pending #define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency -// full FET strobe can be a bit much... use max regulated level instead, -// if there's a bright enough regulated level -#ifdef MAX_Nx7135 -#define STROBE_BRIGHTNESS MAX_Nx7135 -#else -#define STROBE_BRIGHTNESS MAX_LEVEL -#endif - // specific settings for known driver types #if defined(FSM_BLF_GT_DRIVER) #include "cfg-blf-gt.h" @@ -120,28 +91,7 @@ #else #define EEPROM_BYTES 12 #endif -#ifdef START_AT_MEMORIZED_LEVEL -#define USE_EEPROM_WL -#define EEPROM_WL_BYTES 1 -#endif -// auto-configure other stuff... -#if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) -#define USE_PSEUDO_RAND -#endif -// count the strobe modes (seems like there should be an easier way to do this) -#define NUM_STROBES_BASE 3 -#ifdef USE_LIGHTNING_MODE -#define ADD_LIGHTNING_STROBE 1 -#else -#define ADD_LIGHTNING_STROBE 0 -#endif -#ifdef USE_CANDLE_MODE -#define ADD_CANDLE_MODE 1 -#else -#define ADD_CANDLE_MODE 0 -#endif -#define NUM_STROBES (NUM_STROBES_BASE+ADD_LIGHTNING_STROBE+ADD_CANDLE_MODE) #include "spaghetti-monster.h" @@ -157,8 +107,6 @@ 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); -// party and tactical strobes -uint8_t strobe_state(EventPtr event, uint16_t arg); #ifdef USE_BATTCHECK uint8_t battcheck_state(EventPtr event, uint16_t arg); #endif @@ -166,10 +114,6 @@ uint8_t battcheck_state(EventPtr event, uint16_t arg); uint8_t tempcheck_state(EventPtr event, uint16_t arg); uint8_t thermal_config_state(EventPtr event, uint16_t arg); #endif -#ifdef USE_GOODNIGHT_MODE -// 1-hour ramp down from low, then automatic off -uint8_t goodnight_state(EventPtr event, uint16_t arg); -#endif // 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); @@ -178,11 +122,6 @@ uint8_t beacon_config_state(EventPtr event, uint16_t arg); uint8_t lockout_state(EventPtr event, uint16_t arg); // momentary / signalling mode uint8_t momentary_state(EventPtr 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_mode_active = 0; -#endif // general helper function for config modes uint8_t number_entry_state(EventPtr event, uint16_t arg); @@ -193,13 +132,13 @@ void blink_confirm(uint8_t num); #if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) void indicator_blink(uint8_t arg); #endif +#ifdef USE_INDICATOR_LED +uint8_t auxled_next_state(EventPtr event, uint16_t arg); +#endif // remember stuff even after battery was changed void load_config(); void save_config(); -#ifdef START_AT_MEMORIZED_LEVEL -void save_config_wl(); -#endif // default ramp options if not overridden earlier per-driver #ifndef RAMP_SMOOTH_FLOOR @@ -255,22 +194,6 @@ uint8_t nearest_level(int16_t target); uint8_t target_level = 0; #endif -// strobe timing -volatile uint8_t strobe_delays[] = { 40, 67 }; // party strobe, tactical strobe -// 0 == bike flasher -// 1 == party strobe -// 2 == tactical strobe -// 3 == lightning storm -// 4 == candle mode -volatile uint8_t strobe_type = 4; - -// bike mode config options -volatile uint8_t bike_flasher_brightness = MAX_1x7135; - -#ifdef USE_CANDLE_MODE -uint8_t triangle_wave(uint8_t phase); -#endif - // beacon timing volatile uint8_t beacon_seconds = 2; @@ -356,31 +279,33 @@ uint8_t off_state(EventPtr event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif - // click, click, long-click: strobe mode - else if (event == EV_click3_hold) { - set_state(strobe_state, 0); + // 4 clicks: momentary + else if (event == EV_4clicks) { + blink_confirm(1); + set_state(momentary_state, 0); return MISCHIEF_MANAGED; } - // 4 clicks: soft lockout - else if (event == EV_4clicks) { + // 6 clicks: lockout mode + else if (event == EV_6clicks) { blink_confirm(2); set_state(lockout_state, 0); return MISCHIEF_MANAGED; } - // 5 clicks: momentary mode - else if (event == EV_5clicks) { - blink_confirm(1); - set_state(momentary_state, 0); + // 8 clicks: beacon mode + else if (event == EV_8clicks) { + set_state(beacon_state, 0); return MISCHIEF_MANAGED; } - #ifdef USE_MUGGLE_MODE - // 6 clicks: muggle mode - else if (event == EV_6clicks) { - blink_confirm(1); - set_state(muggle_state, 0); + // 10 clicks: thermal config mode + else if (event == EV_10clicks) { + set_state(thermal_config_state, 0); + return MISCHIEF_MANAGED; + } + // 14 clicks: next aux LED mode + else if (event == EV_14clicks) { + set_state(auxled_next_state, 0); return MISCHIEF_MANAGED; } - #endif return EVENT_NOT_HANDLED; } @@ -450,9 +375,6 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { #endif #endif save_config(); - #ifdef START_AT_MEMORIZED_LEVEL - save_config_wl(); - #endif set_level(0); delay_4ms(20/4); set_level(memorized_level); @@ -521,15 +443,12 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { set_level(memorized_level); return MISCHIEF_MANAGED; } - #if defined(USE_REVERSING) || defined(START_AT_MEMORIZED_LEVEL) + #if defined(USE_REVERSING) // reverse ramp direction on hold release else if (event == EV_click1_hold_release) { #ifdef USE_REVERSING ramp_direction = -ramp_direction; #endif - #ifdef START_AT_MEMORIZED_LEVEL - save_config_wl(); - #endif return MISCHIEF_MANAGED; } #endif @@ -583,13 +502,6 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { set_level(memorized_level); return MISCHIEF_MANAGED; } - #ifdef START_AT_MEMORIZED_LEVEL - // click, release, hold, release: save new ramp level (if necessary) - else if (event == EV_click2_hold_release) { - save_config_wl(); - return MISCHIEF_MANAGED; - } - #endif #if defined(USE_SET_LEVEL_GRADUALLY) || defined(USE_REVERSING) else if (event == EV_tick) { #ifdef USE_REVERSING @@ -598,7 +510,10 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { #endif #ifdef USE_SET_LEVEL_GRADUALLY // make thermal adjustment speed scale with magnitude - if (arg & 1) return MISCHIEF_MANAGED; // adjust slower + // if we're on a really high mode, drop faster + if ((arg & 1) && (actual_level < THERM_DOUBLE_SPEED_LEVEL)) { + return MISCHIEF_MANAGED; // adjust slower when not a high mode + } // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] @@ -611,10 +526,6 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { if (target_level > actual_level) diff = target_level - actual_level; else { diff = actual_level - target_level; - // if we're on a really high mode, drop faster - if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { - diff <<= 1; - } } uint8_t magnitude = 0; while (diff) { @@ -680,190 +591,6 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { } -uint8_t strobe_state(EventPtr event, uint16_t arg) { - // 'st' reduces ROM size by avoiding access to a volatile var - // (maybe I should just make it nonvolatile?) - uint8_t st = strobe_type; - #ifdef USE_CANDLE_MODE - // 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) - 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; - static uint8_t candle_mode_brightness = 24; - static uint8_t candle_mode_timer = 0; - #define TICKS_PER_CANDLE_MINUTE 4096 // about 65 seconds - #define MINUTES_PER_CANDLE_HALFHOUR 27 // ish - #endif - - if (event == EV_enter_state) { - #ifdef USE_CANDLE_MODE - candle_mode_timer = 0; // in case any time was left over from earlier - #endif - return MISCHIEF_MANAGED; - } - // 1 click: off - else if (event == EV_1click) { - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - // 2 clicks: rotate through strobe/flasher modes - else if (event == EV_2clicks) { - strobe_type = (st + 1) % NUM_STROBES; - #ifdef USE_CANDLE_MODE - candle_mode_timer = 0; // in case any time was left over from earlier - #endif - interrupt_nice_delays(); - save_config(); - return MISCHIEF_MANAGED; - } - // hold: change speed (go faster) - // or change brightness (brighter) - else if (event == EV_click1_hold) { - // biking mode brighter - if (st == 0) { - if (bike_flasher_brightness < MAX_BIKING_LEVEL) - bike_flasher_brightness ++; - set_level(bike_flasher_brightness); - } - // strobe faster - else if (st < 3) { - if ((arg & 1) == 0) { - if (strobe_delays[st-1] > 8) strobe_delays[st-1] --; - } - } - // lightning has no adjustments - // else if (st == 3) {} - #ifdef USE_CANDLE_MODE - // candle mode brighter - else if (st == 4) { - if (candle_mode_brightness < MAX_CANDLE_LEVEL) - candle_mode_brightness ++; - } - #endif - return MISCHIEF_MANAGED; - } - // click, hold: change speed (go slower) - // or change brightness (dimmer) - else if (event == EV_click2_hold) { - // biking mode dimmer - if (st == 0) { - if (bike_flasher_brightness > 2) - bike_flasher_brightness --; - set_level(bike_flasher_brightness); - } - // strobe slower - else if (st < 3) { - if ((arg & 1) == 0) { - if (strobe_delays[st-1] < 255) strobe_delays[st-1] ++; - } - } - // lightning has no adjustments - // else if (st == 3) {} - #ifdef USE_CANDLE_MODE - // candle mode dimmer - else if (st == 4) { - if (candle_mode_brightness > 1) - candle_mode_brightness --; - } - #endif - return MISCHIEF_MANAGED; - } - // release hold: save new strobe settings - else if ((event == EV_click1_hold_release) - || (event == EV_click2_hold_release)) { - save_config(); - return MISCHIEF_MANAGED; - } - #if defined(USE_CANDLE_MODE) - // 3 clicks: add 30m to candle timer - else if (event == EV_3clicks) { - // candle mode only - if (st == 4) { - if (candle_mode_timer < (255 - MINUTES_PER_CANDLE_HALFHOUR)) { - // add 30m to the timer - candle_mode_timer += MINUTES_PER_CANDLE_HALFHOUR; - // blink to confirm - set_level(actual_level + 32); - delay_4ms(2); - } - } - return MISCHIEF_MANAGED; - } - #endif - #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) - // clock tick: bump the random seed - else if (event == EV_tick) { - #ifdef USE_LIGHTNING_MODE - pseudo_rand_seed += arg; - #endif - #ifdef USE_CANDLE_MODE - if (st == 4) { - // self-timer dims the light during the final minute - uint8_t subtract = 0; - if (candle_mode_timer == 1) { - subtract = ((candle_mode_brightness+20) - * ((arg & (TICKS_PER_CANDLE_MINUTE-1)) >> 4)) - >> 8; - } - // we passed a minute mark, decrease timer if it's running - if ((arg & (TICKS_PER_CANDLE_MINUTE-1)) == (TICKS_PER_CANDLE_MINUTE - 1)) { - if (candle_mode_timer > 0) { - candle_mode_timer --; - //set_level(0); delay_4ms(2); - // if the timer ran out, shut off - if (! candle_mode_timer) { - set_state(off_state, 0); - } - } - } - // 3-oscillator synth for a relatively organic pattern - uint8_t add; - add = ((triangle_wave(candle_wave1) * 8) >> 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; - if (brightness < 0) { brightness = 0; } - set_level(brightness); - - // wave1: slow random LFO - if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; - // wave2: medium-speed erratic LFO - candle_wave2 += candle_wave2_speed; - // wave3: erratic fast wave - candle_wave3 += pseudo_rand() % 37; - // S&H on wave2 frequency to make it more erratic - if ((pseudo_rand() & 0b00111111) == 0) - candle_wave2_speed = pseudo_rand() % 13; - // downward sawtooth on wave2 depth to simulate stabilizing - if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) - candle_wave2_depth --; - // random sawtooth retrigger - if ((pseudo_rand()) == 0) { - candle_wave2_depth = 7; - //candle_wave3_depth = 5; - candle_wave2 = 0; - } - // downward sawtooth on wave3 depth to simulate stabilizing - if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) - candle_wave3_depth --; - if ((pseudo_rand() & 0b01111111) == 0) - candle_wave3_depth = 5; - } - #endif - return MISCHIEF_MANAGED; - } - #endif - return EVENT_NOT_HANDLED; -} - - #ifdef USE_BATTCHECK uint8_t battcheck_state(EventPtr event, uint16_t arg) { // 1 click: off @@ -880,6 +607,7 @@ uint8_t battcheck_state(EventPtr event, uint16_t arg) { } #endif + #ifdef USE_THERMAL_REGULATION uint8_t tempcheck_state(EventPtr event, uint16_t arg) { // 1 click: off @@ -903,6 +631,8 @@ uint8_t beacon_state(EventPtr event, uint16_t arg) { set_state(off_state, 0); return MISCHIEF_MANAGED; } + // TODO: use sleep ticks to measure time between pulses, + // to save power // 4 clicks: beacon config mode else if (event == EV_4clicks) { push_state(beacon_config_state, 0); @@ -912,48 +642,6 @@ uint8_t beacon_state(EventPtr event, uint16_t arg) { } -#ifdef USE_GOODNIGHT_MODE -#define GOODNIGHT_TICKS_PER_STEPDOWN (GOODNIGHT_TIME*TICKS_PER_SECOND*60L/GOODNIGHT_LEVEL) -uint8_t goodnight_state(EventPtr event, uint16_t arg) { - static uint16_t ticks_since_stepdown = 0; - // blink on start - if (event == EV_enter_state) { - ticks_since_stepdown = 0; - blink_confirm(2); - set_level(GOODNIGHT_LEVEL); - return MISCHIEF_MANAGED; - } - // 1 click: off - else if (event == EV_1click) { - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - // 2 clicks: beacon mode - else if (event == EV_2clicks) { - set_state(beacon_state, 0); - return MISCHIEF_MANAGED; - } - // tick: step down (maybe) or off (maybe) - else if (event == EV_tick) { - if (++ticks_since_stepdown > GOODNIGHT_TICKS_PER_STEPDOWN) { - ticks_since_stepdown = 0; - set_level(actual_level-1); - if (! actual_level) { - #if 0 // test blink, to help measure timing - set_level(MAX_LEVEL>>2); - delay_4ms(8/2); - set_level(0); - #endif - set_state(off_state, 0); - } - } - return MISCHIEF_MANAGED; - } - return EVENT_NOT_HANDLED; -} -#endif - - uint8_t lockout_state(EventPtr event, uint16_t arg) { #ifdef MOON_DURING_LOCKOUT_MODE // momentary(ish) moon mode during lockout @@ -1064,6 +752,30 @@ uint8_t lockout_state(EventPtr event, uint16_t arg) { } +#ifdef USE_INDICATOR_LED +uint8_t auxled_next_state(EventPtr event, uint16_t arg) { + if (event == EV_enter_state) { + uint8_t mode = indicator_led_mode & 3; + #ifdef TICK_DURING_STANDBY + mode = (mode + 1) & 3; + #else + mode = (mode + 1) % 3; + #endif + indicator_led_mode = mode + (indicator_led_mode & 0b00001100); + indicator_led(mode); + save_config(); + return MISCHIEF_MANAGED; + } + else { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} +#endif + + uint8_t momentary_state(EventPtr event, uint16_t arg) { // TODO: momentary strobe here? (for light painting) if (event == EV_click1_press) { @@ -1096,144 +808,6 @@ uint8_t momentary_state(EventPtr event, uint16_t arg) { } -#ifdef USE_MUGGLE_MODE -uint8_t muggle_state(EventPtr event, uint16_t arg) { - static int8_t ramp_direction; - static int8_t muggle_off_mode; - - // turn LED off when we first enter the mode - if (event == EV_enter_state) { - ramp_direction = 1; - - #ifdef START_AT_MEMORIZED_LEVEL - memorized_level = arg; - muggle_off_mode = 0; - set_level(memorized_level); - - if (! muggle_mode_active) { // don't write eeprom at every boot - muggle_mode_active = 1; - save_config(); - } - #else - muggle_mode_active = 1; - save_config(); - - muggle_off_mode = 1; - //memorized_level = MAX_1x7135; - memorized_level = (MUGGLE_FLOOR + MUGGLE_CEILING) / 2; - #endif - return MISCHIEF_MANAGED; - } - // initial press: moon hint - else if (event == EV_click1_press) { - if (muggle_off_mode) - set_level(MUGGLE_FLOOR); - } - // initial release: direct to memorized level - else if (event == EV_click1_release) { - if (muggle_off_mode) - set_level(memorized_level); - } - // if the user keeps pressing, turn off - else if (event == EV_click2_press) { - muggle_off_mode = 1; - set_level(0); - } - // 1 click: on/off - else if (event == EV_1click) { - muggle_off_mode ^= 1; - if (muggle_off_mode) { - set_level(0); - } - /* - else { - set_level(memorized_level); - } - */ - return MISCHIEF_MANAGED; - } - // hold: change brightness - else if (event == EV_click1_hold) { - // ramp at half speed - if (arg & 1) return MISCHIEF_MANAGED; - - // if off, start at bottom - if (muggle_off_mode) { - muggle_off_mode = 0; - ramp_direction = 1; - set_level(MUGGLE_FLOOR); - } - else { - uint8_t m; - m = actual_level; - // ramp down if already at ceiling - if ((arg <= 1) && (m >= MUGGLE_CEILING)) ramp_direction = -1; - // ramp - m += ramp_direction; - if (m < MUGGLE_FLOOR) - m = MUGGLE_FLOOR; - if (m > MUGGLE_CEILING) - m = MUGGLE_CEILING; - memorized_level = m; - set_level(m); - } - return MISCHIEF_MANAGED; - } - // reverse ramp direction on hold release - else if (event == EV_click1_hold_release) { - ramp_direction = -ramp_direction; - #ifdef START_AT_MEMORIZED_LEVEL - save_config_wl(); // momentary use should retain brightness level - #endif - return MISCHIEF_MANAGED; - } - /* - // click, hold: change brightness (dimmer) - else if (event == EV_click2_hold) { - ramp_direction = 1; - if (memorized_level > MUGGLE_FLOOR) - memorized_level = actual_level - 1; - set_level(memorized_level); - return MISCHIEF_MANAGED; - } - */ - // 6 clicks: exit muggle mode - else if (event == EV_6clicks) { - blink_confirm(1); - muggle_mode_active = 0; - save_config(); - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - // tick: housekeeping - else if (event == EV_tick) { - // un-reverse after 1 second - if (arg == TICKS_PER_SECOND) ramp_direction = 1; - - // turn off, but don't go to the main "off" state - if (muggle_off_mode) { - if (arg > TICKS_PER_SECOND*1) { // sleep after 1 second - go_to_standby = 1; // sleep while light is off - } - } - return MISCHIEF_MANAGED; - } - // low voltage is handled specially in muggle mode - else if(event == EV_voltage_low) { - uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); - if (lvl >= MUGGLE_FLOOR) { - set_level(lvl); - } else { - muggle_off_mode = 1; - } - return MISCHIEF_MANAGED; - } - - return EVENT_NOT_HANDLED; -} -#endif - - // 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 num_config_steps, @@ -1483,15 +1057,6 @@ void indicator_blink(uint8_t arg) { #endif -#ifdef USE_CANDLE_MODE -uint8_t triangle_wave(uint8_t phase) { - uint8_t result = phase << 1; - if (phase > 127) result = 255 - result; - return result; -} -#endif - - void load_config() { if (load_eeprom()) { ramp_style = eeprom[0]; @@ -1500,14 +1065,7 @@ void load_config() { ramp_discrete_floor = eeprom[3]; ramp_discrete_ceil = eeprom[4]; ramp_discrete_steps = eeprom[5]; - strobe_type = eeprom[6]; // TODO: move this to eeprom_wl? - strobe_delays[0] = eeprom[7]; - strobe_delays[1] = eeprom[8]; - bike_flasher_brightness = eeprom[9]; beacon_seconds = eeprom[10]; - #ifdef USE_MUGGLE_MODE - muggle_mode_active = eeprom[11]; - #endif #ifdef USE_THERMAL_REGULATION therm_ceil = eeprom[12]; therm_cal_offset = eeprom[13]; @@ -1516,11 +1074,6 @@ void load_config() { indicator_led_mode = eeprom[14]; #endif } - #ifdef START_AT_MEMORIZED_LEVEL - if (load_eeprom_wl()) { - memorized_level = eeprom_wl[0]; - } - #endif } void save_config() { @@ -1530,14 +1083,7 @@ void save_config() { eeprom[3] = ramp_discrete_floor; eeprom[4] = ramp_discrete_ceil; eeprom[5] = ramp_discrete_steps; - eeprom[6] = strobe_type; // TODO: move this to eeprom_wl? - eeprom[7] = strobe_delays[0]; - eeprom[8] = strobe_delays[1]; - eeprom[9] = bike_flasher_brightness; eeprom[10] = beacon_seconds; - #ifdef USE_MUGGLE_MODE - eeprom[11] = muggle_mode_active; - #endif #ifdef USE_THERMAL_REGULATION eeprom[12] = therm_ceil; eeprom[13] = therm_cal_offset; @@ -1549,23 +1095,11 @@ void save_config() { save_eeprom(); } -#ifdef START_AT_MEMORIZED_LEVEL -void save_config_wl() { - eeprom_wl[0] = memorized_level; - save_eeprom_wl(); -} -#endif - void low_voltage() { StatePtr state = current_state; - // "step down" from strobe to something low - if (state == strobe_state) { - set_state(steady_state, RAMP_SIZE/6); - } - // in normal or muggle mode, step down or turn off - //else if ((state == steady_state) || (state == muggle_state)) { - else if (state == steady_state) { + // in normal mode, step down or turn off + if (state == steady_state) { if (actual_level > 1) { uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); set_level(lvl); @@ -1589,25 +1123,6 @@ void low_voltage() { void setup() { - #ifdef START_AT_MEMORIZED_LEVEL - // dual switch: e-switch + power clicky - // power clicky acts as a momentary mode - load_config(); - - #ifdef USE_MUGGLE_MODE - if (muggle_mode_active) - push_state(muggle_state, memorized_level); - else - #endif - if (button_is_pressed()) - // hold button to go to moon - push_state(steady_state, 1); - else - // otherwise use memory - push_state(steady_state, memorized_level); - - #else // if not START_AT_MEMORIZED_LEVEL - // blink at power-on to let user know power is connected set_level(RAMP_SIZE/8); delay_4ms(3); @@ -1615,14 +1130,7 @@ void setup() { load_config(); - #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 - + push_state(off_state, 0); } @@ -1639,93 +1147,12 @@ void loop() { else if ( (state == steady_state) || (state == off_state) || (state == lockout_state) - #ifdef USE_GOODNIGHT_MODE - || (state == goodnight_state) - #endif ) { // doze until next clock tick idle_mode(); } #endif - if (state == strobe_state) { - uint8_t st = strobe_type; - // bike flasher - if (st == 0) { - uint8_t burst = bike_flasher_brightness << 1; - if (burst > MAX_LEVEL) burst = MAX_LEVEL; - for(uint8_t i=0; i<4; i++) { - set_level(burst); - if (! nice_delay_ms(5)) return; - set_level(bike_flasher_brightness); - if (! nice_delay_ms(65)) return; - } - nice_delay_ms(720); // no return check necessary on final delay - } - // party / tactical strobe - else if (st < 3) { - uint8_t del = strobe_delays[st-1]; - // TODO: make tac strobe brightness configurable? - set_level(STROBE_BRIGHTNESS); - CLKPR = 1<> 1); - } - set_level(0); - nice_delay_ms(del); // no return check necessary on final delay - } - #ifdef USE_LIGHTNING_MODE - // lightning storm - else if (st == 3) { - int16_t brightness; - uint16_t rand_time; - - // turn the emitter on at a random level, - // for a random amount of time between 1ms and 32ms - //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 += pseudo_rand() % brightness; // 2 to 159 now (w/ low bias) - if (brightness > MAX_LEVEL) brightness = MAX_LEVEL; - set_level(brightness); - if (! nice_delay_ms(rand_time)) return; - - // decrease the brightness somewhat more gradually, like lightning - uint8_t stepdown = brightness >> 3; - if (stepdown < 1) stepdown = 1; - while(brightness > 1) { - if (! nice_delay_ms(rand_time)) return; - brightness -= stepdown; - if (brightness < 0) brightness = 0; - set_level(brightness); - /* - if ((brightness < MAX_LEVEL/2) && (! (pseudo_rand() & 15))) { - brightness <<= 1; - set_level(brightness); - } - */ - if (! (pseudo_rand() & 3)) { - if (! nice_delay_ms(rand_time)) return; - set_level(brightness>>1); - } - } - - // turn the emitter off, - // for a random amount of time between 1ms and 8192ms - // (with a low bias) - rand_time = 1 << (pseudo_rand() % 13); - rand_time += pseudo_rand() % rand_time; - set_level(0); - nice_delay_ms(rand_time); // no return check necessary on final delay - - } - #endif - } - #ifdef USE_BATTCHECK else if (state == battcheck_state) { battcheck(); diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h index 4a67347..0212c2c 100644 --- a/spaghetti-monster/fsm-events.h +++ b/spaghetti-monster/fsm-events.h @@ -68,6 +68,7 @@ static volatile uint16_t ticks_since_last_event = 0; #define A_DEBUG 255 // test event for debugging // Event types +// TODO: make these progmem-only? Event EV_debug[] = { A_DEBUG, 0 } ; @@ -407,9 +408,76 @@ Event EV_click12_complete[] = { A_RELEASE_TIMEOUT, 0 }; #endif +#if MAX_CLICKS >= 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_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, @@ -458,6 +526,12 @@ EventPtr event_sequences[] = { #if MAX_CLICKS >= 12 EV_click12_complete, #endif + #if MAX_CLICKS >= 13 + EV_click13_complete, + #endif + #if MAX_CLICKS >= 14 + EV_click14_complete, + #endif // ... }; -- cgit v1.2.3 From 687cf0f31db72f3f614af262dc33c150af11dd98 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 26 Jun 2018 19:56:01 -0600 Subject: Forgot to change lockout mode exit mapping and remove off_state aux LED UI in lockout mode. --- spaghetti-monster/anduril/rampingiosv3.c | 34 ++------------------------------ 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c index 12550cc..ab148ed 100644 --- a/spaghetti-monster/anduril/rampingiosv3.c +++ b/spaghetti-monster/anduril/rampingiosv3.c @@ -710,39 +710,9 @@ uint8_t lockout_state(EventPtr event, uint16_t arg) { save_config(); return MISCHIEF_MANAGED; } - // click, click, hold: rotate through indicator LED modes (off mode) - else if (event == EV_click3_hold) { - #ifndef USE_INDICATOR_LED_WHILE_RAMPING - // if main LED obscures aux LEDs, turn it off - // FIXME: might not work, since it was turned on just a few clock - // cycles ago at beginning of this function - set_level(0); - #endif - #ifdef TICK_DURING_STANDBY - uint8_t mode = (arg >> 5) & 3; - #else - uint8_t mode = (arg >> 5) % 3; - #endif - indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; - #ifdef TICK_DURING_STANDBY - if (mode == 3) - indicator_led(mode & (arg&3)); - else - indicator_led(mode); - #else - indicator_led(mode); - #endif - //save_config(); - return MISCHIEF_MANAGED; - } - // click, click, hold, release: save indicator LED mode (off mode) - else if (event == EV_click3_hold_release) { - save_config(); - return MISCHIEF_MANAGED; - } #endif - // 4 clicks: exit - else if (event == EV_4clicks) { + // 6 clicks: exit + else if (event == EV_6clicks) { blink_confirm(1); set_state(off_state, 0); return MISCHIEF_MANAGED; -- cgit v1.2.3 From 175de43e01adcf75b6d1935eb5e41752c5cf7227 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 27 Jun 2018 00:35:01 -0600 Subject: Fixed return from therm_config state, removed unused eeprom slots, reorganized some #defines to be more robust. --- spaghetti-monster/anduril/rampingiosv3.c | 61 +++++++++++++++++++------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c index ab148ed..e4fae2d 100644 --- a/spaghetti-monster/anduril/rampingiosv3.c +++ b/spaghetti-monster/anduril/rampingiosv3.c @@ -54,16 +54,7 @@ //#define BATTCHECK_8bars // FIXME: breaks build //#define BATTCHECK_4bars // FIXME: breaks build -/********* Configure SpaghettiMonster *********/ -#define USE_DELAY_ZERO -#define USE_RAMPING -#define RAMP_LENGTH 150 -#define USE_BATTCHECK -#define MAX_CLICKS 14 -#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending -#define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency - -// specific settings for known driver types +/***** specific settings for known driver types *****/ #if defined(FSM_BLF_GT_DRIVER) #include "cfg-blf-gt.h" @@ -81,17 +72,37 @@ #endif +/********* Configure SpaghettiMonster *********/ +#define USE_DELAY_ZERO +#define USE_RAMPING +#define RAMP_LENGTH 150 +#define USE_BATTCHECK +#ifdef USE_INDICATOR_LED +#define MAX_CLICKS 14 +#else +#define MAX_CLICKS 10 +#endif +#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending +#define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency + // try to auto-detect how many eeprom bytes -// FIXME: detect this better, and assign offsets better, for various configs #define USE_EEPROM +#define EEPROM_BYTES_BASE 7 + #ifdef USE_INDICATOR_LED -#define EEPROM_BYTES 15 -#elif defined(USE_THERMAL_REGULATION) -#define EEPROM_BYTES 14 +#define EEPROM_INDICATOR_BYTES 1 #else -#define EEPROM_BYTES 12 +#define EEPROM_INDICATOR_BYTES 0 #endif +#ifdef USE_THERMAL_REGULATION +#define EEPROM_THERMAL_BYTES 2 +#else +#define EEPROM_THERMAL_BYTES 0 +#endif + +#define EEPROM_BYTES (EEPROM_BYTES_BASE+EEPROM_INDICATOR_BYTES+EEPROM_THERMAL_BYTES) + #include "spaghetti-monster.h" @@ -298,14 +309,16 @@ uint8_t off_state(EventPtr event, uint16_t arg) { } // 10 clicks: thermal config mode else if (event == EV_10clicks) { - set_state(thermal_config_state, 0); + push_state(thermal_config_state, 0); return MISCHIEF_MANAGED; } + #ifdef USE_INDICATOR_LED // 14 clicks: next aux LED mode else if (event == EV_14clicks) { set_state(auxled_next_state, 0); return MISCHIEF_MANAGED; } + #endif return EVENT_NOT_HANDLED; } @@ -1035,13 +1048,13 @@ void load_config() { ramp_discrete_floor = eeprom[3]; ramp_discrete_ceil = eeprom[4]; ramp_discrete_steps = eeprom[5]; - beacon_seconds = eeprom[10]; + beacon_seconds = eeprom[6]; #ifdef USE_THERMAL_REGULATION - therm_ceil = eeprom[12]; - therm_cal_offset = eeprom[13]; + therm_ceil = eeprom[EEPROM_BYTES_BASE]; + therm_cal_offset = eeprom[EEPROM_BYTES_BASE+1]; #endif #ifdef USE_INDICATOR_LED - indicator_led_mode = eeprom[14]; + indicator_led_mode = eeprom[EEPROM_BYTES_BASE+EEPROM_THERMAL_BYTES]; #endif } } @@ -1053,13 +1066,13 @@ void save_config() { eeprom[3] = ramp_discrete_floor; eeprom[4] = ramp_discrete_ceil; eeprom[5] = ramp_discrete_steps; - eeprom[10] = beacon_seconds; + eeprom[6] = beacon_seconds; #ifdef USE_THERMAL_REGULATION - eeprom[12] = therm_ceil; - eeprom[13] = therm_cal_offset; + eeprom[EEPROM_BYTES_BASE ] = therm_ceil; + eeprom[EEPROM_BYTES_BASE+1] = therm_cal_offset; #endif #ifdef USE_INDICATOR_LED - eeprom[14] = indicator_led_mode; + eeprom[EEPROM_BYTES_BASE+EEPROM_THERMAL_BYTES] = indicator_led_mode; #endif save_eeprom(); -- cgit v1.2.3 From 21139e619f30ea51be8ebda00966fb7ef090e9c9 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 27 Jun 2018 00:58:04 -0600 Subject: Move driver-specific ramp tables into the driver's config file. Added a method to allow driver configs to override default ramp tables. --- spaghetti-monster/anduril/anduril.c | 35 +++++++++++++------------- spaghetti-monster/anduril/cfg-blf-gt.h | 18 +++++++++++++ spaghetti-monster/anduril/cfg-blf-q8.h | 15 +++++++++++ spaghetti-monster/anduril/cfg-emisar-d4.h | 13 ++++++++++ spaghetti-monster/anduril/cfg-fw3a.h | 17 +++++++++++++ spaghetti-monster/fsm-ramping.h | 42 +++++++++++++------------------ 6 files changed, 98 insertions(+), 42 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index abd3ed8..a29adae 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -33,7 +33,7 @@ #ifdef MAX_Nx7135 #define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 // throttle back faster when high #else -#define THERM_DOUBLE_SPEED_LEVEL (RAMP_LENGTH*4/5) // throttle back faster when high +#define THERM_DOUBLE_SPEED_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high #endif #ifdef USE_THERMAL_REGULATION #define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments @@ -65,10 +65,26 @@ // dual-switch support (second switch is a tail clicky) //#define START_AT_MEMORIZED_LEVEL +/***** specific settings for known driver types *****/ +#if defined(FSM_BLF_GT_DRIVER) +#include "cfg-blf-gt.h" + +#elif FSM_BLF_Q8_DRIVER +#include "cfg-blf-q8.h" + +#elif defined(FSM_EMISAR_D4_DRIVER) +#include "cfg-emisar-d4.h" + +#elif defined(FSM_FW3A_DRIVER) +#include "cfg-fw3a.h" + +#endif + + /********* Configure SpaghettiMonster *********/ #define USE_DELAY_ZERO #define USE_RAMPING -#define RAMP_LENGTH 150 +#define RAMP_LENGTH 150 // default, if not overridden in a driver cfg file #define MAX_BIKING_LEVEL 120 // should be 127 or less #define USE_BATTCHECK #ifdef USE_MUGGLE_MODE @@ -89,21 +105,6 @@ #define STROBE_BRIGHTNESS MAX_LEVEL #endif -// specific settings for known driver types -#if defined(FSM_BLF_GT_DRIVER) -#include "cfg-blf-gt.h" - -#elif FSM_BLF_Q8_DRIVER -#include "cfg-blf-q8.h" - -#elif defined(FSM_EMISAR_D4_DRIVER) -#include "cfg-emisar-d4.h" - -#elif defined(FSM_FW3A_DRIVER) -#include "cfg-fw3a.h" - -#endif - // try to auto-detect how many eeprom bytes // FIXME: detect this better, and assign offsets better, for various configs #define USE_EEPROM diff --git a/spaghetti-monster/anduril/cfg-blf-gt.h b/spaghetti-monster/anduril/cfg-blf-gt.h index 904668a..a576d04 100644 --- a/spaghetti-monster/anduril/cfg-blf-gt.h +++ b/spaghetti-monster/anduril/cfg-blf-gt.h @@ -14,6 +14,24 @@ //#undef USE_SET_LEVEL_GRADUALLY +#ifdef RAMP_LENGTH +#undef RAMP_LENGTH +#endif + +#define RAMP_LENGTH 150 +// First 60 values: level_calc.py 1 60 7135 4 5.0 255 +// Remainder: all 255 (buck driver at 100% duty cycle) +#define PWM1_LEVELS 4,5,6,6,7,8,9,11,12,13,15,16,18,19,21,23,25,27,30,32,34,37,40,43,46,49,52,55,59,63,66,70,75,79,83,88,93,98,103,108,114,119,125,131,137,144,150,157,164,171,179,186,194,202,210,219,228,236,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 +// First 60 values: all 25 (buck driver at 10% power) +// Remainder: values 61-150 of level_calc.py 1 150 7135 1 3 3000 +#define PWM2_LEVELS 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, \ + 26,27,28,29,30,31,32,33,35,36,37,38,40,41,42,44,45,47,48,50,51,53,54,56,58,59,61,63,65,67,69,70,72,74,76,79,81,83,85,87,89,92,94,96,99,101,104,106,109,112,114,117,120,123,125,128,131,134,137,140,143,147,150,153,156,160,163,167,170,174,177,181,184,188,192,196,200,204,208,212,216,220,224,228,233,237,241,246,250,255 +#define POWER_80PX 138 // 2.0 Amps out of maximum 2.5 Amps +#define MAX_1x7135 60 // where it switches from PWM to current control +#define HALFSPEED_LEVEL 17 +#define QUARTERSPEED_LEVEL 6 + // use 2.0 A as the ceiling, 2.5 A only for turbo // start both ramps at the bottom; even moon throws a long way on the GT #define RAMP_SMOOTH_FLOOR 1 diff --git a/spaghetti-monster/anduril/cfg-blf-q8.h b/spaghetti-monster/anduril/cfg-blf-q8.h index 929fb55..7733721 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8.h +++ b/spaghetti-monster/anduril/cfg-blf-q8.h @@ -7,3 +7,18 @@ // enable blinking indicator LED while off #define TICK_DURING_STANDBY +#ifdef RAMP_LENGTH +#undef RAMP_LENGTH +#endif + +// copied from Emisar D4 ramp +// ../../bin/level_calc.py 1 65 7135 1 0.8 150 +// ... mixed with this: +// ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 +#define RAMP_LENGTH 150 +#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,0 +#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,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 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h index 5421110..d17e2b0 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -1 +1,14 @@ // Emisar D4 config options for Anduril + +#ifdef RAMP_LENGTH +#undef RAMP_LENGTH +#endif +// ../../bin/level_calc.py 1 65 7135 1 0.8 150 +// ... mixed with this: +// ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 +#define RAMP_LENGTH 150 +#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,0 +#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,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 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h index 420eaeb..3df426d 100644 --- a/spaghetti-monster/anduril/cfg-fw3a.h +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -1 +1,18 @@ // FW3A config options for Anduril + +#ifdef RAMP_LENGTH +#undef RAMP_LENGTH +#endif + +// ../../bin/level_calc.py 1 65 7135 1 0.8 150 +// ... mixed with this: +// ../../../bin/level_calc.py 3 150 7135 1 0.33 150 7135 1 1 850 FET 1 10 1500 +#define RAMP_LENGTH 150 +#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,0 +#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,0 +#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,19,31,43,55,67,79,91,104,117,130,143,157,170,184,198,212,226,240,255 +#define MAX_1x7135 65 +#define MAX_Nx7135 130 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 + diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 86742f6..b942ec0 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -33,18 +33,30 @@ inline void set_level_gradually(uint8_t lvl); void gradual_tick(); #endif -// ramp tables +// use UI-defined ramp tables if they exist +#ifdef PWM1_LEVELS +PROGMEM const uint8_t pwm1_levels[] = { PWM1_LEVELS }; +#endif +#ifdef PWM2_LEVELS +PROGMEM const uint8_t pwm2_levels[] = { PWM2_LEVELS }; +#endif +#ifdef PWM3_LEVELS +PROGMEM const uint8_t pwm3_levels[] = { PWM3_LEVELS }; +#endif +#ifdef PWM4_LEVELS +PROGMEM const uint8_t pwm4_levels[] = { PWM4_LEVELS }; +#endif + +// default / example ramps +#ifndef PWM1_LEVELS #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 @@ -60,23 +72,6 @@ void gradual_tick(); 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 - #ifdef FSM_BLF_GT_DRIVER - // First 60 values: level_calc.py 1 60 7135 4 5.0 255 - // Remainder: all 255 (buck driver at 100% duty cycle) - PROGMEM const uint8_t pwm1_levels[] = { 4,5,6,6,7,8,9,11,12,13,15,16,18,19,21,23,25,27,30,32,34,37,40,43,46,49,52,55,59,63,66,70,75,79,83,88,93,98,103,108,114,119,125,131,137,144,150,157,164,171,179,186,194,202,210,219,228,236,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 }; - // First 60 values: all 25 (buck driver at 10% power) - // Remainder: values 61-150 of level_calc.py 1 150 7135 1 3 3000 - PROGMEM const uint8_t pwm2_levels[] = { 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, - 26,27,28,29,30,31,32,33,35,36,37,38,40,41,42,44,45,47,48,50,51,53,54,56,58,59,61,63,65,67,69,70,72,74,76,79,81,83,85,87,89,92,94,96,99,101,104,106,109,112,114,117,120,123,125,128,131,134,137,140,143,147,150,153,156,160,163,167,170,174,177,181,184,188,192,196,200,204,208,212,216,220,224,228,233,237,241,246,250,255 }; - #define POWER_80PX 138 // 2.0 Amps out of maximum 2.5 Amps - #define MAX_1x7135 60 // where it switches from PWM to current control - #define HALFSPEED_LEVEL 17 - #define QUARTERSPEED_LEVEL 6 - #else - // ../../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 }; // ../../bin/level_calc.py 1 65 7135 1 0.8 150 // ... mixed with this: // ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 @@ -85,11 +80,9 @@ void gradual_tick(); #define MAX_1x7135 65 #define HALFSPEED_LEVEL 14 #define QUARTERSPEED_LEVEL 5 - #endif #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 }; @@ -97,7 +90,6 @@ void gradual_tick(); #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 }; @@ -105,7 +97,6 @@ void gradual_tick(); #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 1 65 7135 1 0.8 150 // ... mixed with this: // ../../../bin/level_calc.py 3 150 7135 1 0.33 150 7135 1 1 850 FET 1 10 1500 @@ -120,6 +111,7 @@ void gradual_tick(); #elif PWM_CHANNELS == 4 4-channel PWM not really supported yet, sorry. #endif +#endif // RAMP_SIZE / MAX_LVL #define RAMP_SIZE sizeof(pwm1_levels) -- cgit v1.2.3 From 12b1218a3e80e864cc35d6720c45aedfe4793c04 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 27 Jun 2018 02:34:25 -0600 Subject: Made high levels regulate down even faster. Added missing save_config() at the end of, um, config modes. Fixed ramp table indentation. --- spaghetti-monster/anduril/anduril.c | 11 ++++++----- spaghetti-monster/fsm-ramping.h | 16 ++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index a29adae..2b958cc 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -587,7 +587,9 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { #endif #ifdef USE_SET_LEVEL_GRADUALLY // make thermal adjustment speed scale with magnitude - if (arg & 1) return MISCHIEF_MANAGED; // adjust slower + if ((arg & 1) && (actual_level < THERM_DOUBLE_SPEED_LEVEL)) { + return MISCHIEF_MANAGED; // adjust slower when not a high mode + } // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] @@ -600,12 +602,10 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { if (target_level > actual_level) diff = target_level - actual_level; else { diff = actual_level - target_level; - // if we're on a really high mode, drop faster - if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { - diff <<= 1; - } } uint8_t magnitude = 0; + // if we're on a really high mode, drop faster + if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { magnitude ++; } while (diff) { magnitude ++; diff >>= 1; @@ -1253,6 +1253,7 @@ uint8_t config_state_base(EventPtr event, uint16_t arg, else { // TODO: blink out some sort of success pattern savefunc(); + save_config(); //set_state(retstate, retval); pop_state(); } diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index b942ec0..14c8dae 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -72,14 +72,14 @@ PROGMEM const uint8_t pwm4_levels[] = { PWM4_LEVELS }; 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 1 65 7135 1 0.8 150 - // ... mixed with this: - // ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 - PROGMEM const uint8_t 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,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 - #define HALFSPEED_LEVEL 14 - #define QUARTERSPEED_LEVEL 5 + // ../../bin/level_calc.py 1 65 7135 1 0.8 150 + // ... mixed with this: + // ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 + PROGMEM const uint8_t 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,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 + #define HALFSPEED_LEVEL 14 + #define QUARTERSPEED_LEVEL 5 #endif #elif PWM_CHANNELS == 3 #if RAMP_LENGTH == 50 -- cgit v1.2.3 From 5391d0364c37013845b83c8dec2862f317fce0fa Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 27 Jun 2018 03:40:34 -0600 Subject: Ramp down even faster on high modes. Actually save to eeprom after config modes. --- spaghetti-monster/anduril/rampingiosv3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c index e4fae2d..1afcbb0 100644 --- a/spaghetti-monster/anduril/rampingiosv3.c +++ b/spaghetti-monster/anduril/rampingiosv3.c @@ -33,7 +33,7 @@ #ifdef MAX_Nx7135 #define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 // throttle back faster when high #else -#define THERM_DOUBLE_SPEED_LEVEL (RAMP_LENGTH*4/5) // throttle back faster when high +#define THERM_DOUBLE_SPEED_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high #endif #ifdef USE_THERMAL_REGULATION #define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments @@ -541,6 +541,8 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { diff = actual_level - target_level; } uint8_t magnitude = 0; + // if we're on a really high mode, drop faster + if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { magnitude ++; } while (diff) { magnitude ++; diff >>= 1; @@ -809,6 +811,7 @@ uint8_t config_state_base(EventPtr event, uint16_t arg, else { // TODO: blink out some sort of success pattern savefunc(); + save_config(); //set_state(retstate, retval); pop_state(); } -- cgit v1.2.3 From 0e039cd22402ff44fe2cf3bea5dc276da49d7b36 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 29 Jun 2018 13:37:18 -0600 Subject: Oops, not sure how it even compiled with this typo. --- spaghetti-monster/anduril/anduril.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 2b958cc..f2d02ee 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -69,7 +69,7 @@ #if defined(FSM_BLF_GT_DRIVER) #include "cfg-blf-gt.h" -#elif FSM_BLF_Q8_DRIVER +#elif defined(FSM_BLF_Q8_DRIVER) #include "cfg-blf-q8.h" #elif defined(FSM_EMISAR_D4_DRIVER) -- cgit v1.2.3 From ddaa3eb594a8dc6656529306ccdf9f9a240a3588 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 30 Jun 2018 16:50:55 -0600 Subject: Just in case, overheating in muggle mode triggers an immediate drop to the floor. Because WTF. This basically can't happen unless someone is doing something very stupid. --- spaghetti-monster/anduril/anduril.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index f2d02ee..e79d568 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -1219,6 +1219,18 @@ uint8_t muggle_state(EventPtr event, uint16_t arg) { } return MISCHIEF_MANAGED; } + #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); + return MISCHIEF_MANAGED; + } + #endif // low voltage is handled specially in muggle mode else if(event == EV_voltage_low) { uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); -- cgit v1.2.3 From 3fd042cfc13c5cddc79b5a6b38e5c50e4d24c7d6 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 30 Jun 2018 19:25:05 -0600 Subject: Fixed thermal regulation bug, where it used the wrong target to determine adjustment speed. Added a THERM_HARD_TURBO_DROP option, but after fixing the previous bug I'm not sure it's really needed. Decreased default temperature ceiling to 45 C (was 50). --- spaghetti-monster/anduril/anduril.c | 27 ++++++++++++++++++++++++--- spaghetti-monster/anduril/cfg-emisar-d4.h | 4 ++++ spaghetti-monster/anduril/cfg-fw3a.h | 6 ++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index e79d568..0766361 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -28,7 +28,7 @@ #define USE_LVP // FIXME: won't build when this option is turned off #define USE_THERMAL_REGULATION -#define DEFAULT_THERM_CEIL 50 +#define DEFAULT_THERM_CEIL 45 #define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to #ifdef MAX_Nx7135 #define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 // throttle back faster when high @@ -590,6 +590,13 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { if ((arg & 1) && (actual_level < THERM_DOUBLE_SPEED_LEVEL)) { return MISCHIEF_MANAGED; // adjust slower when not a high mode } + #ifdef THERM_HARD_TURBO_DROP + else if ((! (actual_level < THERM_DOUBLE_SPEED_LEVEL)) + && (actual_level > gradual_target)) { + gradual_tick(); + } + else { + #endif // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] @@ -599,13 +606,15 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { uint8_t diff; static uint8_t ticks_since_adjust = 0; ticks_since_adjust ++; - if (target_level > actual_level) diff = target_level - actual_level; + if (gradual_target > actual_level) diff = gradual_target - actual_level; else { - diff = actual_level - target_level; + diff = actual_level - gradual_target; } uint8_t magnitude = 0; + #ifndef THERM_HARD_TURBO_DROP // if we're on a really high mode, drop faster if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { magnitude ++; } + #endif while (diff) { magnitude ++; diff >>= 1; @@ -617,6 +626,9 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { ticks_since_adjust = 0; } //if (!(arg % ticks_per_adjust)) gradual_tick(); + #ifdef THERM_HARD_TURBO_DROP + } + #endif #endif return MISCHIEF_MANAGED; } @@ -630,6 +642,15 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { delay_4ms(2); set_level(foo); #endif + #ifdef THERM_HARD_TURBO_DROP + if (actual_level > THERM_DOUBLE_SPEED_LEVEL) { + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(THERM_DOUBLE_SPEED_LEVEL); + #else + set_level(THERM_DOUBLE_SPEED_LEVEL); + #endif + } else + #endif if (actual_level > MIN_THERM_STEPDOWN) { int16_t stepdown = actual_level - arg; if (stepdown < MIN_THERM_STEPDOWN) stepdown = MIN_THERM_STEPDOWN; diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h index d17e2b0..a90d318 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -12,3 +12,7 @@ #define MAX_1x7135 65 #define HALFSPEED_LEVEL 14 #define QUARTERSPEED_LEVEL 5 + +// optional, makes initial turbo step-down faster so first peak isn't as hot +//#define THERM_HARD_TURBO_DROP + diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h index 3df426d..2790086 100644 --- a/spaghetti-monster/anduril/cfg-fw3a.h +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -16,3 +16,9 @@ #define HALFSPEED_LEVEL 14 #define QUARTERSPEED_LEVEL 5 +#ifdef THERM_DOUBLE_SPEED_LEVEL +#undef THERM_DOUBLE_SPEED_LEVEL +#endif +#define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 +// optional, makes initial turbo step-down faster so first peak isn't as hot +//#define THERM_HARD_TURBO_DROP -- cgit v1.2.3 From 667d789caf9b425f2fb1105d47b8aff8c2091ecb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 30 Jun 2018 19:42:05 -0600 Subject: Fixed bug: moon mode flickered a bit in momentary mode due to constant MCU clock speed adjustments. (also, reduced code size and made it harder for similar bugs to appear in the future) --- spaghetti-monster/anduril/anduril.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 0766361..ab6a0af 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -1670,16 +1670,6 @@ void loop() { #endif if (0) {} - #ifdef USE_IDLE_MODE - else if ( (state == steady_state) - || (state == off_state) - || (state == lockout_state) - || (state == goodnight_state) ) { - // doze until next clock tick - idle_mode(); - } - #endif - if (state == strobe_state) { uint8_t st = strobe_type; // bike flasher @@ -1777,4 +1767,12 @@ void loop() { set_level(0); nice_delay_ms(((beacon_seconds) * 1000) - 500); } + + #ifdef USE_IDLE_MODE + else { + // doze until next clock tick + idle_mode(); + } + #endif + } -- cgit v1.2.3 From b90e9ab2814c1623c0b0068e8230c003923e6d51 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 1 Jul 2018 14:31:45 -0600 Subject: Made it easier to define thermal parameters per driver type. Renamed THERM_DOUBLE_SPEED_LEVEL to THERM_FASTER_LEVEL, since it's not really 2X speed, it's 4X or more. This parameter defines approximately how bright the light can be without being considered risky or "turbo". Or the threshold between optimizing for rapid response vs optimizing for no oscillations. --- spaghetti-monster/anduril/anduril.c | 40 ++++++++++++++++++------------- spaghetti-monster/anduril/cfg-blf-gt.h | 3 +++ spaghetti-monster/anduril/cfg-blf-q8.h | 3 +++ spaghetti-monster/anduril/cfg-emisar-d4.h | 2 ++ spaghetti-monster/anduril/cfg-fw3a.h | 6 ++--- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index ab6a0af..cff5386 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -27,17 +27,9 @@ #define USE_LVP // FIXME: won't build when this option is turned off +// parameters for this defined below or per-driver #define USE_THERMAL_REGULATION -#define DEFAULT_THERM_CEIL 45 -#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to -#ifdef MAX_Nx7135 -#define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 // throttle back faster when high -#else -#define THERM_DOUBLE_SPEED_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high -#endif -#ifdef USE_THERMAL_REGULATION -#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments -#endif +#define DEFAULT_THERM_CEIL 45 // try not to get hotter than this // short blips while ramping #define BLINK_AT_CHANNEL_BOUNDARIES @@ -81,6 +73,22 @@ #endif +// thermal properties, if not defined per-driver +#ifndef MIN_THERM_STEPDOWN +#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#endif +#ifndef THERM_FASTER_LEVEL + #ifdef MAX_Nx7135 + #define THERM_FASTER_LEVEL MAX_Nx7135 // throttle back faster when high + #else + #define THERM_FASTER_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high + #endif +#endif +#ifdef USE_THERMAL_REGULATION +#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments +#endif + + /********* Configure SpaghettiMonster *********/ #define USE_DELAY_ZERO #define USE_RAMPING @@ -587,11 +595,11 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { #endif #ifdef USE_SET_LEVEL_GRADUALLY // make thermal adjustment speed scale with magnitude - if ((arg & 1) && (actual_level < THERM_DOUBLE_SPEED_LEVEL)) { + if ((arg & 1) && (actual_level < THERM_FASTER_LEVEL)) { return MISCHIEF_MANAGED; // adjust slower when not a high mode } #ifdef THERM_HARD_TURBO_DROP - else if ((! (actual_level < THERM_DOUBLE_SPEED_LEVEL)) + else if ((! (actual_level < THERM_FASTER_LEVEL)) && (actual_level > gradual_target)) { gradual_tick(); } @@ -613,7 +621,7 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { uint8_t magnitude = 0; #ifndef THERM_HARD_TURBO_DROP // if we're on a really high mode, drop faster - if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { magnitude ++; } + if (actual_level >= THERM_FASTER_LEVEL) { magnitude ++; } #endif while (diff) { magnitude ++; @@ -643,11 +651,11 @@ uint8_t steady_state(EventPtr event, uint16_t arg) { set_level(foo); #endif #ifdef THERM_HARD_TURBO_DROP - if (actual_level > THERM_DOUBLE_SPEED_LEVEL) { + if (actual_level > THERM_FASTER_LEVEL) { #ifdef USE_SET_LEVEL_GRADUALLY - set_level_gradually(THERM_DOUBLE_SPEED_LEVEL); + set_level_gradually(THERM_FASTER_LEVEL); #else - set_level(THERM_DOUBLE_SPEED_LEVEL); + set_level(THERM_FASTER_LEVEL); #endif } else #endif diff --git a/spaghetti-monster/anduril/cfg-blf-gt.h b/spaghetti-monster/anduril/cfg-blf-gt.h index a576d04..369d028 100644 --- a/spaghetti-monster/anduril/cfg-blf-gt.h +++ b/spaghetti-monster/anduril/cfg-blf-gt.h @@ -40,3 +40,6 @@ #define RAMP_DISCRETE_CEIL POWER_80PX #define RAMP_DISCRETE_STEPS 7 +// stop panicking at 80% power, this light has plenty of thermal mass +#define THERM_FASTER_LEVEL POWER_80PX // throttle back faster when high + diff --git a/spaghetti-monster/anduril/cfg-blf-q8.h b/spaghetti-monster/anduril/cfg-blf-q8.h index 7733721..269aae9 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8.h +++ b/spaghetti-monster/anduril/cfg-blf-q8.h @@ -22,3 +22,6 @@ #define HALFSPEED_LEVEL 14 #define QUARTERSPEED_LEVEL 5 +// stop panicking at ~75% power or ~3000 lm, this light has high thermal mass +#define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h index a90d318..4ac1f5e 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -16,3 +16,5 @@ // optional, makes initial turbo step-down faster so first peak isn't as hot //#define THERM_HARD_TURBO_DROP +// stop panicking at ~25% power or ~1000 lm, this light is a hotrod +#define THERM_FASTER_LEVEL (RAMP_SIZE*2/3) // throttle back faster when high diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h index 2790086..262ef13 100644 --- a/spaghetti-monster/anduril/cfg-fw3a.h +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -16,9 +16,7 @@ #define HALFSPEED_LEVEL 14 #define QUARTERSPEED_LEVEL 5 -#ifdef THERM_DOUBLE_SPEED_LEVEL -#undef THERM_DOUBLE_SPEED_LEVEL -#endif -#define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 +// 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 -- cgit v1.2.3 From ebe2cf08b60c5fbae19b1af3098cde3d134e4803 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 1 Jul 2018 19:48:49 -0600 Subject: Added hardware profiles and build targets for Emisar D1 and D1S. (same as D4, except with lower power-to-mass ratio) --- hwdef-Emisar_D1.h | 4 ++++ hwdef-Emisar_D1S.h | 4 ++++ spaghetti-monster/anduril/build-all.sh | 2 ++ spaghetti-monster/anduril/cfg-emisar-d1.h | 6 ++++++ spaghetti-monster/anduril/cfg-emisar-d1s.h | 6 ++++++ tk-attiny.h | 6 ++++++ 6 files changed, 28 insertions(+) create mode 100644 hwdef-Emisar_D1.h create mode 100644 hwdef-Emisar_D1S.h create mode 100644 spaghetti-monster/anduril/cfg-emisar-d1.h create mode 100644 spaghetti-monster/anduril/cfg-emisar-d1s.h diff --git a/hwdef-Emisar_D1.h b/hwdef-Emisar_D1.h new file mode 100644 index 0000000..6df8705 --- /dev/null +++ b/hwdef-Emisar_D1.h @@ -0,0 +1,4 @@ +/* Emisar D1 driver layout + */ +// D1 driver is exactly the same as a D4 +#include "hwdef-Emisar_D4.h" diff --git a/hwdef-Emisar_D1S.h b/hwdef-Emisar_D1S.h new file mode 100644 index 0000000..31792c7 --- /dev/null +++ b/hwdef-Emisar_D1S.h @@ -0,0 +1,4 @@ +/* Emisar D1S driver layout + */ +// D1S driver is exactly the same as a D4 +#include "hwdef-Emisar_D4.h" diff --git a/spaghetti-monster/anduril/build-all.sh b/spaghetti-monster/anduril/build-all.sh index 4100805..07f33b1 100755 --- a/spaghetti-monster/anduril/build-all.sh +++ b/spaghetti-monster/anduril/build-all.sh @@ -3,6 +3,8 @@ for TARGET in \ BLF_GT \ BLF_Q8 \ + EMISAR_D1 \ + EMISAR_D1S \ EMISAR_D4 \ FW3A \ ; do diff --git a/spaghetti-monster/anduril/cfg-emisar-d1.h b/spaghetti-monster/anduril/cfg-emisar-d1.h new file mode 100644 index 0000000..e9064ac --- /dev/null +++ b/spaghetti-monster/anduril/cfg-emisar-d1.h @@ -0,0 +1,6 @@ +// Emisar D1 config options for Anduril +#include "cfg-emisar-d4.h" + +// stop panicking at ~75% power or ~1000 lm (D1 has a decent power-to-thermal-mass ratio) +#undef THERM_FASTER_LEVEL +#define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high diff --git a/spaghetti-monster/anduril/cfg-emisar-d1s.h b/spaghetti-monster/anduril/cfg-emisar-d1s.h new file mode 100644 index 0000000..7e73fa7 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-emisar-d1s.h @@ -0,0 +1,6 @@ +// Emisar D1S config options for Anduril +#include "cfg-emisar-d4.h" + +// stop panicking at ~90% power or ~1200 lm (D1S has a good power-to-thermal-mass ratio) +#undef THERM_FASTER_LEVEL +#define THERM_FASTER_LEVEL 144 // throttle back faster when high diff --git a/tk-attiny.h b/tk-attiny.h index b3edb6d..a36fef0 100644 --- a/tk-attiny.h +++ b/tk-attiny.h @@ -84,6 +84,12 @@ #elif defined(FSM_EMISAR_D4_DRIVER) #include "hwdef-Emisar_D4.h" +#elif defined(FSM_EMISAR_D1_DRIVER) +#include "hwdef-Emisar_D1.h" + +#elif defined(FSM_EMISAR_D1S_DRIVER) +#include "hwdef-Emisar_D1S.h" + #elif defined(FSM_FW3A_DRIVER) #include "hwdef-FW3A.h" -- cgit v1.2.3 From 609dd2971a23634515998c9fb30d5eed7661d903 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 1 Jul 2018 20:31:32 -0600 Subject: Higher thermal elbow. This light has some decent thermal mass, and the curve here is pretty steep and low-biased. --- spaghetti-monster/anduril/cfg-emisar-d4s.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s.h b/spaghetti-monster/anduril/cfg-emisar-d4s.h index 52ecae0..7a8b342 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4s.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4s.h @@ -41,6 +41,6 @@ // thermal regulation parameters #undef MIN_THERM_STEPDOWN // this should be lower, because 3x7135 instead of 1x7135 #define MIN_THERM_STEPDOWN 60 // lowest value it'll step down to -#undef THERM_DOUBLE_SPEED_LEVEL // this should be lower too, because this light is a hot rod -#define THERM_DOUBLE_SPEED_LEVEL (RAMP_SIZE*2/3) // throttle back faster when high +#undef THERM_DOUBLE_SPEED_LEVEL +#define THERM_DOUBLE_SPEED_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high -- cgit v1.2.3 From aa52415286c095bc2c0e529d52eb383e4d2daa69 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 1 Jul 2018 20:38:16 -0600 Subject: Moved "next aux LED mode" to 7 clicks instead of 14 clicks. Shorter, easier, and has sort of an odd symmetry to "next lockout aux LED mode", which is 4 clicks, a pause, and then 3 clicks. --- spaghetti-monster/anduril/rampingiosv3.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c index 13be1b6..d15d8ed 100644 --- a/spaghetti-monster/anduril/rampingiosv3.c +++ b/spaghetti-monster/anduril/rampingiosv3.c @@ -77,11 +77,7 @@ #define USE_RAMPING #define RAMP_LENGTH 150 #define USE_BATTCHECK -#ifdef USE_INDICATOR_LED -#define MAX_CLICKS 14 -#else #define MAX_CLICKS 10 -#endif #define USE_IDLE_MODE // reduce power use while awake and no tasks are pending #define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency @@ -302,6 +298,13 @@ uint8_t off_state(EventPtr event, uint16_t arg) { set_state(lockout_state, 0); return MISCHIEF_MANAGED; } + #ifdef USE_INDICATOR_LED + // 7 clicks: next aux LED mode + else if (event == EV_7clicks) { + set_state(auxled_next_state, 0); + return MISCHIEF_MANAGED; + } + #endif // 8 clicks: beacon mode else if (event == EV_8clicks) { set_state(beacon_state, 0); @@ -312,13 +315,6 @@ uint8_t off_state(EventPtr event, uint16_t arg) { push_state(thermal_config_state, 0); return MISCHIEF_MANAGED; } - #ifdef USE_INDICATOR_LED - // 14 clicks: next aux LED mode - else if (event == EV_14clicks) { - set_state(auxled_next_state, 0); - return MISCHIEF_MANAGED; - } - #endif return EVENT_NOT_HANDLED; } -- cgit v1.2.3 From df0601f6ad03fb1ebbbe06ff99d1589ef0aeda25 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 3 Jul 2018 21:26:09 -0600 Subject: Added a momentary + Werner-style UI for FSM, because why not. Based on Anduril, but with most of the features removed. --- spaghetti-monster/werner/cfg-blf-gt.h | 1 + spaghetti-monster/werner/cfg-blf-q8.h | 1 + spaghetti-monster/werner/cfg-emisar-d1.h | 1 + spaghetti-monster/werner/cfg-emisar-d1s.h | 1 + spaghetti-monster/werner/cfg-emisar-d4.h | 1 + spaghetti-monster/werner/cfg-fw3a.h | 1 + spaghetti-monster/werner/werner.c | 724 ++++++++++++++++++++++++++++++ 7 files changed, 730 insertions(+) create mode 120000 spaghetti-monster/werner/cfg-blf-gt.h create mode 120000 spaghetti-monster/werner/cfg-blf-q8.h create mode 120000 spaghetti-monster/werner/cfg-emisar-d1.h create mode 120000 spaghetti-monster/werner/cfg-emisar-d1s.h create mode 120000 spaghetti-monster/werner/cfg-emisar-d4.h create mode 120000 spaghetti-monster/werner/cfg-fw3a.h create mode 100644 spaghetti-monster/werner/werner.c diff --git a/spaghetti-monster/werner/cfg-blf-gt.h b/spaghetti-monster/werner/cfg-blf-gt.h new file mode 120000 index 0000000..5e10228 --- /dev/null +++ b/spaghetti-monster/werner/cfg-blf-gt.h @@ -0,0 +1 @@ +../anduril/cfg-blf-gt.h \ No newline at end of file diff --git a/spaghetti-monster/werner/cfg-blf-q8.h b/spaghetti-monster/werner/cfg-blf-q8.h new file mode 120000 index 0000000..fe84054 --- /dev/null +++ b/spaghetti-monster/werner/cfg-blf-q8.h @@ -0,0 +1 @@ +../anduril/cfg-blf-q8.h \ No newline at end of file diff --git a/spaghetti-monster/werner/cfg-emisar-d1.h b/spaghetti-monster/werner/cfg-emisar-d1.h new file mode 120000 index 0000000..f8b4c9b --- /dev/null +++ b/spaghetti-monster/werner/cfg-emisar-d1.h @@ -0,0 +1 @@ +../anduril/cfg-emisar-d1.h \ No newline at end of file diff --git a/spaghetti-monster/werner/cfg-emisar-d1s.h b/spaghetti-monster/werner/cfg-emisar-d1s.h new file mode 120000 index 0000000..b6cfba6 --- /dev/null +++ b/spaghetti-monster/werner/cfg-emisar-d1s.h @@ -0,0 +1 @@ +../anduril/cfg-emisar-d1s.h \ No newline at end of file diff --git a/spaghetti-monster/werner/cfg-emisar-d4.h b/spaghetti-monster/werner/cfg-emisar-d4.h new file mode 120000 index 0000000..fb74f2c --- /dev/null +++ b/spaghetti-monster/werner/cfg-emisar-d4.h @@ -0,0 +1 @@ +../anduril/cfg-emisar-d4.h \ No newline at end of file diff --git a/spaghetti-monster/werner/cfg-fw3a.h b/spaghetti-monster/werner/cfg-fw3a.h new file mode 120000 index 0000000..5bc8b21 --- /dev/null +++ b/spaghetti-monster/werner/cfg-fw3a.h @@ -0,0 +1 @@ +../anduril/cfg-fw3a.h \ No newline at end of file diff --git a/spaghetti-monster/werner/werner.c b/spaghetti-monster/werner/werner.c new file mode 100644 index 0000000..3c55d98 --- /dev/null +++ b/spaghetti-monster/werner/werner.c @@ -0,0 +1,724 @@ +/* + * Werner: Werner-style dual-switch UI for SpaghettiMonster. + * Side click to go up, side hold to go down, tail click for on/off. + * + * Copyright (C) 2018 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 . + */ + +/********* User-configurable options *********/ +// Physical driver type (uncomment one of the following or define it at the gcc command line) +//#define FSM_EMISAR_D4_DRIVER +//#define FSM_BLF_Q8_DRIVER +//#define FSM_FW3A_DRIVER +//#define FSM_BLF_GT_DRIVER + +#define USE_LVP // FIXME: won't build when this option is turned off + +// parameters for this defined below or per-driver +#define USE_THERMAL_REGULATION +#define DEFAULT_THERM_CEIL 45 // try not to get hotter than this + +// battery readout style (pick one) +#define BATTCHECK_VpT +//#define BATTCHECK_8bars // FIXME: breaks build +//#define BATTCHECK_4bars // FIXME: breaks build + +/***** specific settings for known driver types *****/ +#if defined(FSM_BLF_GT_DRIVER) +#include "cfg-blf-gt.h" + +#elif defined(FSM_BLF_Q8_DRIVER) +#include "cfg-blf-q8.h" + +#elif defined(FSM_EMISAR_D4_DRIVER) +#include "cfg-emisar-d4.h" + +#elif defined(FSM_FW3A_DRIVER) +#include "cfg-fw3a.h" + +#endif + + +// thermal properties, if not defined per-driver +#ifndef MIN_THERM_STEPDOWN +#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#endif +#ifndef THERM_FASTER_LEVEL + #ifdef MAX_Nx7135 + #define THERM_FASTER_LEVEL MAX_Nx7135 // throttle back faster when high + #else + #define THERM_FASTER_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high + #endif +#endif +#ifdef USE_THERMAL_REGULATION +#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments +#endif + + +/********* Configure SpaghettiMonster *********/ +#define USE_DELAY_ZERO +#define USE_RAMPING +#define RAMP_LENGTH 150 // default, if not overridden in a driver cfg file +#define USE_BATTCHECK +#define MAX_CLICKS 4 +#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending +#define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency + +// auto-detect how many eeprom bytes +#define USE_EEPROM +#ifdef USE_THERMAL_REGULATION +#define EEPROM_BYTES 5 +#else +#define EEPROM_BYTES 3 +#endif +// for mode memory on tail switch +#define USE_EEPROM_WL +#define EEPROM_WL_BYTES 1 + +#include "spaghetti-monster.h" + + +// FSM states +uint8_t off_state(EventPtr event, uint16_t arg); +// simple numeric entry config menu +uint8_t config_state_base(EventPtr 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); +#ifdef USE_BATTCHECK +uint8_t battcheck_state(EventPtr 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); +#endif + +// general helper function for config modes +uint8_t number_entry_state(EventPtr event, uint16_t arg); +// return value from number_entry_state() +volatile uint8_t number_entry_value; + +void blink_confirm(uint8_t num); + +// remember stuff even after battery was changed +void load_config(); +void save_config(); +void save_config_wl(); + +// default ramp options if not overridden earlier per-driver +#ifndef RAMP_DISCRETE_FLOOR + #define RAMP_DISCRETE_FLOOR 1 +#endif +#ifndef RAMP_DISCRETE_CEIL + #define RAMP_DISCRETE_CEIL RAMP_SIZE +#endif +#ifndef RAMP_DISCRETE_STEPS + #define RAMP_DISCRETE_STEPS 7 +#endif + +// brightness control +uint8_t memorized_level = MAX_1x7135; +// smooth vs discrete ramping +volatile uint8_t ramp_discrete_floor = RAMP_DISCRETE_FLOOR; +volatile uint8_t ramp_discrete_ceil = RAMP_DISCRETE_CEIL; +volatile uint8_t ramp_discrete_steps = RAMP_DISCRETE_STEPS; +uint8_t ramp_discrete_step_size; // don't set this + +// calculate the nearest ramp level which would be valid at the moment +// (is a no-op for smooth ramp, but limits discrete ramp to only the +// correct levels for the user's config) +uint8_t nearest_level(int16_t target); + +#ifdef USE_THERMAL_REGULATION +// brightness before thermal step-down +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) || (event == EV_reenter_state)) { + // let the user know the power is connected + blink_confirm(1); + // but otherwise stay off + set_level(0); + // sleep while off (lower power use) + go_to_standby = 1; + return MISCHIEF_MANAGED; + } + // go back to sleep eventually if we got bumped but didn't leave "off" state + else if (event == EV_tick) { + if (arg > TICKS_PER_SECOND*2) { + go_to_standby = 1; + } + return MISCHIEF_MANAGED; + } + // hold (initially): go to lowest level, but allow abort for regular click + else if (event == EV_click1_press) { + set_level(nearest_level(1)); + return MISCHIEF_MANAGED; + } + // 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 MISCHIEF_MANAGED; + } + // hold, release quickly: go to lowest level + else if (event == EV_click1_hold_release) { + set_state(steady_state, 1); + return MISCHIEF_MANAGED; + } + // 1 click (before timeout): go to memorized level, but allow abort for double click + else if (event == EV_click1_release) { + set_level(nearest_level(memorized_level)); + return MISCHIEF_MANAGED; + } + // 1 click: regular mode + else if (event == EV_1click) { + set_state(steady_state, memorized_level); + return MISCHIEF_MANAGED; + } + // 2 clicks (initial press): off, to prep for later events + else if (event == EV_click2_press) { + set_level(0); + return MISCHIEF_MANAGED; + } + // click, hold: go to highest level (for ramping down) + else if (event == EV_click2_hold) { + set_state(steady_state, MAX_LEVEL); + return MISCHIEF_MANAGED; + } + // 2 clicks: highest mode + else if (event == EV_2clicks) { + set_state(steady_state, nearest_level(MAX_LEVEL)); + return MISCHIEF_MANAGED; + } + #ifdef USE_BATTCHECK + // 3 clicks: battcheck mode / blinky mode group + else if (event == EV_3clicks) { + set_state(battcheck_state, 0); + return MISCHIEF_MANAGED; + } + #endif + // 4 clicks: configure ramp + else if (event == EV_4clicks) { + push_state(ramp_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +uint8_t steady_state(EventPtr event, uint16_t arg) { + uint8_t mode_min = ramp_discrete_floor; + uint8_t mode_max = ramp_discrete_ceil; + uint8_t ramp_step_size = ramp_discrete_step_size; + + // turn LED on when we first enter the mode + if ((event == EV_enter_state) || (event == EV_reenter_state)) { + // if we just got back from config mode, go back to memorized level + if (event == EV_reenter_state) { + arg = memorized_level; + } + // remember this level, unless it's moon or turbo + if ((arg > mode_min) && (arg < mode_max)) + memorized_level = arg; + // use the requested level even if not memorized + #ifdef USE_THERMAL_REGULATION + target_level = arg; + #endif + set_level(nearest_level(arg)); + return MISCHIEF_MANAGED; + } + // click: brighter + else if (event == EV_click1_release) { + memorized_level = nearest_level((int16_t)actual_level + ramp_step_size); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + set_level(memorized_level); + // make sure next click will respond quickly + empty_event_sequence(); + // remember mode for later + save_config_wl(); + return MISCHIEF_MANAGED; + } + // hold: dimmer + else if (event == EV_click1_hold) { + // ramp slower in discrete mode + if (arg % HOLD_TIMEOUT != 0) { + return MISCHIEF_MANAGED; + } + memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + // reverse ramp direction on hold release + else if (event == EV_click1_hold_release) { + save_config_wl(); + return MISCHIEF_MANAGED; + } + #if defined(USE_SET_LEVEL_GRADUALLY) + // gradual thermal regulation + else if (event == EV_tick) { + #ifdef USE_SET_LEVEL_GRADUALLY + // make thermal adjustment speed scale with magnitude + if ((arg & 1) && (actual_level < THERM_FASTER_LEVEL)) { + return MISCHIEF_MANAGED; // adjust slower when not a high mode + } + #ifdef THERM_HARD_TURBO_DROP + else if ((! (actual_level < THERM_FASTER_LEVEL)) + && (actual_level > gradual_target)) { + gradual_tick(); + } + else { + #endif + // [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)] + uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2}; + uint8_t diff; + static uint8_t ticks_since_adjust = 0; + ticks_since_adjust ++; + if (gradual_target > actual_level) diff = gradual_target - actual_level; + else { + diff = actual_level - gradual_target; + } + uint8_t magnitude = 0; + #ifndef THERM_HARD_TURBO_DROP + // if we're on a really high mode, drop faster + if (actual_level >= THERM_FASTER_LEVEL) { magnitude ++; } + #endif + while (diff) { + magnitude ++; + diff >>= 1; + } + uint8_t ticks_per_adjust = intervals[magnitude]; + if (ticks_since_adjust > ticks_per_adjust) + { + gradual_tick(); + ticks_since_adjust = 0; + } + //if (!(arg % ticks_per_adjust)) gradual_tick(); + #ifdef THERM_HARD_TURBO_DROP + } + #endif + #endif + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_THERMAL_REGULATION + // overheating: drop by an amount proportional to how far we are above the ceiling + else if (event == EV_temperature_high) { + #ifdef THERM_HARD_TURBO_DROP + if (actual_level > THERM_FASTER_LEVEL) { + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(THERM_FASTER_LEVEL); + #else + set_level(THERM_FASTER_LEVEL); + #endif + } else + #endif + if (actual_level > MIN_THERM_STEPDOWN) { + int16_t stepdown = actual_level - arg; + if (stepdown < MIN_THERM_STEPDOWN) stepdown = MIN_THERM_STEPDOWN; + else if (stepdown > MAX_LEVEL) stepdown = MAX_LEVEL; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepdown); + #else + set_level(stepdown); + #endif + } + return MISCHIEF_MANAGED; + } + // underheating: increase slowly if we're lower than the target + // (proportional to how low we are) + else if (event == EV_temperature_low) { + if (actual_level < target_level) { + //int16_t stepup = actual_level + (arg>>1); + int16_t stepup = actual_level + arg; + if (stepup > target_level) stepup = target_level; + else if (stepup < MIN_THERM_STEPDOWN) stepup = MIN_THERM_STEPDOWN; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepup); + #else + set_level(stepup); + #endif + } + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +#ifdef USE_BATTCHECK +uint8_t battcheck_state(EventPtr event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: tempcheck mode + else if (event == EV_2clicks) { + blink_confirm(2); + set_state(tempcheck_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} +#endif + +#ifdef USE_THERMAL_REGULATION +uint8_t tempcheck_state(EventPtr event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: battcheck mode + else if (event == EV_2clicks) { + blink_confirm(1); + set_state(battcheck_state, 0); + return MISCHIEF_MANAGED; + } + // 4 clicks: thermal config mode + else if (event == EV_4clicks) { + push_state(thermal_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} +#endif + + +// 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 num_config_steps, + void (*savefunc)()) { + static uint8_t config_step; + if (event == EV_enter_state) { + config_step = 0; + set_level(0); + return MISCHIEF_MANAGED; + } + // advance forward through config steps + else if (event == EV_tick) { + if (config_step < num_config_steps) { + push_state(number_entry_state, config_step + 1); + } + else { + // TODO: blink out some sort of success pattern + savefunc(); + save_config(); + //set_state(retstate, retval); + pop_state(); + } + return MISCHIEF_MANAGED; + } + // an option was set (return from number_entry_state) + else if (event == EV_reenter_state) { + config_state_values[config_step] = number_entry_value; + config_step ++; + return MISCHIEF_MANAGED; + } + //return EVENT_NOT_HANDLED; + // eat all other events; don't pass any through to parent + return EVENT_HANDLED; +} + +void ramp_config_save() { + // parse values + uint8_t val; + + val = config_state_values[0]; + if (val) { ramp_discrete_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_discrete_ceil = MAX_LEVEL + 1 - val; } + + val = config_state_values[2]; + if (val) ramp_discrete_steps = val; +} + +uint8_t ramp_config_state(EventPtr event, uint16_t arg) { + uint8_t num_config_steps; + num_config_steps = 3; + return config_state_base(event, arg, + num_config_steps, ramp_config_save); +} + + +#ifdef USE_THERMAL_REGULATION +void thermal_config_save() { + // parse values + uint8_t val; + + // calibrate room temperature + val = config_state_values[0]; + if (val) { + int8_t rawtemp = (temperature >> 1) - therm_cal_offset; + therm_cal_offset = val - rawtemp; + } + + val = config_state_values[1]; + if (val) { + // set maximum heat limit + therm_ceil = 30 + val; + } + if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; +} + +uint8_t thermal_config_state(EventPtr event, uint16_t arg) { + return config_state_base(event, arg, + 2, thermal_config_save); +} +#endif + + +uint8_t number_entry_state(EventPtr event, uint16_t arg) { + static uint8_t value; + static uint8_t blinks_left; + static uint8_t entry_step; + static uint16_t wait_ticks; + if (event == EV_enter_state) { + value = 0; + blinks_left = arg; + entry_step = 0; + wait_ticks = 0; + return MISCHIEF_MANAGED; + } + // advance through the process: + // 0: wait a moment + // 1: blink out the 'arg' value + // 2: wait a moment + // 3: "buzz" while counting clicks + // 4: save and exit + else if (event == EV_tick) { + // wait a moment + if ((entry_step == 0) || (entry_step == 2)) { + if (wait_ticks < TICKS_PER_SECOND/2) + wait_ticks ++; + else { + entry_step ++; + wait_ticks = 0; + } + } + // blink out the option number + else if (entry_step == 1) { + if (blinks_left) { + if ((wait_ticks & 31) == 10) { + set_level(RAMP_SIZE/4); + } + else if ((wait_ticks & 31) == 20) { + set_level(0); + } + else if ((wait_ticks & 31) == 31) { + blinks_left --; + } + wait_ticks ++; + } + else { + entry_step ++; + wait_ticks = 0; + } + } + else if (entry_step == 3) { // buzz while waiting for a number to be entered + wait_ticks ++; + // buzz for N seconds after last event + if ((wait_ticks & 3) == 0) { + set_level(RAMP_SIZE/6); + } + else if ((wait_ticks & 3) == 2) { + set_level(RAMP_SIZE/8); + } + // time out after 3 seconds + if (wait_ticks > TICKS_PER_SECOND*3) { + //number_entry_value = value; + set_level(0); + entry_step ++; + } + } + else if (entry_step == 4) { + number_entry_value = value; + pop_state(); + } + return MISCHIEF_MANAGED; + } + // count clicks + else if (event == EV_click1_release) { + empty_event_sequence(); + if (entry_step == 3) { // only count during the "buzz" + value ++; + wait_ticks = 0; + // flash briefly + set_level(RAMP_SIZE/2); + delay_4ms(8/2); + set_level(0); + } + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +// find the ramp level closest to the target, +// using only the levels which are allowed in the current state +uint8_t nearest_level(int16_t target) { + // bounds check + // using int16_t here saves us a bunch of logic elsewhere, + // by allowing us to correct for numbers < 0 or > 255 in one central place + uint8_t mode_min = ramp_discrete_floor; + uint8_t mode_max = ramp_discrete_ceil; + if (target < mode_min) return mode_min; + if (target > mode_max) return mode_max; + + uint8_t ramp_range = ramp_discrete_ceil - ramp_discrete_floor; + ramp_discrete_step_size = ramp_range / (ramp_discrete_steps-1); + uint8_t this_level = ramp_discrete_floor; + + for(uint8_t i=0; i>1)) + return this_level; + } + return this_level; +} + + +void blink_confirm(uint8_t num) { + for (; num>0; num--) { + set_level(MAX_LEVEL/4); + delay_4ms(10/4); + set_level(0); + delay_4ms(100/4); + } +} + + +void load_config() { + if (load_eeprom()) { + ramp_discrete_floor = eeprom[0]; + ramp_discrete_ceil = eeprom[1]; + ramp_discrete_steps = eeprom[2]; + #ifdef USE_THERMAL_REGULATION + therm_ceil = eeprom[3]; + therm_cal_offset = eeprom[4]; + #endif + } + if (load_eeprom_wl()) { + memorized_level = eeprom_wl[0]; + } +} + + +void save_config() { + eeprom[0] = ramp_discrete_floor; + eeprom[1] = ramp_discrete_ceil; + eeprom[2] = ramp_discrete_steps; + #ifdef USE_THERMAL_REGULATION + eeprom[3] = therm_ceil; + eeprom[4] = therm_cal_offset; + #endif + + save_eeprom(); +} + + +void save_config_wl() { + eeprom_wl[0] = memorized_level; + save_eeprom_wl(); +} + + +void low_voltage() { + StatePtr state = current_state; + + // in normal mode, step down or turn off + if (state == steady_state) { + if (actual_level > 1) { + uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); + set_level(lvl); + #ifdef USE_THERMAL_REGULATION + target_level = lvl; + #endif + } + else { + set_state(off_state, 0); + } + } + // all other modes, just turn off when voltage is low + else { + set_state(off_state, 0); + } +} + + +void setup() { + // dual switch: e-switch + power clicky + // power clicky acts as a momentary mode + load_config(); + + if (button_is_pressed()) + // hold button to go to moon + push_state(off_state, 0); + else + // otherwise use memory + push_state(steady_state, memorized_level); +} + + +void loop() { + + StatePtr state = current_state; + + #ifdef USE_DYNAMIC_UNDERCLOCKING + auto_clock_speed(); + #endif + if (0) {} + + #ifdef USE_BATTCHECK + else if (state == battcheck_state) { + battcheck(); + } + #endif + #ifdef USE_THERMAL_REGULATION + // TODO: blink out therm_ceil during thermal_config_state + else if (state == tempcheck_state) { + blink_num(temperature>>1); + nice_delay_ms(1000); + } + #endif + + #ifdef USE_IDLE_MODE + else { + // doze until next clock tick + idle_mode(); + } + #endif + +} -- cgit v1.2.3 From cd78d561e114f932abe330dbddda179de6941bc9 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 14 Jul 2018 20:07:53 -0600 Subject: Added special 219c build. Fixed bug with forgetting memorized brightness after changing aux LED mode. (it was actually rebooting after the aux LED change, because it got into an infinite loop of changing state in its leave_state event, which caused a stack overflow... ... so don't change state in a catch-all "else" event handling clause, oops) --- spaghetti-monster/anduril/cfg-emisar-d4s-219c.h | 8 ++++++++ spaghetti-monster/anduril/cfg-emisar-d4s.h | 1 + spaghetti-monster/anduril/rampingiosv3.c | 7 ++++++- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 spaghetti-monster/anduril/cfg-emisar-d4s-219c.h diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h b/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h new file mode 100644 index 0000000..8099498 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h @@ -0,0 +1,8 @@ +// Emisar D4S-219c config options for Anduril +// same as D4S but with FET modes limited to 80% power +// to avoid destroying the LEDs +#include "cfg-emisar-d4s.h" + +#undef PWM2_LEVELS +#define PWM2_LEVELS PWM2_LEVELS_219c + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s.h b/spaghetti-monster/anduril/cfg-emisar-d4s.h index 568ff67..ddb56ee 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4s.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4s.h @@ -30,6 +30,7 @@ // (because it made the ramp look better than accurate values) #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,0 #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,1,3,4,5,7,8,10,11,13,14,16,18,19,21,23,25,27,29,31,34,36,38,41,43,46,48,51,54,57,60,63,66,69,72,76,79,83,87,91,95,99,103,107,112,116,121,126,131,136,141,146,152,158,163,169,175,182,188,195,202,209,216,223,231,239,247,255 +#define PWM2_LEVELS_219c 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,3,4,5,6,8,8,10,11,12,14,15,16,18,20,21,23,24,27,28,30,32,34,36,38,40,43,45,48,50,52,55,57,60,63,66,69,72,76,79,82,85,89,92,96,100,104,108,112,116,121,126,130,135,140,145,150,156,161,167,172,178,184,191,197,204 #define MAX_1x7135 83 #define HALFSPEED_LEVEL 13 #define QUARTERSPEED_LEVEL 6 diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c index d15d8ed..e593a84 100644 --- a/spaghetti-monster/anduril/rampingiosv3.c +++ b/spaghetti-monster/anduril/rampingiosv3.c @@ -21,6 +21,7 @@ // Physical driver type (uncomment one of the following or define it at the gcc command line) //#define FSM_EMISAR_D4_DRIVER #define FSM_EMISAR_D4S_DRIVER +//#define FSM_EMISAR_D4S_219c_DRIVER //#define FSM_BLF_Q8_DRIVER //#define FSM_FW3A_DRIVER //#define FSM_BLF_GT_DRIVER @@ -64,6 +65,9 @@ #elif defined(FSM_EMISAR_D4_DRIVER) #include "cfg-emisar-d4.h" +#elif defined(FSM_EMISAR_D4S_219c_DRIVER) +#include "cfg-emisar-d4s-219c.h" + #elif defined(FSM_EMISAR_D4S_DRIVER) #include "cfg-emisar-d4s.h" @@ -301,6 +305,7 @@ uint8_t off_state(EventPtr event, uint16_t arg) { #ifdef USE_INDICATOR_LED // 7 clicks: next aux LED mode else if (event == EV_7clicks) { + blink_confirm(1); set_state(auxled_next_state, 0); return MISCHIEF_MANAGED; } @@ -747,7 +752,7 @@ uint8_t auxled_next_state(EventPtr event, uint16_t arg) { save_config(); return MISCHIEF_MANAGED; } - else { + else if (event == EV_tick) { set_state(off_state, 0); return MISCHIEF_MANAGED; } -- cgit v1.2.3 From 9f1ed182a5ac266ef20560d252eeeee264cc4749 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 6 Aug 2018 20:56:51 -0600 Subject: Added UI diagram for RampingIOS V3. --- spaghetti-monster/anduril/rampingiosv3-ui.png | Bin 0 -> 240749 bytes spaghetti-monster/anduril/rampingiosv3.svg | 4113 +++++++++++++++++++++++++ 2 files changed, 4113 insertions(+) create mode 100644 spaghetti-monster/anduril/rampingiosv3-ui.png create mode 100644 spaghetti-monster/anduril/rampingiosv3.svg diff --git a/spaghetti-monster/anduril/rampingiosv3-ui.png b/spaghetti-monster/anduril/rampingiosv3-ui.png new file mode 100644 index 0000000..d02dbf6 Binary files /dev/null and b/spaghetti-monster/anduril/rampingiosv3-ui.png differ diff --git a/spaghetti-monster/anduril/rampingiosv3.svg b/spaghetti-monster/anduril/rampingiosv3.svg new file mode 100644 index 0000000..bc9e6b3 --- /dev/null +++ b/spaghetti-monster/anduril/rampingiosv3.svg @@ -0,0 +1,4113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + Ramps: + + + ThermalCfg + + + + + BeaconCfg + + + + + + Ramp + Ceil + Floor + + + Turbo + + + + + Mem + Regulated Hybrid -------------- Direct Drive + + + + + + + + + + + + Ramp + + Cfg + + + + + + Actions + 1 Fast Click + Hold + 3 Fast Clicks + Other Action + + + + 2 Fast Clicks + Click, Hold + RampingIOS V3 + + + + 7 Clicks + + + + OFF + + + + OFF + + + + + + + 4 Clicks + 4 Clicks + Click, Click, Hold + + 6 Clicks + + + + Smooth + + + + Ramp Cfg + + 4 Clicks + + + + 4 Clicks + + + + 1. Floor (click N times for level N)2. Ceiling (click N times for 1 + Turbo - N)3. Number of steps (stepped ramp only) + 1. Current temperature (click N times for N deg C)2. Temperature limit (click N times for 30 C + N) + 1. Beacon speed (click N times for N seconds per flash) + Thermal Cfg + Beacon Cfg + + 4 Clicks + + + + + + Stepped + + + + Tactical + + + BattCheck + + Lockout + + TempCheck + Beacon + + ThermalCfg + + + OFF + + + + + + + + + + + (momentary) + 3 Clicks + 4 Clicks + 6 Clicks + 8 Clicks + 10 Clicks + + + Aux LED + mode + next + + + + + + + + lockout LED + mode + next + 4 Clicks + 4 Clicks + 4 Clicks + + + + + -- cgit v1.2.3 From d0222f7aec74cbd77530a0d661cd13cf4e6bd0db Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 6 Aug 2018 21:15:30 -0600 Subject: Moved RampingIOS V3 code into its own directory. --- spaghetti-monster/anduril/cfg-emisar-d4s-219c.h | 1 + spaghetti-monster/anduril/rampingiosv3-ui.png | Bin 240749 -> 0 bytes spaghetti-monster/anduril/rampingiosv3.c | 1160 ------ spaghetti-monster/anduril/rampingiosv3.svg | 4113 -------------------- spaghetti-monster/rampingios/build-all.sh | 16 + spaghetti-monster/rampingios/cfg-blf-gt.h | 1 + spaghetti-monster/rampingios/cfg-blf-q8.h | 1 + spaghetti-monster/rampingios/cfg-emisar-d1.h | 1 + spaghetti-monster/rampingios/cfg-emisar-d1s.h | 1 + spaghetti-monster/rampingios/cfg-emisar-d4.h | 1 + spaghetti-monster/rampingios/cfg-emisar-d4s-219c.h | 1 + spaghetti-monster/rampingios/cfg-emisar-d4s.h | 1 + spaghetti-monster/rampingios/cfg-fw3a.h | 1 + spaghetti-monster/rampingios/rampingiosv3-ui.png | Bin 0 -> 240749 bytes spaghetti-monster/rampingios/rampingiosv3.c | 1166 ++++++ spaghetti-monster/rampingios/rampingiosv3.svg | 4113 ++++++++++++++++++++ 16 files changed, 5304 insertions(+), 5273 deletions(-) delete mode 100644 spaghetti-monster/anduril/rampingiosv3-ui.png delete mode 100644 spaghetti-monster/anduril/rampingiosv3.c delete mode 100644 spaghetti-monster/anduril/rampingiosv3.svg create mode 100755 spaghetti-monster/rampingios/build-all.sh create mode 120000 spaghetti-monster/rampingios/cfg-blf-gt.h create mode 120000 spaghetti-monster/rampingios/cfg-blf-q8.h create mode 120000 spaghetti-monster/rampingios/cfg-emisar-d1.h create mode 120000 spaghetti-monster/rampingios/cfg-emisar-d1s.h create mode 120000 spaghetti-monster/rampingios/cfg-emisar-d4.h create mode 120000 spaghetti-monster/rampingios/cfg-emisar-d4s-219c.h create mode 120000 spaghetti-monster/rampingios/cfg-emisar-d4s.h create mode 120000 spaghetti-monster/rampingios/cfg-fw3a.h create mode 100644 spaghetti-monster/rampingios/rampingiosv3-ui.png create mode 100644 spaghetti-monster/rampingios/rampingiosv3.c create mode 100644 spaghetti-monster/rampingios/rampingiosv3.svg diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h b/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h index 8099498..a98f123 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h @@ -1,6 +1,7 @@ // Emisar D4S-219c config options for Anduril // same as D4S but with FET modes limited to 80% power // to avoid destroying the LEDs +#define FSM_EMISAR_D4S_DRIVER #include "cfg-emisar-d4s.h" #undef PWM2_LEVELS diff --git a/spaghetti-monster/anduril/rampingiosv3-ui.png b/spaghetti-monster/anduril/rampingiosv3-ui.png deleted file mode 100644 index d02dbf6..0000000 Binary files a/spaghetti-monster/anduril/rampingiosv3-ui.png and /dev/null differ diff --git a/spaghetti-monster/anduril/rampingiosv3.c b/spaghetti-monster/anduril/rampingiosv3.c deleted file mode 100644 index e593a84..0000000 --- a/spaghetti-monster/anduril/rampingiosv3.c +++ /dev/null @@ -1,1160 +0,0 @@ -/* - * RampingIOS V3: FSM-based version of RampingIOS V2 UI, with upgrades. - * - * Copyright (C) 2018 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 . - */ - -/********* User-configurable options *********/ -// Physical driver type (uncomment one of the following or define it at the gcc command line) -//#define FSM_EMISAR_D4_DRIVER -#define FSM_EMISAR_D4S_DRIVER -//#define FSM_EMISAR_D4S_219c_DRIVER -//#define FSM_BLF_Q8_DRIVER -//#define FSM_FW3A_DRIVER -//#define FSM_BLF_GT_DRIVER - -#define USE_LVP // FIXME: won't build when this option is turned off - -#define USE_THERMAL_REGULATION -#define DEFAULT_THERM_CEIL 45 -#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to -#ifdef MAX_Nx7135 -#define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 // throttle back faster when high -#else -#define THERM_DOUBLE_SPEED_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high -#endif -#ifdef USE_THERMAL_REGULATION -#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments -#endif - -// short blips while ramping -#define BLINK_AT_CHANNEL_BOUNDARIES -//#define BLINK_AT_RAMP_FLOOR -#define BLINK_AT_RAMP_CEILING -//#define BLINK_AT_STEPS // whenever a discrete ramp mode is passed in smooth mode - -// ramp down via regular button hold if a ramp-up ended <1s ago -// ("hold, release, hold" ramps down instead of up) -#define USE_REVERSING - -// battery readout style (pick one) -#define BATTCHECK_VpT -//#define BATTCHECK_8bars // FIXME: breaks build -//#define BATTCHECK_4bars // FIXME: breaks build - -/***** specific settings for known driver types *****/ -#if defined(FSM_BLF_GT_DRIVER) -#include "cfg-blf-gt.h" - -#elif defined(FSM_BLF_Q8_DRIVER) -#include "cfg-blf-q8.h" - -#elif defined(FSM_EMISAR_D4_DRIVER) -#include "cfg-emisar-d4.h" - -#elif defined(FSM_EMISAR_D4S_219c_DRIVER) -#include "cfg-emisar-d4s-219c.h" - -#elif defined(FSM_EMISAR_D4S_DRIVER) -#include "cfg-emisar-d4s.h" - -#elif defined(FSM_FW3A_DRIVER) -#include "cfg-fw3a.h" - -#endif - -/********* Configure SpaghettiMonster *********/ -#define USE_DELAY_ZERO -#define USE_RAMPING -#define RAMP_LENGTH 150 -#define USE_BATTCHECK -#define MAX_CLICKS 10 -#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending -#define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency - -// try to auto-detect how many eeprom bytes -#define USE_EEPROM -#define EEPROM_BYTES_BASE 7 - -#ifdef USE_INDICATOR_LED -#define EEPROM_INDICATOR_BYTES 1 -#else -#define EEPROM_INDICATOR_BYTES 0 -#endif - -#ifdef USE_THERMAL_REGULATION -#define EEPROM_THERMAL_BYTES 2 -#else -#define EEPROM_THERMAL_BYTES 0 -#endif - -#define EEPROM_BYTES (EEPROM_BYTES_BASE+EEPROM_INDICATOR_BYTES+EEPROM_THERMAL_BYTES) - - -#include "spaghetti-monster.h" - - -// FSM states -uint8_t off_state(EventPtr event, uint16_t arg); -// simple numeric entry config menu -uint8_t config_state_base(EventPtr 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); -#ifdef USE_BATTCHECK -uint8_t battcheck_state(EventPtr 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); -#endif -// 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); -// soft lockout -#define MOON_DURING_LOCKOUT_MODE -uint8_t lockout_state(EventPtr event, uint16_t arg); -// momentary / signalling mode -uint8_t momentary_state(EventPtr event, uint16_t arg); - -// general helper function for config modes -uint8_t number_entry_state(EventPtr event, uint16_t arg); -// return value from number_entry_state() -volatile uint8_t number_entry_value; - -void blink_confirm(uint8_t num); -#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) -void indicator_blink(uint8_t arg); -#endif -#ifdef USE_INDICATOR_LED -uint8_t auxled_next_state(EventPtr event, uint16_t arg); -#endif - -// remember stuff even after battery was changed -void load_config(); -void save_config(); - -// default ramp options if not overridden earlier per-driver -#ifndef RAMP_SMOOTH_FLOOR - #define RAMP_SMOOTH_FLOOR 1 -#endif -#ifndef RAMP_SMOOTH_CEIL - #if PWM_CHANNELS == 3 - #define RAMP_SMOOTH_CEIL MAX_Nx7135 - #else - #define RAMP_SMOOTH_CEIL MAX_LEVEL - 30 - #endif -#endif -#ifndef RAMP_DISCRETE_FLOOR - #define RAMP_DISCRETE_FLOOR 20 -#endif -#ifndef RAMP_DISCRETE_CEIL - #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#endif -#ifndef RAMP_DISCRETE_STEPS - #define RAMP_DISCRETE_STEPS 7 -#endif - -// brightness control -uint8_t memorized_level = MAX_1x7135; -// smooth vs discrete ramping -volatile uint8_t ramp_style = 0; // 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; -volatile uint8_t ramp_discrete_ceil = RAMP_DISCRETE_CEIL; -volatile uint8_t ramp_discrete_steps = RAMP_DISCRETE_STEPS; -uint8_t ramp_discrete_step_size; // don't set this - -#ifdef USE_INDICATOR_LED -// bits 2-3 control lockout mode -// bits 0-1 control "off" mode -// modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) -#ifdef USE_INDICATOR_LED_WHILE_RAMPING -//uint8_t indicator_led_mode = (1<<2) + 2; -uint8_t indicator_led_mode = (2<<2) + 1; -#else -uint8_t indicator_led_mode = (3<<2) + 1; -#endif -#endif - -// calculate the nearest ramp level which would be valid at the moment -// (is a no-op for smooth ramp, but limits discrete ramp to only the -// correct levels for the user's config) -uint8_t nearest_level(int16_t target); - -#ifdef USE_THERMAL_REGULATION -// brightness before thermal step-down -uint8_t target_level = 0; -#endif - -// beacon timing -volatile uint8_t beacon_seconds = 2; - - -uint8_t off_state(EventPtr event, uint16_t arg) { - // turn emitter off when entering state - if (event == EV_enter_state) { - set_level(0); - #ifdef USE_INDICATOR_LED - indicator_led(indicator_led_mode & 0x03); - #endif - // sleep while off (lower power use) - go_to_standby = 1; - return MISCHIEF_MANAGED; - } - // go back to sleep eventually if we got bumped but didn't leave "off" state - else if (event == EV_tick) { - if (arg > TICKS_PER_SECOND*2) { - go_to_standby = 1; - #ifdef USE_INDICATOR_LED - indicator_led(indicator_led_mode & 0x03); - #endif - } - return MISCHIEF_MANAGED; - } - #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) - // blink the indicator LED, maybe - else if (event == EV_sleep_tick) { - if ((indicator_led_mode & 0b00000011) == 0b00000011) { - indicator_blink(arg); - } - return MISCHIEF_MANAGED; - } - #endif - // hold (initially): go to lowest level, but allow abort for regular click - else if (event == EV_click1_press) { - set_level(nearest_level(1)); - return MISCHIEF_MANAGED; - } - // 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 MISCHIEF_MANAGED; - } - // hold, release quickly: go to lowest level - else if (event == EV_click1_hold_release) { - set_state(steady_state, 1); - return MISCHIEF_MANAGED; - } - // 1 click (before timeout): go to memorized level, but allow abort for double click - else if (event == EV_click1_release) { - set_level(nearest_level(memorized_level)); - return MISCHIEF_MANAGED; - } - // 1 click: regular mode - else if (event == EV_1click) { - set_state(steady_state, memorized_level); - return MISCHIEF_MANAGED; - } - // 2 clicks (initial press): off, to prep for later events - else if (event == EV_click2_press) { - set_level(0); - return MISCHIEF_MANAGED; - } - // click, hold: go to highest level (for ramping down) - else if (event == EV_click2_hold) { - set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; - } - // 2 clicks: highest mode - else if (event == EV_2clicks) { - set_state(steady_state, nearest_level(MAX_LEVEL)); - return MISCHIEF_MANAGED; - } - #ifdef USE_BATTCHECK - // 3 clicks: battcheck mode / blinky mode group 1 - else if (event == EV_3clicks) { - set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; - } - #endif - // 4 clicks: momentary - else if (event == EV_4clicks) { - blink_confirm(1); - set_state(momentary_state, 0); - return MISCHIEF_MANAGED; - } - // 6 clicks: lockout mode - else if (event == EV_6clicks) { - blink_confirm(2); - set_state(lockout_state, 0); - return MISCHIEF_MANAGED; - } - #ifdef USE_INDICATOR_LED - // 7 clicks: next aux LED mode - else if (event == EV_7clicks) { - blink_confirm(1); - set_state(auxled_next_state, 0); - return MISCHIEF_MANAGED; - } - #endif - // 8 clicks: beacon mode - else if (event == EV_8clicks) { - set_state(beacon_state, 0); - return MISCHIEF_MANAGED; - } - // 10 clicks: thermal config mode - else if (event == EV_10clicks) { - push_state(thermal_config_state, 0); - return MISCHIEF_MANAGED; - } - return EVENT_NOT_HANDLED; -} - - -uint8_t steady_state(EventPtr event, uint16_t arg) { - uint8_t mode_min = ramp_smooth_floor; - uint8_t mode_max = ramp_smooth_ceil; - uint8_t ramp_step_size = 1; - #ifdef USE_REVERSING - static int8_t ramp_direction = 1; - #endif - if (ramp_style) { - mode_min = ramp_discrete_floor; - mode_max = ramp_discrete_ceil; - ramp_step_size = ramp_discrete_step_size; - } - - // turn LED on when we first enter the mode - if ((event == EV_enter_state) || (event == EV_reenter_state)) { - // if we just got back from config mode, go back to memorized level - if (event == EV_reenter_state) { - arg = memorized_level; - } - // remember this level, unless it's moon or turbo - if ((arg > mode_min) && (arg < mode_max)) - memorized_level = arg; - // use the requested level even if not memorized - #ifdef USE_THERMAL_REGULATION - target_level = arg; - #endif - set_level(nearest_level(arg)); - #ifdef USE_REVERSING - ramp_direction = 1; - #endif - return MISCHIEF_MANAGED; - } - // 1 click: off - else if (event == EV_1click) { - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - // 2 clicks: go to/from highest level - else if (event == EV_2clicks) { - if (actual_level < MAX_LEVEL) { - #ifdef USE_THERMAL_REGULATION - target_level = MAX_LEVEL; - #endif - // true turbo, not the mode-specific ceiling - set_level(MAX_LEVEL); - } - else { - #ifdef USE_THERMAL_REGULATION - target_level = memorized_level; - #endif - set_level(memorized_level); - } - return MISCHIEF_MANAGED; - } - // 3 clicks: toggle smooth vs discrete ramping - else if (event == EV_3clicks) { - ramp_style = !ramp_style; - memorized_level = nearest_level(memorized_level); - #ifdef USE_THERMAL_REGULATION - target_level = memorized_level; - #ifdef USE_SET_LEVEL_GRADUALLY - //set_level_gradually(lvl); - #endif - #endif - save_config(); - set_level(0); - delay_4ms(20/4); - set_level(memorized_level); - return MISCHIEF_MANAGED; - } - // 4 clicks: configure this ramp mode - else if (event == EV_4clicks) { - push_state(ramp_config_state, 0); - return MISCHIEF_MANAGED; - } - // hold: change brightness (brighter) - else if (event == EV_click1_hold) { - // ramp slower in discrete mode - if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { - return MISCHIEF_MANAGED; - } - #ifdef USE_REVERSING - // make it ramp down instead, if already at max - if ((arg <= 1) && (actual_level >= mode_max)) { - ramp_direction = -1; - } - memorized_level = nearest_level((int16_t)actual_level \ - + (ramp_step_size * ramp_direction)); - #else - memorized_level = nearest_level((int16_t)actual_level + ramp_step_size); - #endif - #ifdef USE_THERMAL_REGULATION - target_level = memorized_level; - #endif - #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_CHANNEL_BOUNDARIES) - // only blink once for each threshold - if ((memorized_level != actual_level) && ( - 0 // for easier syntax below - #ifdef BLINK_AT_CHANNEL_BOUNDARIES - || (memorized_level == MAX_1x7135) - #if PWM_CHANNELS >= 3 - || (memorized_level == MAX_Nx7135) - #endif - #endif - #ifdef BLINK_AT_RAMP_CEILING - || (memorized_level == mode_max) - #endif - #if defined(USE_REVERSING) && defined(BLINK_AT_RAMP_FLOOR) - || (memorized_level == mode_min) - #endif - )) { - set_level(0); - delay_4ms(8/4); - } - #endif - #if defined(BLINK_AT_STEPS) - uint8_t foo = ramp_style; - ramp_style = 1; - uint8_t nearest = nearest_level((int16_t)actual_level); - ramp_style = foo; - // only blink once for each threshold - if ((memorized_level != actual_level) && - (ramp_style == 0) && - (memorized_level == nearest) - ) - { - set_level(0); - delay_4ms(8/4); - } - #endif - set_level(memorized_level); - return MISCHIEF_MANAGED; - } - #if defined(USE_REVERSING) - // reverse ramp direction on hold release - else if (event == EV_click1_hold_release) { - #ifdef USE_REVERSING - ramp_direction = -ramp_direction; - #endif - return MISCHIEF_MANAGED; - } - #endif - // click, hold: change brightness (dimmer) - else if (event == EV_click2_hold) { - #ifdef USE_REVERSING - ramp_direction = 1; - #endif - // ramp slower in discrete mode - if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { - return MISCHIEF_MANAGED; - } - // TODO? make it ramp up instead, if already at min? - memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); - #ifdef USE_THERMAL_REGULATION - target_level = memorized_level; - #endif - #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_CHANNEL_BOUNDARIES) - // only blink once for each threshold - if ((memorized_level != actual_level) && ( - 0 // for easier syntax below - #ifdef BLINK_AT_CHANNEL_BOUNDARIES - || (memorized_level == MAX_1x7135) - #if PWM_CHANNELS >= 3 - || (memorized_level == MAX_Nx7135) - #endif - #endif - #ifdef BLINK_AT_RAMP_FLOOR - || (memorized_level == mode_min) - #endif - )) { - set_level(0); - delay_4ms(8/4); - } - #endif - #if defined(BLINK_AT_STEPS) - uint8_t foo = ramp_style; - ramp_style = 1; - uint8_t nearest = nearest_level((int16_t)actual_level); - ramp_style = foo; - // only blink once for each threshold - if ((memorized_level != actual_level) && - (ramp_style == 0) && - (memorized_level == nearest) - ) - { - set_level(0); - delay_4ms(8/4); - } - #endif - set_level(memorized_level); - return MISCHIEF_MANAGED; - } - #if defined(USE_SET_LEVEL_GRADUALLY) || defined(USE_REVERSING) - else if (event == EV_tick) { - #ifdef USE_REVERSING - // un-reverse after 1 second - if (arg == TICKS_PER_SECOND) ramp_direction = 1; - #endif - #ifdef USE_SET_LEVEL_GRADUALLY - // make thermal adjustment speed scale with magnitude - // if we're on a really high mode, drop faster - if ((arg & 1) && (actual_level < THERM_DOUBLE_SPEED_LEVEL)) { - return MISCHIEF_MANAGED; // adjust slower when not a high mode - } - // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] - //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; - // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] - //uint8_t intervals[] = {248, 132, 71, 38, 20, 10, 5, 3}; - // [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)] - uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2}; - uint8_t diff; - static uint8_t ticks_since_adjust = 0; - ticks_since_adjust ++; - if (gradual_target > actual_level) diff = gradual_target - actual_level; - else { - diff = actual_level - gradual_target; - } - uint8_t magnitude = 0; - // if we're on a really high mode, drop faster - if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { magnitude ++; } - while (diff) { - magnitude ++; - diff >>= 1; - } - uint8_t ticks_per_adjust = intervals[magnitude]; - if (ticks_since_adjust > ticks_per_adjust) - { - gradual_tick(); - ticks_since_adjust = 0; - } - //if (!(arg % ticks_per_adjust)) gradual_tick(); - #endif - return MISCHIEF_MANAGED; - } - #endif - #ifdef USE_THERMAL_REGULATION - // 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); - #endif - if (actual_level > MIN_THERM_STEPDOWN) { - int16_t stepdown = actual_level - arg; - if (stepdown < MIN_THERM_STEPDOWN) stepdown = MIN_THERM_STEPDOWN; - else if (stepdown > MAX_LEVEL) stepdown = MAX_LEVEL; - #ifdef USE_SET_LEVEL_GRADUALLY - set_level_gradually(stepdown); - #else - set_level(stepdown); - #endif - } - return MISCHIEF_MANAGED; - } - // underheating: increase slowly if we're lower than the target - // (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); - #endif - if (actual_level < target_level) { - //int16_t stepup = actual_level + (arg>>1); - int16_t stepup = actual_level + arg; - if (stepup > target_level) stepup = target_level; - else if (stepup < MIN_THERM_STEPDOWN) stepup = MIN_THERM_STEPDOWN; - #ifdef USE_SET_LEVEL_GRADUALLY - set_level_gradually(stepup); - #else - set_level(stepup); - #endif - } - return MISCHIEF_MANAGED; - } - #endif - return EVENT_NOT_HANDLED; -} - - -#ifdef USE_BATTCHECK -uint8_t battcheck_state(EventPtr event, uint16_t arg) { - // 1 click: off - if (event == EV_1click) { - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - // 2 clicks: tempcheck mode - else if (event == EV_2clicks) { - set_state(tempcheck_state, 0); - return MISCHIEF_MANAGED; - } - return EVENT_NOT_HANDLED; -} -#endif - - -#ifdef USE_THERMAL_REGULATION -uint8_t tempcheck_state(EventPtr event, uint16_t arg) { - // 1 click: off - if (event == EV_1click) { - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - // 4 clicks: thermal config mode - else if (event == EV_4clicks) { - push_state(thermal_config_state, 0); - return MISCHIEF_MANAGED; - } - return EVENT_NOT_HANDLED; -} -#endif - - -uint8_t beacon_state(EventPtr event, uint16_t arg) { - // 1 click: off - if (event == EV_1click) { - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - // TODO: use sleep ticks to measure time between pulses, - // to save power - // 4 clicks: beacon config mode - else if (event == EV_4clicks) { - push_state(beacon_config_state, 0); - return MISCHIEF_MANAGED; - } - return EVENT_NOT_HANDLED; -} - - -uint8_t lockout_state(EventPtr 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 - // FIXME: maybe do this only if arg == 0? - // (so it'll only get turned on once, instead of every frame) - uint8_t last = 0; - for(uint8_t i=0; pgm_read_byte(event + i) && (i> 2); - } else - #endif - if (event == EV_tick) { - if (arg > TICKS_PER_SECOND*2) { - go_to_standby = 1; - #ifdef USE_INDICATOR_LED - indicator_led(indicator_led_mode >> 2); - #endif - } - return MISCHIEF_MANAGED; - } - #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) - else if (event == EV_sleep_tick) { - if ((indicator_led_mode & 0b00001100) == 0b00001100) { - indicator_blink(arg); - } - return MISCHIEF_MANAGED; - } - #endif - #ifdef USE_INDICATOR_LED - // 3 clicks: rotate through indicator LED modes (lockout mode) - else if (event == EV_3clicks) { - uint8_t mode = indicator_led_mode >> 2; - #ifdef TICK_DURING_STANDBY - mode = (mode + 1) & 3; - #else - mode = (mode + 1) % 3; - #endif - indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); - indicator_led(mode); - save_config(); - return MISCHIEF_MANAGED; - } - #endif - // 6 clicks: exit - else if (event == EV_6clicks) { - blink_confirm(1); - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - - return EVENT_NOT_HANDLED; -} - - -#ifdef USE_INDICATOR_LED -uint8_t auxled_next_state(EventPtr event, uint16_t arg) { - if (event == EV_enter_state) { - uint8_t mode = indicator_led_mode & 3; - #ifdef TICK_DURING_STANDBY - mode = (mode + 1) & 3; - #else - mode = (mode + 1) % 3; - #endif - indicator_led_mode = mode + (indicator_led_mode & 0b00001100); - indicator_led(mode); - save_config(); - return MISCHIEF_MANAGED; - } - else if (event == EV_tick) { - set_state(off_state, 0); - return MISCHIEF_MANAGED; - } - - return EVENT_NOT_HANDLED; -} -#endif - - -uint8_t momentary_state(EventPtr event, uint16_t arg) { - // TODO: momentary strobe here? (for light painting) - if (event == EV_click1_press) { - set_level(memorized_level); - empty_event_sequence(); // don't attempt to parse multiple clicks - return MISCHIEF_MANAGED; - } - - else if (event == EV_release) { - set_level(0); - empty_event_sequence(); // don't attempt to parse multiple clicks - //go_to_standby = 1; // sleep while light is off - // TODO: lighted button should use lockout config? - return MISCHIEF_MANAGED; - } - - // Sleep, dammit! (but wait a few seconds first) - // (because standby mode uses such little power that it can interfere - // 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 - } - return MISCHIEF_MANAGED; - } - - return EVENT_NOT_HANDLED; -} - - -// 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 num_config_steps, - void (*savefunc)()) { - static uint8_t config_step; - if (event == EV_enter_state) { - config_step = 0; - set_level(0); - return MISCHIEF_MANAGED; - } - // advance forward through config steps - else if (event == EV_tick) { - if (config_step < num_config_steps) { - push_state(number_entry_state, config_step + 1); - } - else { - // TODO: blink out some sort of success pattern - savefunc(); - save_config(); - //set_state(retstate, retval); - pop_state(); - } - return MISCHIEF_MANAGED; - } - // an option was set (return from number_entry_state) - else if (event == EV_reenter_state) { - config_state_values[config_step] = number_entry_value; - config_step ++; - return MISCHIEF_MANAGED; - } - //return EVENT_NOT_HANDLED; - // eat all other events; don't pass any through to parent - return EVENT_HANDLED; -} - -void ramp_config_save() { - // parse values - uint8_t val; - if (ramp_style) { // discrete / stepped ramp - - val = config_state_values[0]; - if (val) { ramp_discrete_floor = val; } - - val = config_state_values[1]; - if (val) { ramp_discrete_ceil = MAX_LEVEL + 1 - val; } - - val = config_state_values[2]; - if (val) ramp_discrete_steps = val; - - } else { // smooth ramp - - val = config_state_values[0]; - if (val) { ramp_smooth_floor = val; } - - val = config_state_values[1]; - if (val) { ramp_smooth_ceil = MAX_LEVEL + 1 - val; } - - } -} - -uint8_t ramp_config_state(EventPtr event, uint16_t arg) { - uint8_t num_config_steps; - num_config_steps = 2 + ramp_style; - return config_state_base(event, arg, - num_config_steps, ramp_config_save); -} - - -#ifdef USE_THERMAL_REGULATION -void thermal_config_save() { - // parse values - uint8_t val; - - // calibrate room temperature - val = config_state_values[0]; - if (val) { - int8_t rawtemp = (temperature >> 1) - therm_cal_offset; - therm_cal_offset = val - rawtemp; - } - - val = config_state_values[1]; - if (val) { - // set maximum heat limit - therm_ceil = 30 + val; - } - if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; -} - -uint8_t thermal_config_state(EventPtr event, uint16_t arg) { - return config_state_base(event, arg, - 2, thermal_config_save); -} -#endif - - -void beacon_config_save() { - // parse values - uint8_t val = config_state_values[0]; - if (val) { - beacon_seconds = val; - } -} - -uint8_t beacon_config_state(EventPtr event, uint16_t arg) { - return config_state_base(event, arg, - 1, beacon_config_save); -} - - -uint8_t number_entry_state(EventPtr event, uint16_t arg) { - static uint8_t value; - static uint8_t blinks_left; - static uint8_t entry_step; - static uint16_t wait_ticks; - if (event == EV_enter_state) { - value = 0; - blinks_left = arg; - entry_step = 0; - wait_ticks = 0; - return MISCHIEF_MANAGED; - } - // advance through the process: - // 0: wait a moment - // 1: blink out the 'arg' value - // 2: wait a moment - // 3: "buzz" while counting clicks - // 4: save and exit - else if (event == EV_tick) { - // wait a moment - if ((entry_step == 0) || (entry_step == 2)) { - if (wait_ticks < TICKS_PER_SECOND/2) - wait_ticks ++; - else { - entry_step ++; - wait_ticks = 0; - } - } - // blink out the option number - else if (entry_step == 1) { - if (blinks_left) { - if ((wait_ticks & 31) == 10) { - set_level(RAMP_SIZE/4); - } - else if ((wait_ticks & 31) == 20) { - set_level(0); - } - else if ((wait_ticks & 31) == 31) { - blinks_left --; - } - wait_ticks ++; - } - else { - entry_step ++; - wait_ticks = 0; - } - } - else if (entry_step == 3) { // buzz while waiting for a number to be entered - wait_ticks ++; - // buzz for N seconds after last event - if ((wait_ticks & 3) == 0) { - set_level(RAMP_SIZE/6); - } - else if ((wait_ticks & 3) == 2) { - set_level(RAMP_SIZE/8); - } - // time out after 3 seconds - if (wait_ticks > TICKS_PER_SECOND*3) { - //number_entry_value = value; - set_level(0); - entry_step ++; - } - } - else if (entry_step == 4) { - number_entry_value = value; - pop_state(); - } - return MISCHIEF_MANAGED; - } - // count clicks - else if (event == EV_click1_release) { - empty_event_sequence(); - if (entry_step == 3) { // only count during the "buzz" - value ++; - wait_ticks = 0; - // flash briefly - set_level(RAMP_SIZE/2); - delay_4ms(8/2); - set_level(0); - } - return MISCHIEF_MANAGED; - } - return EVENT_NOT_HANDLED; -} - - -// find the ramp level closest to the target, -// using only the levels which are allowed in the current state -uint8_t nearest_level(int16_t target) { - // bounds check - // using int16_t here saves us a bunch of logic elsewhere, - // by allowing us to correct for numbers < 0 or > 255 in one central place - uint8_t mode_min = ramp_smooth_floor; - uint8_t mode_max = ramp_smooth_ceil; - if (ramp_style) { - mode_min = ramp_discrete_floor; - mode_max = ramp_discrete_ceil; - } - if (target < mode_min) return mode_min; - if (target > mode_max) return mode_max; - // the rest isn't relevant for smooth ramping - if (! ramp_style) return target; - - uint8_t ramp_range = ramp_discrete_ceil - ramp_discrete_floor; - ramp_discrete_step_size = ramp_range / (ramp_discrete_steps-1); - uint8_t this_level = ramp_discrete_floor; - - for(uint8_t i=0; i>1)) - return this_level; - } - return this_level; -} - - -void blink_confirm(uint8_t num) { - for (; num>0; num--) { - set_level(MAX_LEVEL/4); - delay_4ms(10/4); - set_level(0); - delay_4ms(100/4); - } -} - - -#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) -// beacon-like mode for the indicator LED -void indicator_blink(uint8_t arg) { - if (! (arg & 7)) { - indicator_led(2); - } - else { - indicator_led(0); - } -} -#endif - - -void load_config() { - if (load_eeprom()) { - ramp_style = eeprom[0]; - ramp_smooth_floor = eeprom[1]; - ramp_smooth_ceil = eeprom[2]; - ramp_discrete_floor = eeprom[3]; - ramp_discrete_ceil = eeprom[4]; - ramp_discrete_steps = eeprom[5]; - beacon_seconds = eeprom[6]; - #ifdef USE_THERMAL_REGULATION - therm_ceil = eeprom[EEPROM_BYTES_BASE]; - therm_cal_offset = eeprom[EEPROM_BYTES_BASE+1]; - #endif - #ifdef USE_INDICATOR_LED - indicator_led_mode = eeprom[EEPROM_BYTES_BASE+EEPROM_THERMAL_BYTES]; - #endif - } -} - -void save_config() { - eeprom[0] = ramp_style; - eeprom[1] = ramp_smooth_floor; - eeprom[2] = ramp_smooth_ceil; - eeprom[3] = ramp_discrete_floor; - eeprom[4] = ramp_discrete_ceil; - eeprom[5] = ramp_discrete_steps; - eeprom[6] = beacon_seconds; - #ifdef USE_THERMAL_REGULATION - eeprom[EEPROM_BYTES_BASE ] = therm_ceil; - eeprom[EEPROM_BYTES_BASE+1] = therm_cal_offset; - #endif - #ifdef USE_INDICATOR_LED - eeprom[EEPROM_BYTES_BASE+EEPROM_THERMAL_BYTES] = indicator_led_mode; - #endif - - save_eeprom(); -} - -void low_voltage() { - StatePtr state = current_state; - - // in normal mode, step down or turn off - if (state == steady_state) { - if (actual_level > 1) { - uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); - set_level(lvl); - #ifdef USE_THERMAL_REGULATION - target_level = lvl; - #ifdef USE_SET_LEVEL_GRADUALLY - // not needed? - //set_level_gradually(lvl); - #endif - #endif - } - else { - set_state(off_state, 0); - } - } - // all other modes, just turn off when voltage is low - else { - set_state(off_state, 0); - } -} - - -void setup() { - // blink at power-on to let user know power is connected - set_level(RAMP_SIZE/8); - delay_4ms(3); - set_level(0); - - load_config(); - - push_state(off_state, 0); -} - - -void loop() { - - StatePtr state = current_state; - - #ifdef USE_DYNAMIC_UNDERCLOCKING - auto_clock_speed(); - #endif - if (0) {} - - #ifdef USE_BATTCHECK - else if (state == battcheck_state) { - battcheck(); - } - #endif - #ifdef USE_THERMAL_REGULATION - // TODO: blink out therm_ceil during thermal_config_state - else if (state == tempcheck_state) { - blink_num(temperature>>1); - nice_delay_ms(1000); - } - #endif - - else if (state == beacon_state) { - set_level(memorized_level); - if (! nice_delay_ms(500)) return; - set_level(0); - nice_delay_ms(((beacon_seconds) * 1000) - 500); - } - - #ifdef USE_IDLE_MODE - else { - // doze until next clock tick - idle_mode(); - } - #endif - -} diff --git a/spaghetti-monster/anduril/rampingiosv3.svg b/spaghetti-monster/anduril/rampingiosv3.svg deleted file mode 100644 index bc9e6b3..0000000 --- a/spaghetti-monster/anduril/rampingiosv3.svg +++ /dev/null @@ -1,4113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - Ramps: - - - ThermalCfg - - - - - BeaconCfg - - - - - - Ramp - Ceil - Floor - - - Turbo - - - - - Mem - Regulated Hybrid -------------- Direct Drive - - - - - - - - - - - - Ramp - - Cfg - - - - - - Actions - 1 Fast Click - Hold - 3 Fast Clicks - Other Action - - - - 2 Fast Clicks - Click, Hold - RampingIOS V3 - - - - 7 Clicks - - - - OFF - - - - OFF - - - - - - - 4 Clicks - 4 Clicks - Click, Click, Hold - - 6 Clicks - - - - Smooth - - - - Ramp Cfg - - 4 Clicks - - - - 4 Clicks - - - - 1. Floor (click N times for level N)2. Ceiling (click N times for 1 + Turbo - N)3. Number of steps (stepped ramp only) - 1. Current temperature (click N times for N deg C)2. Temperature limit (click N times for 30 C + N) - 1. Beacon speed (click N times for N seconds per flash) - Thermal Cfg - Beacon Cfg - - 4 Clicks - - - - - - Stepped - - - - Tactical - - - BattCheck - - Lockout - - TempCheck - Beacon - - ThermalCfg - - - OFF - - - - - - - - - - - (momentary) - 3 Clicks - 4 Clicks - 6 Clicks - 8 Clicks - 10 Clicks - - - Aux LED - mode - next - - - - - - - - lockout LED - mode - next - 4 Clicks - 4 Clicks - 4 Clicks - - - - - diff --git a/spaghetti-monster/rampingios/build-all.sh b/spaghetti-monster/rampingios/build-all.sh new file mode 100755 index 0000000..003a28c --- /dev/null +++ b/spaghetti-monster/rampingios/build-all.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +for TARGET in \ + BLF_GT \ + BLF_Q8 \ + EMISAR_D1 \ + EMISAR_D1S \ + EMISAR_D4 \ + EMISAR_D4S \ + EMISAR_D4S_219c \ + FW3A \ + ; do + echo "===== $TARGET =====" + ../../../bin/build-85.sh rampingiosv3 "-DFSM_${TARGET}_DRIVER" + mv -f rampingiosv3.hex rampingiosv3.$TARGET.hex +done diff --git a/spaghetti-monster/rampingios/cfg-blf-gt.h b/spaghetti-monster/rampingios/cfg-blf-gt.h new file mode 120000 index 0000000..5e10228 --- /dev/null +++ b/spaghetti-monster/rampingios/cfg-blf-gt.h @@ -0,0 +1 @@ +../anduril/cfg-blf-gt.h \ No newline at end of file diff --git a/spaghetti-monster/rampingios/cfg-blf-q8.h b/spaghetti-monster/rampingios/cfg-blf-q8.h new file mode 120000 index 0000000..fe84054 --- /dev/null +++ b/spaghetti-monster/rampingios/cfg-blf-q8.h @@ -0,0 +1 @@ +../anduril/cfg-blf-q8.h \ No newline at end of file diff --git a/spaghetti-monster/rampingios/cfg-emisar-d1.h b/spaghetti-monster/rampingios/cfg-emisar-d1.h new file mode 120000 index 0000000..f8b4c9b --- /dev/null +++ b/spaghetti-monster/rampingios/cfg-emisar-d1.h @@ -0,0 +1 @@ +../anduril/cfg-emisar-d1.h \ No newline at end of file diff --git a/spaghetti-monster/rampingios/cfg-emisar-d1s.h b/spaghetti-monster/rampingios/cfg-emisar-d1s.h new file mode 120000 index 0000000..b6cfba6 --- /dev/null +++ b/spaghetti-monster/rampingios/cfg-emisar-d1s.h @@ -0,0 +1 @@ +../anduril/cfg-emisar-d1s.h \ No newline at end of file diff --git a/spaghetti-monster/rampingios/cfg-emisar-d4.h b/spaghetti-monster/rampingios/cfg-emisar-d4.h new file mode 120000 index 0000000..fb74f2c --- /dev/null +++ b/spaghetti-monster/rampingios/cfg-emisar-d4.h @@ -0,0 +1 @@ +../anduril/cfg-emisar-d4.h \ No newline at end of file diff --git a/spaghetti-monster/rampingios/cfg-emisar-d4s-219c.h b/spaghetti-monster/rampingios/cfg-emisar-d4s-219c.h new file mode 120000 index 0000000..f1c90f0 --- /dev/null +++ b/spaghetti-monster/rampingios/cfg-emisar-d4s-219c.h @@ -0,0 +1 @@ +../anduril/cfg-emisar-d4s-219c.h \ No newline at end of file diff --git a/spaghetti-monster/rampingios/cfg-emisar-d4s.h b/spaghetti-monster/rampingios/cfg-emisar-d4s.h new file mode 120000 index 0000000..4a03321 --- /dev/null +++ b/spaghetti-monster/rampingios/cfg-emisar-d4s.h @@ -0,0 +1 @@ +../anduril/cfg-emisar-d4s.h \ No newline at end of file diff --git a/spaghetti-monster/rampingios/cfg-fw3a.h b/spaghetti-monster/rampingios/cfg-fw3a.h new file mode 120000 index 0000000..5bc8b21 --- /dev/null +++ b/spaghetti-monster/rampingios/cfg-fw3a.h @@ -0,0 +1 @@ +../anduril/cfg-fw3a.h \ No newline at end of file diff --git a/spaghetti-monster/rampingios/rampingiosv3-ui.png b/spaghetti-monster/rampingios/rampingiosv3-ui.png new file mode 100644 index 0000000..d02dbf6 Binary files /dev/null and b/spaghetti-monster/rampingios/rampingiosv3-ui.png differ diff --git a/spaghetti-monster/rampingios/rampingiosv3.c b/spaghetti-monster/rampingios/rampingiosv3.c new file mode 100644 index 0000000..6b12262 --- /dev/null +++ b/spaghetti-monster/rampingios/rampingiosv3.c @@ -0,0 +1,1166 @@ +/* + * RampingIOS V3: FSM-based version of RampingIOS V2 UI, with upgrades. + * + * Copyright (C) 2018 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 . + */ + +/********* User-configurable options *********/ +// Physical driver type (uncomment one of the following or define it at the gcc command line) +//#define FSM_EMISAR_D4_DRIVER +//#define FSM_EMISAR_D4S_DRIVER +//#define FSM_EMISAR_D4S_219c_DRIVER +//#define FSM_BLF_Q8_DRIVER +//#define FSM_FW3A_DRIVER +//#define FSM_BLF_GT_DRIVER + +#define USE_LVP // FIXME: won't build when this option is turned off + +#define USE_THERMAL_REGULATION +#define DEFAULT_THERM_CEIL 45 +#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#ifdef MAX_Nx7135 +#define THERM_DOUBLE_SPEED_LEVEL MAX_Nx7135 // throttle back faster when high +#else +#define THERM_DOUBLE_SPEED_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high +#endif +#ifdef USE_THERMAL_REGULATION +#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments +#endif + +// short blips while ramping +#define BLINK_AT_CHANNEL_BOUNDARIES +//#define BLINK_AT_RAMP_FLOOR +#define BLINK_AT_RAMP_CEILING +//#define BLINK_AT_STEPS // whenever a discrete ramp mode is passed in smooth mode + +// ramp down via regular button hold if a ramp-up ended <1s ago +// ("hold, release, hold" ramps down instead of up) +#define USE_REVERSING + +// battery readout style (pick one) +#define BATTCHECK_VpT +//#define BATTCHECK_8bars // FIXME: breaks build +//#define BATTCHECK_4bars // FIXME: breaks build + +/***** specific settings for known driver types *****/ +#if defined(FSM_BLF_GT_DRIVER) +#include "cfg-blf-gt.h" + +#elif defined(FSM_BLF_Q8_DRIVER) +#include "cfg-blf-q8.h" + +#elif defined(FSM_EMISAR_D1_DRIVER) +#include "cfg-emisar-d1.h" + +#elif defined(FSM_EMISAR_D1S_DRIVER) +#include "cfg-emisar-d1s.h" + +#elif defined(FSM_EMISAR_D4_DRIVER) +#include "cfg-emisar-d4.h" + +#elif defined(FSM_EMISAR_D4S_219c_DRIVER) +#include "cfg-emisar-d4s-219c.h" + +#elif defined(FSM_EMISAR_D4S_DRIVER) +#include "cfg-emisar-d4s.h" + +#elif defined(FSM_FW3A_DRIVER) +#include "cfg-fw3a.h" + +#endif + +/********* Configure SpaghettiMonster *********/ +#define USE_DELAY_ZERO +#define USE_RAMPING +#define RAMP_LENGTH 150 +#define USE_BATTCHECK +#define MAX_CLICKS 10 +#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending +#define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency + +// try to auto-detect how many eeprom bytes +#define USE_EEPROM +#define EEPROM_BYTES_BASE 7 + +#ifdef USE_INDICATOR_LED +#define EEPROM_INDICATOR_BYTES 1 +#else +#define EEPROM_INDICATOR_BYTES 0 +#endif + +#ifdef USE_THERMAL_REGULATION +#define EEPROM_THERMAL_BYTES 2 +#else +#define EEPROM_THERMAL_BYTES 0 +#endif + +#define EEPROM_BYTES (EEPROM_BYTES_BASE+EEPROM_INDICATOR_BYTES+EEPROM_THERMAL_BYTES) + + +#include "spaghetti-monster.h" + + +// FSM states +uint8_t off_state(EventPtr event, uint16_t arg); +// simple numeric entry config menu +uint8_t config_state_base(EventPtr 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); +#ifdef USE_BATTCHECK +uint8_t battcheck_state(EventPtr 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); +#endif +// 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); +// soft lockout +#define MOON_DURING_LOCKOUT_MODE +uint8_t lockout_state(EventPtr event, uint16_t arg); +// momentary / signalling mode +uint8_t momentary_state(EventPtr event, uint16_t arg); + +// general helper function for config modes +uint8_t number_entry_state(EventPtr event, uint16_t arg); +// return value from number_entry_state() +volatile uint8_t number_entry_value; + +void blink_confirm(uint8_t num); +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +void indicator_blink(uint8_t arg); +#endif +#ifdef USE_INDICATOR_LED +uint8_t auxled_next_state(EventPtr event, uint16_t arg); +#endif + +// remember stuff even after battery was changed +void load_config(); +void save_config(); + +// default ramp options if not overridden earlier per-driver +#ifndef RAMP_SMOOTH_FLOOR + #define RAMP_SMOOTH_FLOOR 1 +#endif +#ifndef RAMP_SMOOTH_CEIL + #if PWM_CHANNELS == 3 + #define RAMP_SMOOTH_CEIL MAX_Nx7135 + #else + #define RAMP_SMOOTH_CEIL MAX_LEVEL - 30 + #endif +#endif +#ifndef RAMP_DISCRETE_FLOOR + #define RAMP_DISCRETE_FLOOR 20 +#endif +#ifndef RAMP_DISCRETE_CEIL + #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#endif +#ifndef RAMP_DISCRETE_STEPS + #define RAMP_DISCRETE_STEPS 7 +#endif + +// brightness control +uint8_t memorized_level = MAX_1x7135; +// smooth vs discrete ramping +volatile uint8_t ramp_style = 0; // 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; +volatile uint8_t ramp_discrete_ceil = RAMP_DISCRETE_CEIL; +volatile uint8_t ramp_discrete_steps = RAMP_DISCRETE_STEPS; +uint8_t ramp_discrete_step_size; // don't set this + +#ifdef USE_INDICATOR_LED +// bits 2-3 control lockout mode +// bits 0-1 control "off" mode +// modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +//uint8_t indicator_led_mode = (1<<2) + 2; +uint8_t indicator_led_mode = (2<<2) + 1; +#else +uint8_t indicator_led_mode = (3<<2) + 1; +#endif +#endif + +// calculate the nearest ramp level which would be valid at the moment +// (is a no-op for smooth ramp, but limits discrete ramp to only the +// correct levels for the user's config) +uint8_t nearest_level(int16_t target); + +#ifdef USE_THERMAL_REGULATION +// brightness before thermal step-down +uint8_t target_level = 0; +#endif + +// beacon timing +volatile uint8_t beacon_seconds = 2; + + +uint8_t off_state(EventPtr event, uint16_t arg) { + // turn emitter off when entering state + if (event == EV_enter_state) { + set_level(0); + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode & 0x03); + #endif + // sleep while off (lower power use) + go_to_standby = 1; + return MISCHIEF_MANAGED; + } + // go back to sleep eventually if we got bumped but didn't leave "off" state + else if (event == EV_tick) { + if (arg > TICKS_PER_SECOND*2) { + go_to_standby = 1; + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode & 0x03); + #endif + } + return MISCHIEF_MANAGED; + } + #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) + // blink the indicator LED, maybe + else if (event == EV_sleep_tick) { + if ((indicator_led_mode & 0b00000011) == 0b00000011) { + indicator_blink(arg); + } + return MISCHIEF_MANAGED; + } + #endif + // hold (initially): go to lowest level, but allow abort for regular click + else if (event == EV_click1_press) { + set_level(nearest_level(1)); + return MISCHIEF_MANAGED; + } + // 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 MISCHIEF_MANAGED; + } + // hold, release quickly: go to lowest level + else if (event == EV_click1_hold_release) { + set_state(steady_state, 1); + return MISCHIEF_MANAGED; + } + // 1 click (before timeout): go to memorized level, but allow abort for double click + else if (event == EV_click1_release) { + set_level(nearest_level(memorized_level)); + return MISCHIEF_MANAGED; + } + // 1 click: regular mode + else if (event == EV_1click) { + set_state(steady_state, memorized_level); + return MISCHIEF_MANAGED; + } + // 2 clicks (initial press): off, to prep for later events + else if (event == EV_click2_press) { + set_level(0); + return MISCHIEF_MANAGED; + } + // click, hold: go to highest level (for ramping down) + else if (event == EV_click2_hold) { + set_state(steady_state, MAX_LEVEL); + return MISCHIEF_MANAGED; + } + // 2 clicks: highest mode + else if (event == EV_2clicks) { + set_state(steady_state, nearest_level(MAX_LEVEL)); + return MISCHIEF_MANAGED; + } + #ifdef USE_BATTCHECK + // 3 clicks: battcheck mode / blinky mode group 1 + else if (event == EV_3clicks) { + set_state(battcheck_state, 0); + return MISCHIEF_MANAGED; + } + #endif + // 4 clicks: momentary + else if (event == EV_4clicks) { + blink_confirm(1); + set_state(momentary_state, 0); + return MISCHIEF_MANAGED; + } + // 6 clicks: lockout mode + else if (event == EV_6clicks) { + blink_confirm(2); + set_state(lockout_state, 0); + return MISCHIEF_MANAGED; + } + #ifdef USE_INDICATOR_LED + // 7 clicks: next aux LED mode + else if (event == EV_7clicks) { + blink_confirm(1); + set_state(auxled_next_state, 0); + return MISCHIEF_MANAGED; + } + #endif + // 8 clicks: beacon mode + else if (event == EV_8clicks) { + set_state(beacon_state, 0); + return MISCHIEF_MANAGED; + } + // 10 clicks: thermal config mode + else if (event == EV_10clicks) { + push_state(thermal_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +uint8_t steady_state(EventPtr event, uint16_t arg) { + uint8_t mode_min = ramp_smooth_floor; + uint8_t mode_max = ramp_smooth_ceil; + uint8_t ramp_step_size = 1; + #ifdef USE_REVERSING + static int8_t ramp_direction = 1; + #endif + if (ramp_style) { + mode_min = ramp_discrete_floor; + mode_max = ramp_discrete_ceil; + ramp_step_size = ramp_discrete_step_size; + } + + // turn LED on when we first enter the mode + if ((event == EV_enter_state) || (event == EV_reenter_state)) { + // if we just got back from config mode, go back to memorized level + if (event == EV_reenter_state) { + arg = memorized_level; + } + // remember this level, unless it's moon or turbo + if ((arg > mode_min) && (arg < mode_max)) + memorized_level = arg; + // use the requested level even if not memorized + #ifdef USE_THERMAL_REGULATION + target_level = arg; + #endif + set_level(nearest_level(arg)); + #ifdef USE_REVERSING + ramp_direction = 1; + #endif + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: go to/from highest level + else if (event == EV_2clicks) { + if (actual_level < MAX_LEVEL) { + #ifdef USE_THERMAL_REGULATION + target_level = MAX_LEVEL; + #endif + // true turbo, not the mode-specific ceiling + set_level(MAX_LEVEL); + } + else { + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + set_level(memorized_level); + } + return MISCHIEF_MANAGED; + } + // 3 clicks: toggle smooth vs discrete ramping + else if (event == EV_3clicks) { + ramp_style = !ramp_style; + memorized_level = nearest_level(memorized_level); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #ifdef USE_SET_LEVEL_GRADUALLY + //set_level_gradually(lvl); + #endif + #endif + save_config(); + set_level(0); + delay_4ms(20/4); + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + // 4 clicks: configure this ramp mode + else if (event == EV_4clicks) { + push_state(ramp_config_state, 0); + return MISCHIEF_MANAGED; + } + // hold: change brightness (brighter) + else if (event == EV_click1_hold) { + // ramp slower in discrete mode + if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + return MISCHIEF_MANAGED; + } + #ifdef USE_REVERSING + // make it ramp down instead, if already at max + if ((arg <= 1) && (actual_level >= mode_max)) { + ramp_direction = -1; + } + memorized_level = nearest_level((int16_t)actual_level \ + + (ramp_step_size * ramp_direction)); + #else + memorized_level = nearest_level((int16_t)actual_level + ramp_step_size); + #endif + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + // only blink once for each threshold + if ((memorized_level != actual_level) && ( + 0 // for easier syntax below + #ifdef BLINK_AT_CHANNEL_BOUNDARIES + || (memorized_level == MAX_1x7135) + #if PWM_CHANNELS >= 3 + || (memorized_level == MAX_Nx7135) + #endif + #endif + #ifdef BLINK_AT_RAMP_CEILING + || (memorized_level == mode_max) + #endif + #if defined(USE_REVERSING) && defined(BLINK_AT_RAMP_FLOOR) + || (memorized_level == mode_min) + #endif + )) { + set_level(0); + delay_4ms(8/4); + } + #endif + #if defined(BLINK_AT_STEPS) + uint8_t foo = ramp_style; + ramp_style = 1; + uint8_t nearest = nearest_level((int16_t)actual_level); + ramp_style = foo; + // only blink once for each threshold + if ((memorized_level != actual_level) && + (ramp_style == 0) && + (memorized_level == nearest) + ) + { + set_level(0); + delay_4ms(8/4); + } + #endif + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + #if defined(USE_REVERSING) + // reverse ramp direction on hold release + else if (event == EV_click1_hold_release) { + #ifdef USE_REVERSING + ramp_direction = -ramp_direction; + #endif + return MISCHIEF_MANAGED; + } + #endif + // click, hold: change brightness (dimmer) + else if (event == EV_click2_hold) { + #ifdef USE_REVERSING + ramp_direction = 1; + #endif + // ramp slower in discrete mode + if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + return MISCHIEF_MANAGED; + } + // TODO? make it ramp up instead, if already at min? + memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + // only blink once for each threshold + if ((memorized_level != actual_level) && ( + 0 // for easier syntax below + #ifdef BLINK_AT_CHANNEL_BOUNDARIES + || (memorized_level == MAX_1x7135) + #if PWM_CHANNELS >= 3 + || (memorized_level == MAX_Nx7135) + #endif + #endif + #ifdef BLINK_AT_RAMP_FLOOR + || (memorized_level == mode_min) + #endif + )) { + set_level(0); + delay_4ms(8/4); + } + #endif + #if defined(BLINK_AT_STEPS) + uint8_t foo = ramp_style; + ramp_style = 1; + uint8_t nearest = nearest_level((int16_t)actual_level); + ramp_style = foo; + // only blink once for each threshold + if ((memorized_level != actual_level) && + (ramp_style == 0) && + (memorized_level == nearest) + ) + { + set_level(0); + delay_4ms(8/4); + } + #endif + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + #if defined(USE_SET_LEVEL_GRADUALLY) || defined(USE_REVERSING) + else if (event == EV_tick) { + #ifdef USE_REVERSING + // un-reverse after 1 second + if (arg == TICKS_PER_SECOND) ramp_direction = 1; + #endif + #ifdef USE_SET_LEVEL_GRADUALLY + // make thermal adjustment speed scale with magnitude + // if we're on a really high mode, drop faster + if ((arg & 1) && (actual_level < THERM_DOUBLE_SPEED_LEVEL)) { + return MISCHIEF_MANAGED; // adjust slower when not a high mode + } + // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; + // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 132, 71, 38, 20, 10, 5, 3}; + // [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)] + uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2}; + uint8_t diff; + static uint8_t ticks_since_adjust = 0; + ticks_since_adjust ++; + if (gradual_target > actual_level) diff = gradual_target - actual_level; + else { + diff = actual_level - gradual_target; + } + uint8_t magnitude = 0; + // if we're on a really high mode, drop faster + if (actual_level >= THERM_DOUBLE_SPEED_LEVEL) { magnitude ++; } + while (diff) { + magnitude ++; + diff >>= 1; + } + uint8_t ticks_per_adjust = intervals[magnitude]; + if (ticks_since_adjust > ticks_per_adjust) + { + gradual_tick(); + ticks_since_adjust = 0; + } + //if (!(arg % ticks_per_adjust)) gradual_tick(); + #endif + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_THERMAL_REGULATION + // 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); + #endif + if (actual_level > MIN_THERM_STEPDOWN) { + int16_t stepdown = actual_level - arg; + if (stepdown < MIN_THERM_STEPDOWN) stepdown = MIN_THERM_STEPDOWN; + else if (stepdown > MAX_LEVEL) stepdown = MAX_LEVEL; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepdown); + #else + set_level(stepdown); + #endif + } + return MISCHIEF_MANAGED; + } + // underheating: increase slowly if we're lower than the target + // (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); + #endif + if (actual_level < target_level) { + //int16_t stepup = actual_level + (arg>>1); + int16_t stepup = actual_level + arg; + if (stepup > target_level) stepup = target_level; + else if (stepup < MIN_THERM_STEPDOWN) stepup = MIN_THERM_STEPDOWN; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepup); + #else + set_level(stepup); + #endif + } + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +#ifdef USE_BATTCHECK +uint8_t battcheck_state(EventPtr event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: tempcheck mode + else if (event == EV_2clicks) { + set_state(tempcheck_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} +#endif + + +#ifdef USE_THERMAL_REGULATION +uint8_t tempcheck_state(EventPtr event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 4 clicks: thermal config mode + else if (event == EV_4clicks) { + push_state(thermal_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} +#endif + + +uint8_t beacon_state(EventPtr event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // TODO: use sleep ticks to measure time between pulses, + // to save power + // 4 clicks: beacon config mode + else if (event == EV_4clicks) { + push_state(beacon_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +uint8_t lockout_state(EventPtr 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 + // FIXME: maybe do this only if arg == 0? + // (so it'll only get turned on once, instead of every frame) + uint8_t last = 0; + for(uint8_t i=0; pgm_read_byte(event + i) && (i> 2); + } else + #endif + if (event == EV_tick) { + if (arg > TICKS_PER_SECOND*2) { + go_to_standby = 1; + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode >> 2); + #endif + } + return MISCHIEF_MANAGED; + } + #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) + else if (event == EV_sleep_tick) { + if ((indicator_led_mode & 0b00001100) == 0b00001100) { + indicator_blink(arg); + } + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_INDICATOR_LED + // 3 clicks: rotate through indicator LED modes (lockout mode) + else if (event == EV_3clicks) { + uint8_t mode = indicator_led_mode >> 2; + #ifdef TICK_DURING_STANDBY + mode = (mode + 1) & 3; + #else + mode = (mode + 1) % 3; + #endif + indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); + indicator_led(mode); + save_config(); + return MISCHIEF_MANAGED; + } + #endif + // 6 clicks: exit + else if (event == EV_6clicks) { + blink_confirm(1); + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} + + +#ifdef USE_INDICATOR_LED +uint8_t auxled_next_state(EventPtr event, uint16_t arg) { + if (event == EV_enter_state) { + uint8_t mode = indicator_led_mode & 3; + #ifdef TICK_DURING_STANDBY + mode = (mode + 1) & 3; + #else + mode = (mode + 1) % 3; + #endif + indicator_led_mode = mode + (indicator_led_mode & 0b00001100); + indicator_led(mode); + save_config(); + return MISCHIEF_MANAGED; + } + else if (event == EV_tick) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} +#endif + + +uint8_t momentary_state(EventPtr event, uint16_t arg) { + // TODO: momentary strobe here? (for light painting) + if (event == EV_click1_press) { + set_level(memorized_level); + empty_event_sequence(); // don't attempt to parse multiple clicks + return MISCHIEF_MANAGED; + } + + else if (event == EV_release) { + set_level(0); + empty_event_sequence(); // don't attempt to parse multiple clicks + //go_to_standby = 1; // sleep while light is off + // TODO: lighted button should use lockout config? + return MISCHIEF_MANAGED; + } + + // Sleep, dammit! (but wait a few seconds first) + // (because standby mode uses such little power that it can interfere + // 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 + } + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} + + +// 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 num_config_steps, + void (*savefunc)()) { + static uint8_t config_step; + if (event == EV_enter_state) { + config_step = 0; + set_level(0); + return MISCHIEF_MANAGED; + } + // advance forward through config steps + else if (event == EV_tick) { + if (config_step < num_config_steps) { + push_state(number_entry_state, config_step + 1); + } + else { + // TODO: blink out some sort of success pattern + savefunc(); + save_config(); + //set_state(retstate, retval); + pop_state(); + } + return MISCHIEF_MANAGED; + } + // an option was set (return from number_entry_state) + else if (event == EV_reenter_state) { + config_state_values[config_step] = number_entry_value; + config_step ++; + return MISCHIEF_MANAGED; + } + //return EVENT_NOT_HANDLED; + // eat all other events; don't pass any through to parent + return EVENT_HANDLED; +} + +void ramp_config_save() { + // parse values + uint8_t val; + if (ramp_style) { // discrete / stepped ramp + + val = config_state_values[0]; + if (val) { ramp_discrete_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_discrete_ceil = MAX_LEVEL + 1 - val; } + + val = config_state_values[2]; + if (val) ramp_discrete_steps = val; + + } else { // smooth ramp + + val = config_state_values[0]; + if (val) { ramp_smooth_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_smooth_ceil = MAX_LEVEL + 1 - val; } + + } +} + +uint8_t ramp_config_state(EventPtr event, uint16_t arg) { + uint8_t num_config_steps; + num_config_steps = 2 + ramp_style; + return config_state_base(event, arg, + num_config_steps, ramp_config_save); +} + + +#ifdef USE_THERMAL_REGULATION +void thermal_config_save() { + // parse values + uint8_t val; + + // calibrate room temperature + val = config_state_values[0]; + if (val) { + int8_t rawtemp = (temperature >> 1) - therm_cal_offset; + therm_cal_offset = val - rawtemp; + } + + val = config_state_values[1]; + if (val) { + // set maximum heat limit + therm_ceil = 30 + val; + } + if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; +} + +uint8_t thermal_config_state(EventPtr event, uint16_t arg) { + return config_state_base(event, arg, + 2, thermal_config_save); +} +#endif + + +void beacon_config_save() { + // parse values + uint8_t val = config_state_values[0]; + if (val) { + beacon_seconds = val; + } +} + +uint8_t beacon_config_state(EventPtr event, uint16_t arg) { + return config_state_base(event, arg, + 1, beacon_config_save); +} + + +uint8_t number_entry_state(EventPtr event, uint16_t arg) { + static uint8_t value; + static uint8_t blinks_left; + static uint8_t entry_step; + static uint16_t wait_ticks; + if (event == EV_enter_state) { + value = 0; + blinks_left = arg; + entry_step = 0; + wait_ticks = 0; + return MISCHIEF_MANAGED; + } + // advance through the process: + // 0: wait a moment + // 1: blink out the 'arg' value + // 2: wait a moment + // 3: "buzz" while counting clicks + // 4: save and exit + else if (event == EV_tick) { + // wait a moment + if ((entry_step == 0) || (entry_step == 2)) { + if (wait_ticks < TICKS_PER_SECOND/2) + wait_ticks ++; + else { + entry_step ++; + wait_ticks = 0; + } + } + // blink out the option number + else if (entry_step == 1) { + if (blinks_left) { + if ((wait_ticks & 31) == 10) { + set_level(RAMP_SIZE/4); + } + else if ((wait_ticks & 31) == 20) { + set_level(0); + } + else if ((wait_ticks & 31) == 31) { + blinks_left --; + } + wait_ticks ++; + } + else { + entry_step ++; + wait_ticks = 0; + } + } + else if (entry_step == 3) { // buzz while waiting for a number to be entered + wait_ticks ++; + // buzz for N seconds after last event + if ((wait_ticks & 3) == 0) { + set_level(RAMP_SIZE/6); + } + else if ((wait_ticks & 3) == 2) { + set_level(RAMP_SIZE/8); + } + // time out after 3 seconds + if (wait_ticks > TICKS_PER_SECOND*3) { + //number_entry_value = value; + set_level(0); + entry_step ++; + } + } + else if (entry_step == 4) { + number_entry_value = value; + pop_state(); + } + return MISCHIEF_MANAGED; + } + // count clicks + else if (event == EV_click1_release) { + empty_event_sequence(); + if (entry_step == 3) { // only count during the "buzz" + value ++; + wait_ticks = 0; + // flash briefly + set_level(RAMP_SIZE/2); + delay_4ms(8/2); + set_level(0); + } + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +// find the ramp level closest to the target, +// using only the levels which are allowed in the current state +uint8_t nearest_level(int16_t target) { + // bounds check + // using int16_t here saves us a bunch of logic elsewhere, + // by allowing us to correct for numbers < 0 or > 255 in one central place + uint8_t mode_min = ramp_smooth_floor; + uint8_t mode_max = ramp_smooth_ceil; + if (ramp_style) { + mode_min = ramp_discrete_floor; + mode_max = ramp_discrete_ceil; + } + if (target < mode_min) return mode_min; + if (target > mode_max) return mode_max; + // the rest isn't relevant for smooth ramping + if (! ramp_style) return target; + + uint8_t ramp_range = ramp_discrete_ceil - ramp_discrete_floor; + ramp_discrete_step_size = ramp_range / (ramp_discrete_steps-1); + uint8_t this_level = ramp_discrete_floor; + + for(uint8_t i=0; i>1)) + return this_level; + } + return this_level; +} + + +void blink_confirm(uint8_t num) { + for (; num>0; num--) { + set_level(MAX_LEVEL/4); + delay_4ms(10/4); + set_level(0); + delay_4ms(100/4); + } +} + + +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +// beacon-like mode for the indicator LED +void indicator_blink(uint8_t arg) { + if (! (arg & 7)) { + indicator_led(2); + } + else { + indicator_led(0); + } +} +#endif + + +void load_config() { + if (load_eeprom()) { + ramp_style = eeprom[0]; + ramp_smooth_floor = eeprom[1]; + ramp_smooth_ceil = eeprom[2]; + ramp_discrete_floor = eeprom[3]; + ramp_discrete_ceil = eeprom[4]; + ramp_discrete_steps = eeprom[5]; + beacon_seconds = eeprom[6]; + #ifdef USE_THERMAL_REGULATION + therm_ceil = eeprom[EEPROM_BYTES_BASE]; + therm_cal_offset = eeprom[EEPROM_BYTES_BASE+1]; + #endif + #ifdef USE_INDICATOR_LED + indicator_led_mode = eeprom[EEPROM_BYTES_BASE+EEPROM_THERMAL_BYTES]; + #endif + } +} + +void save_config() { + eeprom[0] = ramp_style; + eeprom[1] = ramp_smooth_floor; + eeprom[2] = ramp_smooth_ceil; + eeprom[3] = ramp_discrete_floor; + eeprom[4] = ramp_discrete_ceil; + eeprom[5] = ramp_discrete_steps; + eeprom[6] = beacon_seconds; + #ifdef USE_THERMAL_REGULATION + eeprom[EEPROM_BYTES_BASE ] = therm_ceil; + eeprom[EEPROM_BYTES_BASE+1] = therm_cal_offset; + #endif + #ifdef USE_INDICATOR_LED + eeprom[EEPROM_BYTES_BASE+EEPROM_THERMAL_BYTES] = indicator_led_mode; + #endif + + save_eeprom(); +} + +void low_voltage() { + StatePtr state = current_state; + + // in normal mode, step down or turn off + if (state == steady_state) { + if (actual_level > 1) { + uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); + set_level(lvl); + #ifdef USE_THERMAL_REGULATION + target_level = lvl; + #ifdef USE_SET_LEVEL_GRADUALLY + // not needed? + //set_level_gradually(lvl); + #endif + #endif + } + else { + set_state(off_state, 0); + } + } + // all other modes, just turn off when voltage is low + else { + set_state(off_state, 0); + } +} + + +void setup() { + // blink at power-on to let user know power is connected + set_level(RAMP_SIZE/8); + delay_4ms(3); + set_level(0); + + load_config(); + + push_state(off_state, 0); +} + + +void loop() { + + StatePtr state = current_state; + + #ifdef USE_DYNAMIC_UNDERCLOCKING + auto_clock_speed(); + #endif + if (0) {} + + #ifdef USE_BATTCHECK + else if (state == battcheck_state) { + battcheck(); + } + #endif + #ifdef USE_THERMAL_REGULATION + // TODO: blink out therm_ceil during thermal_config_state + else if (state == tempcheck_state) { + blink_num(temperature>>1); + nice_delay_ms(1000); + } + #endif + + else if (state == beacon_state) { + set_level(memorized_level); + if (! nice_delay_ms(500)) return; + set_level(0); + nice_delay_ms(((beacon_seconds) * 1000) - 500); + } + + #ifdef USE_IDLE_MODE + else { + // doze until next clock tick + idle_mode(); + } + #endif + +} diff --git a/spaghetti-monster/rampingios/rampingiosv3.svg b/spaghetti-monster/rampingios/rampingiosv3.svg new file mode 100644 index 0000000..bc9e6b3 --- /dev/null +++ b/spaghetti-monster/rampingios/rampingiosv3.svg @@ -0,0 +1,4113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + Ramps: + + + ThermalCfg + + + + + BeaconCfg + + + + + + Ramp + Ceil + Floor + + + Turbo + + + + + Mem + Regulated Hybrid -------------- Direct Drive + + + + + + + + + + + + Ramp + + Cfg + + + + + + Actions + 1 Fast Click + Hold + 3 Fast Clicks + Other Action + + + + 2 Fast Clicks + Click, Hold + RampingIOS V3 + + + + 7 Clicks + + + + OFF + + + + OFF + + + + + + + 4 Clicks + 4 Clicks + Click, Click, Hold + + 6 Clicks + + + + Smooth + + + + Ramp Cfg + + 4 Clicks + + + + 4 Clicks + + + + 1. Floor (click N times for level N)2. Ceiling (click N times for 1 + Turbo - N)3. Number of steps (stepped ramp only) + 1. Current temperature (click N times for N deg C)2. Temperature limit (click N times for 30 C + N) + 1. Beacon speed (click N times for N seconds per flash) + Thermal Cfg + Beacon Cfg + + 4 Clicks + + + + + + Stepped + + + + Tactical + + + BattCheck + + Lockout + + TempCheck + Beacon + + ThermalCfg + + + OFF + + + + + + + + + + + (momentary) + 3 Clicks + 4 Clicks + 6 Clicks + 8 Clicks + 10 Clicks + + + Aux LED + mode + next + + + + + + + + lockout LED + mode + next + 4 Clicks + 4 Clicks + 4 Clicks + + + + + -- cgit v1.2.3 From 6b3960695fcadf249c5927c259523e6deb895aca Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 6 Aug 2018 21:24:05 -0600 Subject: Added more driver types to Anduril. --- spaghetti-monster/anduril/anduril.c | 10 ++++++++++ spaghetti-monster/anduril/build-all.sh | 1 + 2 files changed, 11 insertions(+) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 0c53042..71b4b9a 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -22,6 +22,7 @@ // Physical driver type (uncomment one of the following or define it at the gcc command line) //#define FSM_EMISAR_D4_DRIVER //#define FSM_EMISAR_D4S_DRIVER +//#define FSM_EMISAR_D4S_219c_DRIVER //#define FSM_BLF_Q8_DRIVER //#define FSM_FW3A_DRIVER //#define FSM_BLF_GT_DRIVER @@ -65,9 +66,18 @@ #elif defined(FSM_BLF_Q8_DRIVER) #include "cfg-blf-q8.h" +#elif defined(FSM_EMISAR_D1_DRIVER) +#include "cfg-emisar-d1.h" + +#elif defined(FSM_EMISAR_D1S_DRIVER) +#include "cfg-emisar-d1s.h" + #elif defined(FSM_EMISAR_D4_DRIVER) #include "cfg-emisar-d4.h" +#elif defined(FSM_EMISAR_D4S_219c_DRIVER) +#include "cfg-emisar-d4s-219c.h" + #elif defined(FSM_EMISAR_D4S_DRIVER) #include "cfg-emisar-d4s.h" diff --git a/spaghetti-monster/anduril/build-all.sh b/spaghetti-monster/anduril/build-all.sh index c488d77..d0c0d5c 100755 --- a/spaghetti-monster/anduril/build-all.sh +++ b/spaghetti-monster/anduril/build-all.sh @@ -7,6 +7,7 @@ for TARGET in \ EMISAR_D1S \ EMISAR_D4 \ EMISAR_D4S \ + EMISAR_D4S_219c \ FW3A \ ; do echo "===== $TARGET =====" -- cgit v1.2.3