View difference between Paste ID: TbhnU0DX and EtZKy9td
SHOW: | | - or go back to the newest paste.
1
/*
2
 * BLF EE A6 firmware (special-edition group buy light)
3
 * This light uses a FET+1 style driver, with a FET on the main PWM channel
4
 * for the brightest high modes and a single 7135 chip on the secondary PWM
5
 * channel so we can get stable, efficient low / medium modes.  It also
6
 * includes a capacitor for measuring off time.
7
 *
8
 * Copyright (C) 2015 Selene Scriven
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 *
24
 * NANJG 105C Diagram
25
 *           ---
26
 *         -|   |- VCC
27
 *     OTC -|   |- Voltage ADC
28
 *  Star 3 -|   |- PWM (FET)
29
 *     GND -|   |- PWM (1x7135)
30
 *           ---
31
 *
32
 * FUSES
33
 *      I use these fuse settings
34
 *      Low:  0x75  (4.8MHz CPU without 8x divider, 9.4kHz phase-correct PWM or 18.75kHz fast-PWM)
35
 *      High: 0xfd  (to enable brownout detection)
36
 *
37
 *      For more details on these settings, visit http://github.com/JCapSolutions/blf-firmware/wiki/PWM-Frequency
38
 *
39
 * STARS
40
 *      Star 2 = second PWM output channel
41
 *      Star 3 = mode memory if soldered, no memory by default
42
 *      Star 4 = Capacitor for off-time
43
 *
44
 * VOLTAGE
45
 *      Resistor values for voltage divider (reference BLF-VLD README for more info)
46
 *      Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
47
 *
48
 *           VCC
49
 *            |
50
 *           Vd (~.25 v drop from protection diode)
51
 *            |
52
 *          1912 (R1 19,100 ohms)
53
 *            |
54
 *            |---- PB2 from MCU
55
 *            |
56
 *          4701 (R2 4,700 ohms)
57
 *            |
58
 *           GND
59
 *
60
 *   To find out what values to use, flash the driver with battcheck.hex
61
 *   and hook the light up to each voltage you need a value for.  This is
62
 *   much more reliable than attempting to calculate the values from a
63
 *   theoretical formula.
64
 *
65
 *   Same for off-time capacitor values.  Measure, don't guess.
66
 */
67
#define F_CPU 4800000UL
68
69
/*
70
 * =========================================================================
71
 * Settings to modify per driver
72
 */
73
74
//#define FAST 0x23           // fast PWM channel 1 only
75
//#define PHASE 0x21          // phase-correct PWM channel 1 only
76
#define FAST 0xA3           // fast PWM both channels
77
#define PHASE 0xA1          // phase-correct PWM both channels
78
79
#define VOLTAGE_MON         // Comment out to disable LVP
80
#define OWN_DELAY           // Should we use the built-in delay or our own?
81
// Adjust the timing per-driver, since the hardware has high variance
82
// Higher values will run slower, lower values run faster.
83
#define DELAY_TWEAK         950
84
85
//#define OFFTIM3             // Use short/med/long off-time presses
86
                            // instead of just short/long
87
88
89
// output to use for blinks on battery check mode (primary PWM level, alt PWM level)
90
// Use 20,0 for a single-channel driver or 0,20 for a two-channel driver
91
#define BLINK_BRIGHTNESS    20,20
92
93
// Mode group 1
94
#define NUM_MODES1          3
95
// PWM levels for the big circuit (FET or Nx7135)
96
#define MODESNx1            0,255,TURBO
97
// PWM levels for the small circuit (1x7135)
98
#define MODES1x1            255,0,0
99
// PWM speed for each mode
100
#define MODES_PWM1          PHASE,PHASE,PHASE
101
// Mode group 2
102
#define NUM_MODES2          5
103
#define MODESNx2            0,0,15,255,TURBO
104
#define MODES1x2            5,255,0,0,0
105
#define MODES_PWM2          PHASE,FAST,FAST,FAST,FAST
106
// Hidden modes are *before* the lowest (moon) mode, and should be specified
107
// in reverse order.  So, to go backward from moon to turbo to strobe to
108
// battcheck, use BATTCHECK,STROBE,TURBO .
109
#define NUM_HIDDEN          0
110
#define HIDDENMODES         0
111
#define HIDDENMODES_PWM     0
112
#define HIDDENMODES_ALT     0  // Zeroes, same length as NUM_HIDDEN
113
114
#define TURBO     245       // Convenience code for turbo mode
115
#define BATTCHECK 254       // Convenience code for battery check mode
116
// Uncomment to enable tactical strobe mode
117
//#define STROBE    253       // Convenience code for strobe mode
118
// Uncomment to unable a 2-level stutter beacon instead of a tactical strobe
119
//#define BIKING_STROBE 252   // Convenience code for biking strobe mode
120
// comment out to use minimal version instead (smaller)
121
//#define FULL_BIKING_STROBE
122
123
#define NON_WDT_TURBO            // enable turbo step-down without WDT
124
// How many timer ticks before before dropping down.
125
// Each timer tick is 500ms, so "60" would be a 30-second stepdown.
126
// Max value of 255 unless you change "ticks"
127
#define TURBO_TIMEOUT       10
128
129
// These values were measured using wight's "A17HYBRID-S" driver built by DBCstm.
130
// Your mileage may vary.
131
#define ADC_42          174 // the ADC value we expect for 4.20 volts
132
#define ADC_100         174 // the ADC value for 100% full (4.2V resting)
133
#define ADC_75          166 // the ADC value for 75% full (4.0V resting)
134
#define ADC_50          158 // the ADC value for 50% full (3.8V resting)
135
#define ADC_25          145 // the ADC value for 25% full (3.5V resting)
136
#define ADC_0           124 // the ADC value for 0% full (3.0V resting)
137
#define ADC_LOW         116 // When do we start ramping down (2.8V)
138
#define ADC_CRIT        112 // When do we shut the light off (2.7V)
139
// These values were copied from s7.c.
140
// Your mileage may vary.
141
//#define ADC_42          185 // the ADC value we expect for 4.20 volts
142
//#define ADC_100         185 // the ADC value for 100% full (4.2V resting)
143
//#define ADC_75          175 // the ADC value for 75% full (4.0V resting)
144
//#define ADC_50          164 // the ADC value for 50% full (3.8V resting)
145
//#define ADC_25          154 // the ADC value for 25% full (3.5V resting)
146
//#define ADC_0           139 // the ADC value for 0% full (3.0V resting)
147
//#define ADC_LOW         123 // When do we start ramping down (2.8V)
148
//#define ADC_CRIT        113 // When do we shut the light off (2.7V)
149
// Values for testing only:
150
//#define ADC_LOW         125 // When do we start ramping down (2.8V)
151
//#define ADC_CRIT        124 // When do we shut the light off (2.7V)
152
153
// the BLF EE A6 driver may have different offtime cap values than most other drivers
154
// Values are between 1 and 255, and can be measured with offtime-cap.c
155
// These #defines are the edge boundaries, not the center of the target.
156
#ifdef OFFTIM3
157
#define CAP_SHORT           250  // Anything higher than this is a short press
158
#define CAP_MED             190  // Between CAP_MED and CAP_SHORT is a medium press
159
                                 // Below CAP_MED is a long press
160
#else
161
#define CAP_SHORT           190  // Anything higher than this is a short press, lower is a long press
162
#endif
163
164
/*
165
 * =========================================================================
166
 */
167
168
// Ignore a spurious warning, we did the cast on purpose
169
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
170
171
#ifdef OWN_DELAY
172
#include <util/delay_basic.h>
173
// Having own _delay_ms() saves some bytes AND adds possibility to use variables as input
174
void _delay_ms(uint16_t n)
175
{
176
    // TODO: make this take tenths of a ms instead of ms,
177
    // for more precise timing?
178
    while(n-- > 0) _delay_loop_2(DELAY_TWEAK);
179
}
180
void _delay_s()  // because it saves a bit of ROM space to do it this way
181
{
182
    _delay_ms(1000);
183
}
184
#else
185
#include <util/delay.h>
186
#endif
187
188
#include <avr/pgmspace.h>
189
//#include <avr/io.h>
190
//#include <avr/interrupt.h>
191
#include <avr/eeprom.h>
192
#include <avr/sleep.h>
193
//#include <avr/power.h>
194
195
#define STAR2_PIN   PB0     // But note that there is no star 2.
196
#define FET_PIN   PB4
197
#define CAP_PIN     PB3
198
#define CAP_CHANNEL 0x03    // MUX 03 corresponds with PB3 (Star 4)
199
#define CAP_DIDR    ADC3D   // Digital input disable bit corresponding with PB3
200
#define PWM_PIN     PB1
201
#define ALT_PWM_PIN PB0
202
#define VOLTAGE_PIN PB2
203
#define ADC_CHANNEL 0x01    // MUX 01 corresponds with PB2
204
#define ADC_DIDR    ADC1D   // Digital input disable bit corresponding with PB2
205
#define ADC_PRSCL   0x06    // clk/64
206
207
#define PWM_LVL     OCR0B   // OCR0B is the output compare register for PB1
208
#define ALT_PWM_LVL OCR0A   // OCR0A is the output compare register for PB0
209
210
/*
211
 * global variables
212
 */
213
214
// Config / state variables
215
uint8_t eepos = 0;
216
uint8_t memory = 0;        // mode memory, or not (set via soldered star)
217
uint8_t modegroup = 0;     // which mode group (set above in #defines)
218
uint8_t mode_idx = 0;      // current or last-used mode number
219
// counter for entering config mode
220
// (needs to be remembered while off, but only for up to half a second)
221
uint8_t fast_presses __attribute__ ((section (".noinit")));
222
223
// NOTE: Only '1' is known to work; -1 will probably break and is untested.
224
// In other words, short press goes to the next (higher) mode,
225
// medium press goes to the previous (lower) mode.
226
#define mode_dir 1
227
// total length of current mode group's array
228
uint8_t mode_cnt;
229
// number of regular non-hidden modes in current mode group
230
uint8_t solid_modes;
231
// number of hidden modes in the current mode group
232
// (hardcoded because both groups have the same hidden modes)
233
//uint8_t hidden_modes = NUM_HIDDEN;  // this is never used
234
235
236
// Modes (gets set when the light starts up based on saved config values)
237
PROGMEM const uint8_t modesNx1[] = { MODESNx1, HIDDENMODES };
238
PROGMEM const uint8_t modesNx2[] = { MODESNx2, HIDDENMODES };
239
const uint8_t *modesNx;  // gets pointed at whatever group is current
240
241
PROGMEM const uint8_t modes1x1[] = { MODES1x1, HIDDENMODES_ALT };
242
PROGMEM const uint8_t modes1x2[] = { MODES1x2, HIDDENMODES_ALT };
243
const uint8_t *modes1x;
244
245
PROGMEM const uint8_t modes_pwm1[] = { MODES_PWM1, HIDDENMODES_PWM };
246
PROGMEM const uint8_t modes_pwm2[] = { MODES_PWM2, HIDDENMODES_PWM };
247
const uint8_t *modes_pwm;
248
249
PROGMEM const uint8_t voltage_blinks[] = {
250
    ADC_0,    // 1 blink  for 0%-25%
251
    ADC_25,   // 2 blinks for 25%-50%
252
    ADC_50,   // 3 blinks for 50%-75%
253
    ADC_75,   // 4 blinks for 75%-100%
254
    ADC_100,  // 5 blinks for >100%
255
    255,      // Ceiling, don't remove
256
};
257
258
void save_state() {  // central method for writing (with wear leveling)
259
    // a single 16-bit write uses less ROM space than two 8-bit writes
260
    uint8_t eep;
261
    uint8_t oldpos=eepos;
262
263
    eepos = (eepos+1) & 63;  // wear leveling, use next cell
264
265
266
    eep = mode_idx | (modegroup << 5) | (memory << 6);
267
    eeprom_write_byte((uint8_t *)(eepos), eep);      // save current state
268
    eeprom_write_byte((uint8_t *)(oldpos), 0xff);    // erase old state
269
}
270
271
void restore_state() {
272
    uint8_t eep;
273
    // find the config data
274
    for(eepos=0; eepos<64; eepos++) {
275
        eep = eeprom_read_byte((const uint8_t *)eepos);
276
        if (eep != 0xff) break;
277
    }
278
    // unpack the config data
279
    if (eepos < 64) {
280
        mode_idx = eep & 0x0f;
281
        modegroup = (eep >> 5) & 1;
282
        memory = (eep >> 6) & 1;
283
    }
284
    // unnecessary, save_state handles wrap-around
285
    // (and we don't really care about it skipping cell 0 once in a while)
286
    //else eepos=0;
287
}
288
289
inline void next_mode() {
290
    mode_idx += 1;
291
    if (mode_idx >= solid_modes) {
292
        // Wrap around, skipping the hidden modes
293
        // (note: this also applies when going "forward" from any hidden mode)
294
        mode_idx = 0;
295
    }
296
}
297
298
#ifdef OFFTIM3
299
inline void prev_mode() {
300
    if (mode_idx == solid_modes) {
301
        // If we hit the end of the hidden modes, go back to moon
302
        mode_idx = 0;
303
    } else if (mode_idx > 0) {
304
        // Regular mode: is between 1 and TOTAL_MODES
305
        mode_idx -= 1;
306
    } else {
307
        // Otherwise, wrap around (this allows entering hidden modes)
308
        mode_idx = mode_cnt - 1;
309
    }
310
}
311
#endif
312
313
#ifdef CONFIG_STARS
314
inline void check_stars() {
315
    // Configure options based on stars
316
    // 0 being low for soldered, 1 for pulled-up for not soldered
317
#if 0  // not implemented, STAR2_PIN is used for second PWM channel
318
    // Moon
319
    // enable moon mode?
320
    if ((PINB & (1 << STAR2_PIN)) == 0) {
321
        modes[mode_cnt++] = MODE_MOON;
322
    }
323
#endif
324
#if 0  // Mode order not as important as mem/no-mem
325
    // Mode order
326
    if ((PINB & (1 << FET_PIN)) == 0) {
327
        // High to Low
328
        mode_dir = -1;
329
    } else {
330
        mode_dir = 1;
331
    }
332
#endif
333
    // Memory
334
    if ((PINB & (1 << FET_PIN)) == 0) {
335
        memory = 1;  // solder to enable memory
336
    } else {
337
        memory = 0;  // unsolder to disable memory
338
    }
339
}
340
#endif  // ifdef CONFIG_STARS
341
342
void count_modes() {
343
    /*
344
     * Determine how many solid and hidden modes we have.
345
     * The modes_pwm array should have several values for regular modes
346
     * then some values for hidden modes.
347
     *
348
     * (this matters because we have more than one set of modes to choose
349
     *  from, so we need to count at runtime)
350
     */
351
    if (modegroup == 0) {
352
        solid_modes = NUM_MODES1;
353
        modesNx = modesNx1;
354
        modes1x = modes1x1;
355
        modes_pwm = modes_pwm1;
356
    } else {
357
        solid_modes = NUM_MODES2;
358
        modesNx = modesNx2;
359
        modes1x = modes1x2;
360
        modes_pwm = modes_pwm2;
361
    }
362
    mode_cnt = solid_modes + NUM_HIDDEN;
363
}
364
365
#ifdef VOLTAGE_MON
366
inline void ADC_on() {
367
    DIDR0 |= (1 << ADC_DIDR);                           // disable digital input on ADC pin to reduce power consumption
368
    ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
369
    ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
370
}
371
#else
372
inline void ADC_off() {
373
    ADCSRA &= ~(1<<7); //ADC off
374
}
375
#endif
376
377
void set_output(uint8_t pwm1, uint8_t pwm2) {
378
    // Need PHASE to properly turn off the light
379
    if ((pwm1==0) && (pwm2==0)) {
380
        TCCR0A = PHASE;
381
    }
382
#ifdef TURBO
383
	if (pwm1 == TURBO) {
384
		PWM_LVL = 0;
385
		ALT_PWM_LVL = 0;
386
		DDRB |= (1 << FET_PIN);
387
		PORTB |= (1 << FET_PIN);
388
	} else {
389
		PWM_LVL = pwm1;
390
		ALT_PWM_LVL = pwm2;
391
		PORTB &= ~(1 << FET_PIN);
392
	}
393
#else	
394
	PWM_LVL = pwm1;
395
	ALT_PWM_LVL = pwm2;
396
#endif //ifdef TURBO
397
}
398
399
void set_mode(uint8_t mode) {
400
    TCCR0A = pgm_read_byte(modes_pwm + mode);
401
    set_output(pgm_read_byte(modesNx + mode), pgm_read_byte(modes1x + mode));
402
    /*
403
    // Only set output for solid modes
404
    uint8_t out = pgm_read_byte(modesNx + mode);
405
    if ((out < 250) || (out == 255)) {
406
        set_output(pgm_read_byte(modesNx + mode), pgm_read_byte(modes1x + mode));
407
    }
408
    */
409
}
410
411
#ifdef VOLTAGE_MON
412
uint8_t get_voltage() {
413
    // Start conversion
414
    ADCSRA |= (1 << ADSC);
415
    // Wait for completion
416
    while (ADCSRA & (1 << ADSC));
417
    // See if voltage is lower than what we were looking for
418
    return ADCH;
419
}
420
#endif
421
422
void blink(uint8_t val)
423
{
424
    for (; val>0; val--)
425
    {
426
        set_output(BLINK_BRIGHTNESS);
427
        _delay_ms(100);
428
        set_output(0,0);
429
        _delay_ms(400);
430
    }
431
}
432
433
void toggle(uint8_t *var) {
434
    // Used for extended config mode
435
    // Changes the value of a config option, waits for the user to "save"
436
    // by turning the light off, then changes the value back in case they
437
    // didn't save.  Can be used repeatedly on different options, allowing
438
    // the user to change and save only one at a time.
439
    *var ^= 1;
440
    save_state();
441
    blink(2);
442
    *var ^= 1;
443
    save_state();
444
    _delay_s();
445
}
446
447
int main(void)
448
{
449
    uint8_t cap_val;
450
451
    // Read the off-time cap *first* to get the most accurate reading
452
    // Start up ADC for capacitor pin
453
    DIDR0 |= (1 << CAP_DIDR);                           // disable digital input on ADC pin to reduce power consumption
454
    ADMUX  = (1 << REFS0) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3
455
    ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
456
457
    // Wait for completion
458
    while (ADCSRA & (1 << ADSC));
459
    // Start again as datasheet says first result is unreliable
460
    ADCSRA |= (1 << ADSC);
461
    // Wait for completion
462
    while (ADCSRA & (1 << ADSC));
463
    cap_val = ADCH; // save this for later
464
465
    // Set PWM pin to output
466
    DDRB |= (1 << PWM_PIN);     // enable main channel
467
    DDRB |= (1 << ALT_PWM_PIN); // enable second channel
468
469
    // Set timer to do PWM for correct output pin and set prescaler timing
470
    //TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
471
    //TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
472
    TCCR0A = PHASE;
473
    // Set timer to do PWM for correct output pin and set prescaler timing
474
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
475
476
    // Read config values and saved state
477
    restore_state();
478
    // Enable the current mode group
479
    count_modes();
480
481
482
    // memory decayed, reset it
483
    // (should happen on med/long press instead
484
    //  because mem decay is *much* slower when the OTC is charged
485
    //  so let's not wait until it decays to reset it)
486
    //if (fast_presses > 0x20) { fast_presses = 0; }
487
488
    if (cap_val > CAP_SHORT) {
489
        // We don't care what the value is as long as it's over 15
490
        fast_presses = (fast_presses+1) & 0x1f;
491
        // Indicates they did a short press, go to the next mode
492
        next_mode(); // Will handle wrap arounds
493
#ifdef OFFTIM3
494
    } else if (cap_val > CAP_MED) {
495
        fast_presses = 0;
496
        // User did a medium press, go back one mode
497
        prev_mode(); // Will handle "negative" modes and wrap-arounds
498
#endif
499
    } else {
500
        // Long press, keep the same mode
501
        // ... or reset to the first mode
502
        fast_presses = 0;
503
        if (! memory) {
504
            // Reset to the first mode
505
            mode_idx = 0;
506
        }
507
    }
508
    save_state();
509
510
    // Turn off ADC
511
    //ADC_off();
512
513
    // Charge up the capacitor by setting CAP_PIN to output
514
    DDRB  |= (1 << CAP_PIN);    // Output
515
    PORTB |= (1 << CAP_PIN);    // High
516
517
    // Turn features on or off as needed
518
    #ifdef VOLTAGE_MON
519
    ADC_on();
520
    #else
521
    ADC_off();
522
    #endif
523
    //ACSR   |=  (1<<7); //AC off
524
525
    // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
526
    // Will allow us to go idle between WDT interrupts
527
    //set_sleep_mode(SLEEP_MODE_IDLE);  // not used due to blinky modes
528
529
    uint8_t output;
530
#ifdef NON_WDT_TURBO
531
    uint8_t ticks = 0;
532
#endif
533
#ifdef VOLTAGE_MON
534
    uint8_t lowbatt_cnt = 0;
535
    uint8_t i = 0;
536
    uint8_t voltage;
537
    // Make sure voltage reading is running for later
538
    ADCSRA |= (1 << ADSC);
539
#endif
540
    while(1) {
541
        output = pgm_read_byte(modesNx + mode_idx);
542
        if (fast_presses > 0x0f) {  // Config mode
543
            _delay_s();       // wait for user to stop fast-pressing button
544
            fast_presses = 0; // exit this mode after one use
545
            mode_idx = 0;
546
547
            // Longer/larger version of the config mode
548
            // Toggle the mode group, blink, un-toggle, continue
549
            toggle(&modegroup);
550
551
            // Toggle memory, blink, untoggle, exit
552
            toggle(&memory);
553
        }
554
555
#ifdef STROBE
556
        else if (output == STROBE) {
557
            // 10Hz tactical strobe
558
            set_output(255,0);
559
            _delay_ms(50);
560
            set_output(0,0);
561
            _delay_ms(50);
562
        }
563
#endif // ifdef STROBE
564
#ifdef BIKING_STROBE
565
        else if (output == BIKING_STROBE) {
566
            // 2-level stutter beacon for biking and such
567
#ifdef FULL_BIKING_STROBE
568
            // normal version
569
            for(i=0;i<4;i++) {
570
                set_output(255,0);
571
                _delay_ms(5);
572
                set_output(0,255);
573
                _delay_ms(65);
574
            }
575
            _delay_ms(720);
576
#else
577
            // small/minimal version
578
            set_output(255,0);
579
            _delay_ms(10);
580
            set_output(0,255);
581
            _delay_s();
582
#endif
583
        }
584
#endif  // ifdef BIKING_STROBE
585
#ifdef BATTCHECK
586
        else if (output == BATTCHECK) {
587
            voltage = get_voltage();
588
            // figure out how many times to blink
589
            for (i=0;
590
                    voltage > pgm_read_byte(voltage_blinks + i);
591
                    i ++) {}
592
593
            // blink zero to five times to show voltage
594
            // (~0%, ~25%, ~50%, ~75%, ~100%, >100%)
595
            blink(i);
596
            // wait between readouts
597
            _delay_s(); _delay_s();
598
        }
599
#endif // ifdef BATTCHECK
600
        else {  // Regular non-hidden solid mode
601
            set_mode(mode_idx);
602
            // This part of the code will mostly replace the WDT tick code.
603
#ifdef NON_WDT_TURBO
604
            // Do some magic here to handle turbo step-down
605
            //if (ticks < 255) ticks++;  // don't roll over
606
            ticks ++;  // actually, we don't care about roll-over prevention
607
            if ((ticks > TURBO_TIMEOUT) 
608
                    && (output == TURBO)) {
609
                mode_idx = solid_modes - 2; // step down to second-highest mode
610
                set_mode(mode_idx);
611
                save_state();
612
            }
613
#endif
614
            // Otherwise, just sleep.
615
            _delay_ms(500);
616
617
            // If we got this far, the user has stopped fast-pressing.
618
            // So, don't enter config mode.
619
            fast_presses = 0;
620
        }
621
#ifdef VOLTAGE_MON
622
#if 1
623
        if (ADCSRA & (1 << ADIF)) {  // if a voltage reading is ready
624
            voltage = ADCH; // get_voltage();
625
            // See if voltage is lower than what we were looking for
626
            //if (voltage < ((mode_idx <= 1) ? ADC_CRIT : ADC_LOW)) {
627
            if (voltage < ADC_LOW) {
628
                lowbatt_cnt ++;
629
            } else {
630
                lowbatt_cnt = 0;
631
            }
632
            // See if it's been low for a while, and maybe step down
633
            if (lowbatt_cnt >= 8) {
634
                // DEBUG: blink on step-down:
635
                //set_output(0,0);  _delay_ms(100);
636
                i = mode_idx; // save space by not accessing mode_idx more than necessary
637
                // properly track hidden vs normal modes
638
                if (i >= solid_modes) {
639
                    // step down from blinky modes to medium
640
                    i = 2;
641
                } else if (i > 0) {
642
                    // step down from solid modes one at a time
643
                    i -= 1;
644
                } else { // Already at the lowest mode
645
                    i = 0;
646
                    // Turn off the light
647
                    set_output(0,0);
648
                    // Power down as many components as possible
649
                    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
650
                    sleep_mode();
651
                }
652
                set_mode(i);
653
                mode_idx = i;
654
                save_state();
655
                lowbatt_cnt = 0;
656
                // Wait at least 2 seconds before lowering the level again
657
                _delay_ms(250);  // this will interrupt blinky modes
658
            }
659
660
            // Make sure conversion is running for next time through
661
            ADCSRA |= (1 << ADSC);
662
        }
663
#endif
664
#endif  // ifdef VOLTAGE_MON
665
        //sleep_mode();  // incompatible with blinky modes
666
667
        // If we got this far, the user has stopped fast-pressing.
668
        // So, don't enter config mode.
669
        //fast_presses = 0;  // doesn't interact well with strobe, too fast
670
    }
671
672
    //return 0; // Standard Return Code
673
}