~gabe/flashlight-firmware/anduril2

« back to all changes in this revision

Viewing changes to pilotdog68/xintd-x3/xintd-x3.c

  • Committer: Selene Scriven
  • Date: 2016-11-29 22:51:09 UTC
  • mto: This revision was merged to the branch mainline in revision 176.
  • Revision ID: ubuntu@toykeeper.net-20161129225109-oab58sah3mb7mk1j
Copied biscotti.c to gchart/babka/babka.c

Show diffs side-by-side

added added

removed removed

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