88
93
// so don't enable them at the same time as any of the above strobes)
89
94
//#define USE_POLICE_STROBE_MODE
90
95
//#define USE_SOS_MODE
96
//#define USE_SOS_MODE_IN_FF_GROUP // put SOS in the "boring strobes" mode
97
//#define USE_SOS_MODE_IN_BLINKY_GROUP // put SOS in the blinkies mode group
99
// cut clock speed at very low modes for better efficiency
100
// (defined here so config files can override it)
101
#define USE_DYNAMIC_UNDERCLOCKING
92
103
/***** specific settings for known driver types *****/
280
291
uint8_t beacon_state(Event event, uint16_t arg);
281
292
uint8_t beacon_config_state(Event event, uint16_t arg);
294
#ifdef USE_SOS_MODE_IN_BLINKY_GROUP
295
// automatic SOS emergency signal
296
uint8_t sos_state(Event event, uint16_t arg);
284
299
#define MOON_DURING_LOCKOUT_MODE
285
300
// if enabled, 2nd lockout click goes to the other ramp's floor level
286
301
#define LOCKOUT_MOON_FANCY
287
302
uint8_t lockout_state(Event event, uint16_t arg);
303
#ifdef USE_MOMENTARY_MODE
288
304
// momentary / signalling mode
289
305
uint8_t momentary_state(Event event, uint16_t arg);
290
306
uint8_t momentary_mode = 0; // 0 = ramping, 1 = strobe
291
307
uint8_t momentary_active = 0; // boolean, true if active *right now*
292
309
#ifdef USE_MUGGLE_MODE
293
310
// muggle mode, super-simple, hard to exit
294
311
uint8_t muggle_state(Event event, uint16_t arg);
671
711
return MISCHIEF_MANAGED;
673
713
else if (event == EV_click7_hold_release) {
714
setting_rgb_mode_now = 0;
675
716
return MISCHIEF_MANAGED;
677
718
#endif // end 7 clicks
678
#ifdef USE_TENCLICK_THERMAL_CONFIG
719
#if defined(USE_TENCLICK_THERMAL_CONFIG) && defined(USE_THERMAL_REGULATION)
679
720
// 10 clicks: thermal config mode
680
721
else if (event == EV_10clicks) {
681
722
push_state(thermal_config_state, 0);
682
723
return MISCHIEF_MANAGED;
726
#ifdef USE_VERSION_CHECK
727
// 15+ clicks: show the version number
728
else if (event == EV_15clicks) {
729
set_state(version_check_state, 0);
730
return MISCHIEF_MANAGED;
685
733
#if defined(USE_FACTORY_RESET) && defined(USE_SOFT_FACTORY_RESET)
686
734
// 13 clicks and hold the last click: invoke factory reset (reboot)
687
735
else if (event == EV_click13_hold) {
792
842
// (off->hold->stepped_min->release causes this state)
793
843
else if (actual_level <= mode_min) { ramp_direction = 1; }
845
// if the button is stuck, err on the side of safety and ramp down
846
else if ((arg > TICKS_PER_SECOND * 5) && (actual_level >= mode_max)) {
849
// if the button is still stuck, lock the light
850
else if ((arg > TICKS_PER_SECOND * 10) && (actual_level <= mode_min)) {
852
set_state(lockout_state, 0);
795
854
memorized_level = nearest_level((int16_t)actual_level \
796
855
+ (ramp_step_size * ramp_direction));
919
978
if (arg == TICKS_PER_SECOND) ramp_direction = 1;
921
980
#ifdef USE_SET_LEVEL_GRADUALLY
922
// make thermal adjustment speed scale with magnitude
923
// also, adjust slower when going up
925
((actual_level < THERM_FASTER_LEVEL) ||
926
(actual_level < gradual_target))) {
927
return MISCHIEF_MANAGED; // adjust slower when not a high mode
929
#ifdef THERM_HARD_TURBO_DROP
930
else if ((! (actual_level < THERM_FASTER_LEVEL))
931
&& (actual_level > gradual_target)) {
936
// [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)]
937
//uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5};
938
// [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)]
939
//uint8_t intervals[] = {248, 132, 71, 38, 20, 10, 5, 3};
940
// [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)]
941
uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2};
943
static uint8_t ticks_since_adjust = 0;
944
if (gradual_target > actual_level) {
945
// rise at half speed (skip half the frames)
946
if (arg & 2) return MISCHIEF_MANAGED;
947
diff = gradual_target - actual_level;
949
diff = actual_level - gradual_target;
951
ticks_since_adjust ++;
952
// if there's any adjustment to be made, make it
981
int16_t diff = gradual_target - actual_level;
982
static uint16_t ticks_since_adjust = 0;
983
ticks_since_adjust++;
954
uint8_t magnitude = 0;
955
#ifndef THERM_HARD_TURBO_DROP
956
// if we're on a really high mode, drop faster
957
if ((actual_level >= THERM_FASTER_LEVEL)
958
&& (actual_level > gradual_target)) { magnitude ++; }
985
uint16_t ticks_per_adjust = 256;
988
if (actual_level > THERM_FASTER_LEVEL) {
989
#ifdef THERM_HARD_TURBO_DROP
990
ticks_per_adjust >>= 2;
992
ticks_per_adjust >>= 2;
995
// rise at half speed
996
ticks_per_adjust <<= 1;
999
ticks_per_adjust >>= 1;
1001
diff /= 2; // because shifting produces weird behavior
964
uint8_t ticks_per_adjust = intervals[magnitude];
965
1003
if (ticks_since_adjust > ticks_per_adjust)
968
1006
ticks_since_adjust = 0;
970
//if (!(arg % ticks_per_adjust)) gradual_tick();
972
#ifdef THERM_HARD_TURBO_DROP
975
1009
#endif // ifdef USE_SET_LEVEL_GRADUALLY
976
1010
return MISCHIEF_MANAGED;
1025
1059
return MISCHIEF_MANAGED;
1061
#ifdef USE_SET_LEVEL_GRADUALLY
1062
// temperature is within target window
1063
// (so stop trying to adjust output)
1064
else if (event == EV_temperature_okay) {
1065
// if we're still adjusting output... stop after the current step
1066
if (gradual_target > actual_level)
1067
gradual_target = actual_level + 1;
1068
else if (gradual_target < actual_level)
1069
gradual_target = actual_level - 1;
1070
return MISCHIEF_MANAGED;
1072
#endif // ifdef USE_SET_LEVEL_GRADUALLY
1027
1073
#endif // ifdef USE_THERMAL_REGULATION
1028
1074
return EVENT_NOT_HANDLED;
1539
#endif // #ifdef USE_BORING_STROBE_STATE
1488
1541
#ifdef USE_SOS_MODE
1542
#ifdef USE_SOS_MODE_IN_BLINKY_GROUP
1543
uint8_t sos_state(Event event, uint16_t arg) {
1545
if (event == EV_1click) {
1546
set_state(off_state, 0);
1547
return MISCHIEF_MANAGED;
1549
// 2 clicks: next mode
1550
else if (event == EV_2clicks) {
1551
#ifdef USE_THERMAL_REGULATION
1552
set_state(tempcheck_state, 0);
1554
set_state(battcheck_state, 0);
1556
return MISCHIEF_MANAGED;
1558
return EVENT_NOT_HANDLED;
1489
1562
void sos_blink(uint8_t num, uint8_t dah) {
1490
1563
#define DIT_LENGTH 200
1491
1564
for (; num > 0; num--) {
1499
1572
nice_delay_ms(DIT_LENGTH);
1501
1574
// three "off" dits (or one "dah") between letters
1502
nice_delay_ms(DIT_LENGTH*2);
1575
// (except for SOS, which is collectively treated as a single "letter")
1576
//nice_delay_ms(DIT_LENGTH*2);
1505
1579
inline void sos_mode_iter() {
1506
1580
// one iteration of main loop()
1507
nice_delay_ms(1000);
1581
//nice_delay_ms(1000);
1508
1582
sos_blink(3, 0); // S
1509
1583
sos_blink(3, 1); // O
1510
1584
sos_blink(3, 0); // S
1511
nice_delay_ms(1000);
1585
nice_delay_ms(2000);
1513
1587
#endif // #ifdef USE_SOS_MODE
1514
#endif // #ifdef USE_BORING_STROBE_STATE
1517
1590
#ifdef USE_BATTCHECK
1521
1594
set_state(off_state, 0);
1522
1595
return MISCHIEF_MANAGED;
1597
#ifdef USE_GOODNIGHT_MODE
1524
1598
// 2 clicks: goodnight mode
1525
1599
else if (event == EV_2clicks) {
1526
1600
set_state(goodnight_state, 0);
1527
1601
return MISCHIEF_MANAGED;
1603
#elif defined(USE_BEACON_MODE)
1604
// 2 clicks: beacon mode
1605
else if (event == EV_2clicks) {
1606
set_state(beacon_state, 0);
1607
return MISCHIEF_MANAGED;
1609
#elif defined(USE_THERMAL_REGULATION)
1610
// 2 clicks: tempcheck mode
1611
else if (event == EV_2clicks) {
1612
set_state(tempcheck_state, 0);
1613
return MISCHIEF_MANAGED;
1529
1616
return EVENT_NOT_HANDLED;
1563
1652
// TODO: use sleep ticks to measure time between pulses,
1564
1653
// to save power
1565
// 2 clicks: tempcheck mode
1654
// 2 clicks: next mode
1566
1655
else if (event == EV_2clicks) {
1567
#ifdef USE_THERMAL_REGULATION
1656
#ifdef USE_SOS_MODE_IN_BLINKY_GROUP
1657
set_state(sos_state, 0);
1658
#elif defined(USE_THERMAL_REGULATION)
1568
1659
set_state(tempcheck_state, 0);
1660
#elif defined(USE_BATTCHECK)
1570
1661
set_state(battcheck_state, 0);
1572
1663
return MISCHIEF_MANAGED;
1853
#ifdef USE_MOMENTARY_MODE
1754
1854
uint8_t momentary_state(Event event, uint16_t arg) {
1755
1855
// TODO: momentary strobe here? (for light painting)
1757
1857
// init strobe mode, if relevant
1858
#ifdef USE_STROBE_STATE
1758
1859
if ((event == EV_enter_state) && (momentary_mode == 1)) {
1759
1860
strobe_state(event, arg);
1762
1864
// light up when the button is pressed; go dark otherwise
1763
1865
// button is being held
2249
2373
#if defined(USE_AUX_RGB_LEDS) && defined(TICK_DURING_STANDBY)
2374
uint8_t voltage_to_rgb() {
2375
uint8_t levels[] = {
2383
44, 6, // 6, R+G+B // skip; looks too similar to G+B
2386
uint8_t volts = voltage;
2387
if (volts < 29) return 0;
2390
for (i = 0; volts >= levels[i]; i += 2) {}
2391
uint8_t color_num = levels[(i - 2) + 1];
2392
return pgm_read_byte(rgb_led_colors + color_num);
2250
2395
// do fancy stuff with the RGB aux LEDs
2251
2396
// mode: 0bPPPPCCCC where PPPP is the pattern and CCCC is the color
2252
2397
// arg: time slice number
2257
2402
// turn off aux LEDs when battery is empty
2258
2403
// (but if voltage==0, that means we just booted and don't know yet)
2259
2404
uint8_t volts = voltage; // save a few bytes by caching volatile value
2260
if ((volts) && (volts < VOLTAGE_LOW)) { rgb_led_set(0); return; }
2405
if ((volts) && (volts < VOLTAGE_LOW)) {
2407
#ifdef USE_BUTTON_LED
2262
2413
uint8_t pattern = (mode>>4); // off, low, high, blinking, ... more?
2263
2414
uint8_t color = mode & 0x0f;
2266
2417
if ((! go_to_standby) && (pattern > 2)) { pattern = 2; }
2269
uint8_t colors[] = {
2270
0b00000001, // 0: red
2271
0b00000101, // 1: yellow
2272
0b00000100, // 2: green
2273
0b00010100, // 3: cyan
2274
0b00010000, // 4: blue
2275
0b00010001, // 5: purple
2276
0b00010101, // 6: white
2420
const uint8_t *colors = rgb_led_colors;
2278
2421
uint8_t actual_color = 0;
2279
2422
if (color < 7) { // normal color
2280
actual_color = colors[color];
2423
actual_color = pgm_read_byte(colors + color);
2282
2425
else if (color == 7) { // rainbow
2283
if (0 == (arg & 0x03)) {
2426
uint8_t speed = 0x03; // awake speed
2427
if (go_to_standby) speed = RGB_RAINBOW_SPEED; // asleep speed
2428
if (0 == (arg & speed)) {
2284
2429
rainbow = (rainbow + 1) % 6;
2286
actual_color = colors[rainbow];
2431
actual_color = pgm_read_byte(colors + rainbow);
2288
2433
else { // voltage
2289
2434
// show actual voltage while asleep...
2290
2435
if (go_to_standby) {
2436
actual_color = voltage_to_rgb();
2291
2437
// choose a color based on battery voltage
2292
if (volts >= 38) actual_color = colors[4];
2293
else if (volts >= 33) actual_color = colors[2];
2294
else actual_color = colors[0];
2438
//if (volts >= 38) actual_color = pgm_read_byte(colors + 4);
2439
//else if (volts >= 33) actual_color = pgm_read_byte(colors + 2);
2440
//else actual_color = pgm_read_byte(colors + 0);
2296
2442
// ... but during preview, cycle colors quickly
2298
actual_color = colors[((arg>>1) % 3) << 1];
2444
actual_color = pgm_read_byte(colors + (((arg>>1) % 3) << 1));
2307
2453
frame = (frame + 1) % sizeof(animation);
2308
2454
pattern = animation[frame];
2457
#ifdef USE_BUTTON_LED
2458
uint8_t button_led_result;
2310
2460
switch (pattern) {
2463
#ifdef USE_BUTTON_LED
2464
button_led_result = 0;
2315
rgb_led_set(actual_color);
2468
result = actual_color;
2469
#ifdef USE_BUTTON_LED
2470
button_led_result = 1;
2318
rgb_led_set(actual_color << 1);
2474
result = (actual_color << 1);
2475
#ifdef USE_BUTTON_LED
2476
button_led_result = 2;
2480
rgb_led_set(result);
2481
#ifdef USE_BUTTON_LED
2482
button_led_set(button_led_result);
2486
void rgb_led_voltage_readout(uint8_t bright) {
2487
uint8_t color = voltage_to_rgb();
2488
if (bright) color = color << 1;
2557
2726
StatePtr state = current_state;
2728
#ifdef USE_AUX_RGB_LEDS_WHILE_ON
2729
if (! setting_rgb_mode_now) rgb_led_voltage_readout(1);
2734
#ifdef USE_VERSION_CHECK
2735
else if (state == version_check_state) {
2736
for (uint8_t i=0; i<sizeof(version_number)-1; i++) {
2737
blink_digit(pgm_read_byte(version_number + i) - '0');
2740
// FIXME: when user interrupts with button, "off" takes an extra click
2741
// before it'll turn back on, because the click to cancel gets sent
2742
// to the "off" state instead of version_check_state
2743
//while (button_is_pressed()) {}
2744
//empty_event_sequence();
2746
set_state(off_state, 0);
2748
#endif // #ifdef USE_VERSION_CHECK
2561
2750
#ifdef USE_STROBE_STATE
2562
2751
else if ((state == strobe_state)
2563
|| ((state == momentary_state) && (momentary_mode == 1) && (momentary_active)) ) { // also handle momentary strobes
2752
#ifdef USE_MOMENTARY_MODE
2753
// also handle momentary strobes
2754
|| ((state == momentary_state) && (momentary_mode == 1) && (momentary_active))
2564
2757
uint8_t st = strobe_type;