~gabe/flashlight-firmware/anduril2

« back to all changes in this revision

Viewing changes to ToyKeeper/bistro/bistro.c

  • Committer: Selene Scriven
  • Date: 2015-10-08 03:36:32 UTC
  • mfrom: (150.1.12 sandbox)
  • Revision ID: ubuntu@toykeeper.net-20151008033632-qzq66vm22gcj94vg
merged TK refactoring effort and bistro project from sandbox:
  - reworking how common code is shared (in headers)
  - made battcheck output more values (and has more reference measurements too)
  - added new 'bistro' project
  - reworked blf-a6 to use new refactored base code
  - reworked s7 to use new refactored base code, including volts+tenths battcheck
  - made level_calc.py able to use several different curve shapes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * "Bistro" firmware
 
3
 * This code runs on a single-channel or dual-channel driver (FET+7135)
 
4
 * with an attiny25/45/85 MCU and a capacitor to measure offtime (OTC).
 
5
 *
 
6
 * Copyright (C) 2015 Selene Scriven
 
7
 *
 
8
 * This program is free software: you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation, either version 3 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 *
 
22
 * ATTINY25/45/85 Diagram
 
23
 *           ----
 
24
 *         -|1  8|- VCC
 
25
 *     OTC -|2  7|- Voltage ADC
 
26
 *  Star 3 -|3  6|- PWM (FET, optional)
 
27
 *     GND -|4  5|- PWM (1x7135)
 
28
 *           ----
 
29
 *
 
30
 * FUSES
 
31
 *      I use these fuse settings on attiny25
 
32
 *      Low:  0xd2
 
33
 *      High: 0xde
 
34
 *      Ext:  0xff
 
35
 *
 
36
 *      For more details on these settings:
 
37
 *      http://www.engbedded.com/cgi-bin/fcx.cgi?P_PREV=ATtiny25&P=ATtiny25&M_LOW_0x3F=0x12&M_HIGH_0x07=0x06&M_HIGH_0x20=0x00&B_SPIEN=P&B_SUT0=P&B_CKSEL3=P&B_CKSEL2=P&B_CKSEL0=P&B_BODLEVEL0=P&V_LOW=E2&V_HIGH=DE&V_EXTENDED=FF
 
38
 *
 
39
 * STARS
 
40
 *      Star 3 = unused
 
41
 *
 
42
 * CALIBRATION
 
43
 *
 
44
 *   To find out what values to use, flash the driver with battcheck.hex
 
45
 *   and hook the light up to each voltage you need a value for.  This is
 
46
 *   much more reliable than attempting to calculate the values from a
 
47
 *   theoretical formula.
 
48
 *
 
49
 *   Same for off-time capacitor values.  Measure, don't guess.
 
50
 */
 
51
// Choose your MCU here, or in the build script
 
52
//#define ATTINY 13
 
53
//#define ATTINY 25
 
54
// FIXME: make 1-channel vs 2-channel power a single #define option
 
55
#define FET_7135_LAYOUT  // specify an I/O pin layout
 
56
// Also, assign I/O pins in this file:
 
57
#include "../tk-attiny.h"
 
58
 
 
59
/*
 
60
 * =========================================================================
 
61
 * Settings to modify per driver
 
62
 */
 
63
 
 
64
// FIXME: make 1-channel vs 2-channel power a single #define option
 
65
//#define FAST 0x23           // fast PWM channel 1 only
 
66
//#define PHASE 0x21          // phase-correct PWM channel 1 only
 
67
#define FAST 0xA3           // fast PWM both channels
 
68
#define PHASE 0xA1          // phase-correct PWM both channels
 
69
 
 
70
#define VOLTAGE_MON         // Comment out to disable LVP
 
71
 
 
72
#define OFFTIM3             // Use short/med/long off-time presses
 
73
                            // instead of just short/long
 
74
 
 
75
// comment out to use extended config mode instead of a solderable star
 
76
// (controls whether mode memory is on the star or if it's a setting in config mode)
 
77
//#define CONFIG_STARS
 
78
 
 
79
// ../../bin/level_calc.py 64 1 10 1400 y 3 0.25 140
 
80
#define RAMP_SIZE  64
 
81
// log curve
 
82
//#define RAMP_7135  3,3,3,3,3,3,4,4,4,4,4,5,5,5,6,6,7,7,8,9,10,11,12,13,15,16,18,21,23,27,30,34,39,44,50,57,65,74,85,97,111,127,145,166,190,217,248,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0
 
83
//#define RAMP_FET   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,6,11,17,23,30,39,48,59,72,86,103,121,143,168,197,255
 
84
// x**2 curve
 
85
//#define RAMP_7135  3,5,8,12,17,24,32,41,51,63,75,90,105,121,139,158,178,200,223,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,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
 
86
//#define RAMP_FET   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,6,9,12,16,19,22,26,30,33,37,41,45,50,54,59,63,68,73,78,84,89,94,100,106,111,117,123,130,136,142,149,156,162,169,176,184,191,198,206,214,221,255
 
87
// x**3 curve
 
88
#define RAMP_7135  3,3,4,5,7,8,10,13,16,20,25,30,36,42,50,59,68,78,90,103,116,131,148,165,184,204,226,249,255,255,255,255,255,255,255,255,255,255,255,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
 
89
#define RAMP_FET   0,0,0,0,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,7,10,13,16,20,24,28,32,36,41,46,51,56,61,67,73,80,86,93,100,107,115,123,131,139,148,157,166,176,186,196,207,218,255
 
90
// x**5 curve
 
91
//#define RAMP_7135  3,3,3,4,4,5,5,6,7,8,10,11,13,15,18,21,24,28,33,38,44,50,57,66,75,85,96,108,122,137,154,172,192,213,237,255,255,255,255,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
 
92
//#define RAMP_FET   0,0,0,0,0,0,0,0,0,0,0,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,6,9,13,17,21,25,30,35,41,47,53,60,67,75,83,91,101,111,121,132,144,156,169,183,198,213,255
 
93
 
 
94
// output to use for blinks on battery check mode
 
95
#define BLINK_BRIGHTNESS    RAMP_SIZE/4
 
96
 
 
97
// uncomment to ramp up/down to a mode instead of jumping directly
 
98
#define SOFT_START
 
99
 
 
100
// Mode group 1
 
101
#define NUM_MODES1          7
 
102
// PWM levels for the big circuit (FET or Nx7135)
 
103
#define MODES_G1            1,10,21,32,43,53,64
 
104
// PWM speed for each mode
 
105
#define MODES_PWM1          PHASE,FAST,FAST,FAST,FAST,FAST,PHASE
 
106
// Mode group 2
 
107
#define NUM_MODES2          4
 
108
#define MODES_G2            10,28,46,64
 
109
#define MODES_PWM2          FAST,FAST,FAST,PHASE
 
110
// Hidden modes are *before* the lowest (moon) mode, and should be specified
 
111
// in reverse order.  So, to go backward from moon to turbo to strobe to
 
112
// battcheck, use BATTCHECK,STROBE,TURBO .
 
113
#define NUM_HIDDEN          5
 
114
#define HIDDENMODES         BIKING_STROBE,BATTCHECK,POLICE_STROBE,RAMP,TURBO
 
115
#define HIDDENMODES_PWM     PHASE,PHASE,PHASE,PHASE,PHASE
 
116
#define HIDDENMODES_ALT     0,0,0,0,0   // Zeroes, same length as NUM_HIDDEN
 
117
 
 
118
#define TURBO     RAMP_SIZE       // Convenience code for turbo mode
 
119
#define BATTCHECK 254       // Convenience code for battery check mode
 
120
// Uncomment to enable tactical strobe mode
 
121
#define STROBE    253       // Convenience code for strobe mode
 
122
// Uncomment to unable a 2-level stutter beacon instead of a tactical strobe
 
123
#define BIKING_STROBE 252   // Convenience code for biking strobe mode
 
124
// comment out to use minimal version instead (smaller)
 
125
#define FULL_BIKING_STROBE
 
126
#define RAMP 251   // Convenience code for biking strobe mode
 
127
#define POLICE_STROBE 250
 
128
 
 
129
#define NON_WDT_TURBO            // enable turbo step-down without WDT
 
130
// How many timer ticks before before dropping down.
 
131
// Each timer tick is 500ms, so "60" would be a 30-second stepdown.
 
132
// Max value of 255 unless you change "ticks"
 
133
#define TURBO_TIMEOUT       90
 
134
 
 
135
// Calibrate voltage and OTC in this file:
 
136
#include "../tk-calibration.h"
 
137
 
 
138
/*
 
139
 * =========================================================================
 
140
 */
 
141
 
 
142
// Ignore a spurious warning, we did the cast on purpose
 
143
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
 
144
 
 
145
#include <avr/pgmspace.h>
 
146
//#include <avr/io.h>
 
147
//#include <avr/interrupt.h>
 
148
#include <avr/eeprom.h>
 
149
#include <avr/sleep.h>
 
150
//#include <avr/power.h>
 
151
 
 
152
#define OWN_DELAY           // Don't use stock delay functions.
 
153
#define USE_DELAY_S         // Also use _delay_s(), not just _delay_ms()
 
154
#include "../tk-delay.h"
 
155
#define USE_BATTCHECK
 
156
//#define BATTCHECK_4bars
 
157
//#define BATTCHECK_8bars
 
158
#define BATTCHECK_VpT
 
159
#define BLINK_SPEED 500
 
160
#include "../tk-voltage.h"
 
161
 
 
162
/*
 
163
 * global variables
 
164
 */
 
165
 
 
166
// Config / state variables
 
167
uint8_t eepos = 0;
 
168
uint8_t memory = 0;        // mode memory, or not (set via soldered star)
 
169
uint8_t modegroup = 0;     // which mode group (set above in #defines)
 
170
#ifdef OFFTIM3
 
171
uint8_t offtim3 = 1;       // enable medium-press?
 
172
#endif
 
173
uint8_t mode_idx = 0;      // current or last-used mode number
 
174
// counter for entering config mode
 
175
// (needs to be remembered while off, but only for up to half a second)
 
176
uint8_t fast_presses __attribute__ ((section (".noinit")));
 
177
 
 
178
// NOTE: Only '1' is known to work; -1 will probably break and is untested.
 
179
// In other words, short press goes to the next (higher) mode,
 
180
// medium press goes to the previous (lower) mode.
 
181
#define mode_dir 1
 
182
// total length of current mode group's array
 
183
uint8_t mode_cnt;
 
184
// number of regular non-hidden modes in current mode group
 
185
uint8_t solid_modes;
 
186
// number of hidden modes in the current mode group
 
187
// (hardcoded because both groups have the same hidden modes)
 
188
//uint8_t hidden_modes = NUM_HIDDEN;  // this is never used
 
189
 
 
190
 
 
191
// Modes (gets set when the light starts up based on saved config values)
 
192
PROGMEM const uint8_t ramp_7135[] = { RAMP_7135 };
 
193
PROGMEM const uint8_t ramp_FET[]  = { RAMP_FET };
 
194
 
 
195
PROGMEM const uint8_t modes_g1[] = { MODES_G1, HIDDENMODES };
 
196
PROGMEM const uint8_t modes_g2[] = { MODES_G2, HIDDENMODES };
 
197
const uint8_t *modes;  // gets pointed at whatever group is current
 
198
 
 
199
PROGMEM const uint8_t modes_pwm1[] = { MODES_PWM1, HIDDENMODES_PWM };
 
200
PROGMEM const uint8_t modes_pwm2[] = { MODES_PWM2, HIDDENMODES_PWM };
 
201
const uint8_t *modes_pwm;
 
202
 
 
203
void save_mode() {  // save the current mode index (with wear leveling)
 
204
    uint8_t oldpos=eepos;
 
205
 
 
206
    eepos = (eepos+1) & ((EEPSIZE/2)-1); // wear leveling, use next cell
 
207
 
 
208
    eeprom_write_byte((uint8_t *)(eepos), mode_idx);      // save current state
 
209
    eeprom_write_byte((uint8_t *)(oldpos), 0xff);    // erase old state
 
210
}
 
211
 
 
212
#define FIRSTBOOT 0b01010101
 
213
#define OPT_firstboot (EEPSIZE-1)
 
214
#define OPT_modegroup (EEPSIZE-2)
 
215
#define OPT_memory (EEPSIZE-3)
 
216
#define OPT_offtim3 (EEPSIZE-4)
 
217
void save_state() {  // central method for writing complete state
 
218
    save_mode();
 
219
    eeprom_write_byte((uint8_t *)OPT_firstboot, FIRSTBOOT);
 
220
    eeprom_write_byte((uint8_t *)OPT_modegroup, modegroup);
 
221
    eeprom_write_byte((uint8_t *)OPT_memory, memory);
 
222
#ifdef OFFTIM3
 
223
    eeprom_write_byte((uint8_t *)OPT_offtim3, offtim3);
 
224
#endif
 
225
}
 
226
 
 
227
void restore_state() {
 
228
    uint8_t eep;
 
229
 
 
230
    // check if this is the first time we have powered on
 
231
    eep = eeprom_read_byte((uint8_t *)OPT_firstboot);
 
232
    if (eep != FIRSTBOOT) {
 
233
        modegroup = 0;
 
234
        memory = 0;
 
235
#ifdef OFFTIM3
 
236
        offtim3 = 1;
 
237
#endif
 
238
        save_state();
 
239
        return;
 
240
    }
 
241
 
 
242
    // find the mode index data
 
243
    for(eepos=0; eepos<(EEPSIZE/2); eepos++) {
 
244
        eep = eeprom_read_byte((const uint8_t *)eepos);
 
245
        if (eep != 0xff) {
 
246
            mode_idx = eep;
 
247
            break;
 
248
        }
 
249
    }
 
250
 
 
251
    // load other config values
 
252
    modegroup = eeprom_read_byte((uint8_t *)OPT_modegroup);
 
253
    memory    = eeprom_read_byte((uint8_t *)OPT_memory);
 
254
#ifdef OFFTIM3
 
255
    offtim3   = eeprom_read_byte((uint8_t *)OPT_offtim3);
 
256
#endif
 
257
 
 
258
    // unnecessary, save_state handles wrap-around
 
259
    // (and we don't really care about it skipping cell 0 once in a while)
 
260
    //else eepos=0;
 
261
}
 
262
 
 
263
inline void next_mode() {
 
264
    mode_idx += 1;
 
265
    if (mode_idx >= solid_modes) {
 
266
        // Wrap around, skipping the hidden modes
 
267
        // (note: this also applies when going "forward" from any hidden mode)
 
268
        mode_idx = 0;
 
269
    }
 
270
}
 
271
 
 
272
#ifdef OFFTIM3
 
273
inline void prev_mode() {
 
274
    if (mode_idx == solid_modes) {
 
275
        // If we hit the end of the hidden modes, go back to moon
 
276
        mode_idx = 0;
 
277
    } else if (mode_idx > 0) {
 
278
        // Regular mode: is between 1 and TOTAL_MODES
 
279
        mode_idx -= 1;
 
280
    } else {
 
281
        // Otherwise, wrap around (this allows entering hidden modes)
 
282
        mode_idx = mode_cnt - 1;
 
283
    }
 
284
}
 
285
#endif
 
286
 
 
287
#ifdef CONFIG_STARS
 
288
inline void check_stars() {
 
289
    // Configure options based on stars
 
290
    // 0 being low for soldered, 1 for pulled-up for not soldered
 
291
#if 0  // not implemented, STAR2_PIN is used for second PWM channel
 
292
    // Moon
 
293
    // enable moon mode?
 
294
    if ((PINB & (1 << STAR2_PIN)) == 0) {
 
295
        modes[mode_cnt++] = MODE_MOON;
 
296
    }
 
297
#endif
 
298
#if 0  // Mode order not as important as mem/no-mem
 
299
    // Mode order
 
300
    if ((PINB & (1 << STAR3_PIN)) == 0) {
 
301
        // High to Low
 
302
        mode_dir = -1;
 
303
    } else {
 
304
        mode_dir = 1;
 
305
    }
 
306
#endif
 
307
    // Memory
 
308
    if ((PINB & (1 << STAR3_PIN)) == 0) {
 
309
        memory = 1;  // solder to enable memory
 
310
    } else {
 
311
        memory = 0;  // unsolder to disable memory
 
312
    }
 
313
}
 
314
#endif  // ifdef CONFIG_STARS
 
315
 
 
316
void count_modes() {
 
317
    /*
 
318
     * Determine how many solid and hidden modes we have.
 
319
     * The modes_pwm array should have several values for regular modes
 
320
     * then some values for hidden modes.
 
321
     *
 
322
     * (this matters because we have more than one set of modes to choose
 
323
     *  from, so we need to count at runtime)
 
324
     */
 
325
    if (modegroup == 0) {
 
326
        solid_modes = NUM_MODES1;
 
327
        modes = modes_g1;
 
328
        modes_pwm = modes_pwm1;
 
329
    } else {
 
330
        solid_modes = NUM_MODES2;
 
331
        modes = modes_g2;
 
332
        modes_pwm = modes_pwm2;
 
333
    }
 
334
    mode_cnt = solid_modes + NUM_HIDDEN;
 
335
}
 
336
 
 
337
void set_output(uint8_t pwm1, uint8_t pwm2) {
 
338
    // Need PHASE to properly turn off the light
 
339
    if ((pwm1==0) && (pwm2==0)) {
 
340
        TCCR0A = PHASE;
 
341
    }
 
342
    PWM_LVL = pwm1;
 
343
    ALT_PWM_LVL = pwm2;
 
344
}
 
345
 
 
346
void set_level(uint8_t level) {
 
347
    if (level == 0) {
 
348
        set_output(0,0);
 
349
    } else {
 
350
        level -= 1;
 
351
        set_output(pgm_read_byte(ramp_FET + level),
 
352
                   pgm_read_byte(ramp_7135 + level));
 
353
    }
 
354
}
 
355
 
 
356
void set_mode(uint8_t mode) {
 
357
#ifdef SOFT_START
 
358
    static uint8_t actual_level = 0;
 
359
    uint8_t target_level = pgm_read_byte(modes + mode);
 
360
    int8_t shift_amount;
 
361
    int8_t diff;
 
362
    do {
 
363
        // TODO: clean out these old implementation ideas
 
364
        //shift_amount = ((target_level - actual_level) >> 2);
 
365
        //shift_amount = ((target_level - actual_level) >> 2) | (target_level!=actual_level);
 
366
        //if ((target_level != actual_level) && (! shift_amount)) { shift_amount = 1; }
 
367
        //if (target_level != actual_level) { shift_amount |= 1; }
 
368
        //shift_amount |= (target_level != actual_level);
 
369
        diff = target_level - actual_level;
 
370
        shift_amount = (diff >> 2) | (diff!=0);
 
371
        actual_level += shift_amount;
 
372
        /*
 
373
        if (target_level > actual_level) {
 
374
            //shift_amount = 1 + ((target_level - actual_level) >> 2);
 
375
            actual_level += 1 + shift_amount;
 
376
            //actual_level ++;
 
377
        } else if (target_level < actual_level) {
 
378
            //shift_amount = 1 + ((actual_level - target_level) >> 2);
 
379
            actual_level -= 1 + shift_amount;
 
380
            //actual_level --;
 
381
        }
 
382
        */
 
383
        //set_level(pgm_read_byte(modes + mode));
 
384
        //set_level(pgm_read_byte(modes + actual_mode));
 
385
        set_level(actual_level);
 
386
        //_delay_ms(RAMP_SIZE/20);
 
387
        _delay_ms(RAMP_SIZE/4);
 
388
    } while (target_level != actual_level);
 
389
#else
 
390
    //TCCR0A = pgm_read_byte(modes_pwm + mode);
 
391
    //set_output(pgm_read_byte(modesNx + mode), pgm_read_byte(modes1x + mode));
 
392
    set_level(pgm_read_byte(modes + mode));
 
393
#endif  // SOFT_START
 
394
}
 
395
 
 
396
void blink(uint8_t val, uint16_t speed)
 
397
{
 
398
    for (; val>0; val--)
 
399
    {
 
400
        /*
 
401
        set_output(BLINK_BRIGHTNESS);
 
402
        _delay_ms(BLINK_SPEED / 5);
 
403
        set_output(0,0);
 
404
        _delay_ms(BLINK_SPEED * 4 / 5);
 
405
        */
 
406
        set_level(BLINK_BRIGHTNESS);
 
407
        _delay_ms(speed);
 
408
        set_level(0);
 
409
        _delay_ms(speed<<2);
 
410
    }
 
411
}
 
412
 
 
413
#ifndef CONFIG_STARS
 
414
void toggle(uint8_t *var, uint8_t num) {
 
415
    // Used for extended config mode
 
416
    // Changes the value of a config option, waits for the user to "save"
 
417
    // by turning the light off, then changes the value back in case they
 
418
    // didn't save.  Can be used repeatedly on different options, allowing
 
419
    // the user to change and save only one at a time.
 
420
    blink(num, BLINK_SPEED/8);  // indicate which option number this is
 
421
    *var ^= 1;
 
422
    save_state();
 
423
    // "buzz" for a while to indicate the active toggle window
 
424
    for(uint8_t i=0; i<32; i++) {
 
425
        set_level(RAMP_SIZE/8);
 
426
        _delay_ms(20);
 
427
        set_level(0);
 
428
        _delay_ms(20);
 
429
    }
 
430
    // if the user didn't click, reset the value and return
 
431
    *var ^= 1;
 
432
    save_state();
 
433
    _delay_s();
 
434
}
 
435
#endif // ifndef CONFIG_STARS
 
436
 
 
437
int main(void)
 
438
{
 
439
    uint8_t cap_val;
 
440
 
 
441
    // Read the off-time cap *first* to get the most accurate reading
 
442
    // Start up ADC for capacitor pin
 
443
    DIDR0 |= (1 << CAP_DIDR);                           // disable digital input on ADC pin to reduce power consumption
 
444
    ADMUX  = (1 << V_REF) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3
 
445
    ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
 
446
 
 
447
    // Wait for completion
 
448
    while (ADCSRA & (1 << ADSC));
 
449
    // Start again as datasheet says first result is unreliable
 
450
    ADCSRA |= (1 << ADSC);
 
451
    // Wait for completion
 
452
    while (ADCSRA & (1 << ADSC));
 
453
    cap_val = ADCH; // save this for later
 
454
 
 
455
#ifdef CONFIG_STARS
 
456
    // All ports default to input, but turn pull-up resistors on for the stars (not the ADC input!  Made that mistake already)
 
457
    // only one star, because one is used for PWM channel 2
 
458
    // and the other is used for the off-time capacitor
 
459
    PORTB = (1 << STAR3_PIN);
 
460
#endif
 
461
 
 
462
    // Set PWM pin to output
 
463
    DDRB |= (1 << PWM_PIN);     // enable main channel
 
464
    DDRB |= (1 << ALT_PWM_PIN); // enable second channel
 
465
 
 
466
    // Set timer to do PWM for correct output pin and set prescaler timing
 
467
    //TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
 
468
    //TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
 
469
    TCCR0A = PHASE;
 
470
    // Set timer to do PWM for correct output pin and set prescaler timing
 
471
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
 
472
 
 
473
    // Read config values and saved state
 
474
#ifdef CONFIG_STARS
 
475
    check_stars();
 
476
#endif
 
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 (offtim3  &&  (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_mode();
 
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
    //blink(modegroup + 1, BLINK_SPEED/4);
 
530
 
 
531
    uint8_t output;
 
532
#ifdef NON_WDT_TURBO
 
533
    uint8_t ticks = 0;
 
534
#endif
 
535
#ifdef VOLTAGE_MON
 
536
    uint8_t lowbatt_cnt = 0;
 
537
    uint8_t i = 0;
 
538
    uint8_t voltage;
 
539
    // Make sure voltage reading is running for later
 
540
    ADCSRA |= (1 << ADSC);
 
541
#endif
 
542
    while(1) {
 
543
        output = pgm_read_byte(modes + mode_idx);
 
544
        if (fast_presses > 0x0f) {  // Config mode
 
545
            _delay_s();       // wait for user to stop fast-pressing button
 
546
            fast_presses = 0; // exit this mode after one use
 
547
            mode_idx = 0;
 
548
 
 
549
#ifdef CONFIG_STARS
 
550
            // Short/small version of the config mode
 
551
            // Toggle the mode group, blink, then exit
 
552
            modegroup ^= 1;
 
553
            save_state();
 
554
            count_modes();  // reconfigure without a power cycle
 
555
            blink(1, BLINK_SPEED/4);
 
556
#else
 
557
            // Longer/larger version of the config mode
 
558
            // Toggle the mode group, blink, un-toggle, continue
 
559
            toggle(&modegroup, 1);
 
560
 
 
561
            // Toggle memory, blink, untoggle, exit
 
562
            toggle(&memory, 2);
 
563
 
 
564
            // Toggle offtim3, blink, untoggle, exit
 
565
            toggle(&offtim3, 3);
 
566
#endif  // ifdef CONFIG_STARS
 
567
        }
 
568
#ifdef STROBE
 
569
        else if (output == STROBE) {
 
570
            // 10Hz tactical strobe
 
571
            set_level(RAMP_SIZE);
 
572
            _delay_ms(50);
 
573
            set_level(0);
 
574
            _delay_ms(50);
 
575
        }
 
576
#endif // ifdef STROBE
 
577
#ifdef POLICE_STROBE
 
578
        else if (output == POLICE_STROBE) {
 
579
            // police-like strobe
 
580
            for(i=0;i<8;i++) {
 
581
                set_level(RAMP_SIZE);
 
582
                _delay_ms(20);
 
583
                set_level(0);
 
584
                _delay_ms(40);
 
585
            }
 
586
            for(i=0;i<8;i++) {
 
587
                set_level(RAMP_SIZE);
 
588
                _delay_ms(40);
 
589
                set_level(0);
 
590
                _delay_ms(80);
 
591
            }
 
592
        }
 
593
#endif // ifdef POLICE_STROBE
 
594
#ifdef BIKING_STROBE
 
595
        else if (output == BIKING_STROBE) {
 
596
            // 2-level stutter beacon for biking and such
 
597
#ifdef FULL_BIKING_STROBE
 
598
            // normal version
 
599
            for(i=0;i<4;i++) {
 
600
                set_output(255,0);
 
601
                _delay_ms(5);
 
602
                set_output(0,255);
 
603
                _delay_ms(65);
 
604
            }
 
605
            _delay_ms(720);
 
606
#else
 
607
            // small/minimal version
 
608
            set_output(255,0);
 
609
            _delay_ms(10);
 
610
            set_output(0,255);
 
611
            _delay_s();
 
612
#endif
 
613
        }
 
614
#endif  // ifdef BIKING_STROBE
 
615
#ifdef RAMP
 
616
        else if (output == RAMP) {
 
617
            int8_t r;
 
618
            // simple ramping test
 
619
            for(r=1; r<=RAMP_SIZE; r++) {
 
620
                set_level(r);
 
621
                _delay_ms(25);
 
622
            }
 
623
            for(r=RAMP_SIZE; r>0; r--) {
 
624
                set_level(r);
 
625
                _delay_ms(25);
 
626
            }
 
627
        }
 
628
#endif  // ifdef RAMP
 
629
#ifdef BATTCHECK
 
630
        else if (output == BATTCHECK) {
 
631
#ifdef BATTCHECK_VpT
 
632
            // blink out volts and tenths
 
633
            uint8_t result = battcheck();
 
634
            blink(result >> 5, BLINK_SPEED/8);
 
635
            _delay_ms(BLINK_SPEED);
 
636
            blink(1,5);
 
637
            _delay_ms(BLINK_SPEED*3/2);
 
638
            blink(result & 0b00011111, BLINK_SPEED/8);
 
639
#else  // ifdef BATTCHECK_VpT
 
640
            // blink zero to five times to show voltage
 
641
            // (~0%, ~25%, ~50%, ~75%, ~100%, >100%)
 
642
            blink(battcheck(), BLINK_SPEED/8);
 
643
#endif  // ifdef BATTCHECK_VpT
 
644
            // wait between readouts
 
645
            _delay_s(); _delay_s();
 
646
        }
 
647
#endif // ifdef BATTCHECK
 
648
        else {  // Regular non-hidden solid mode
 
649
            set_mode(mode_idx);
 
650
            // This part of the code will mostly replace the WDT tick code.
 
651
#ifdef NON_WDT_TURBO
 
652
            // Do some magic here to handle turbo step-down
 
653
            //if (ticks < 255) ticks++;  // don't roll over
 
654
            ticks ++;  // actually, we don't care about roll-over prevention
 
655
            if ((ticks > TURBO_TIMEOUT) 
 
656
                    && (output == TURBO)) {
 
657
                mode_idx = solid_modes - 2; // step down to second-highest mode
 
658
                set_mode(mode_idx);
 
659
                save_mode();
 
660
            }
 
661
#endif
 
662
            // Otherwise, just sleep.
 
663
            _delay_ms(500);
 
664
 
 
665
            // If we got this far, the user has stopped fast-pressing.
 
666
            // So, don't enter config mode.
 
667
            fast_presses = 0;
 
668
        }
 
669
#ifdef VOLTAGE_MON
 
670
#if 1
 
671
        if (ADCSRA & (1 << ADIF)) {  // if a voltage reading is ready
 
672
            voltage = ADCH; // get_voltage();
 
673
            // See if voltage is lower than what we were looking for
 
674
            //if (voltage < ((mode_idx <= 1) ? ADC_CRIT : ADC_LOW)) {
 
675
            if (voltage < ADC_LOW) {
 
676
                lowbatt_cnt ++;
 
677
            } else {
 
678
                lowbatt_cnt = 0;
 
679
            }
 
680
            // See if it's been low for a while, and maybe step down
 
681
            if (lowbatt_cnt >= 8) {
 
682
                // DEBUG: blink on step-down:
 
683
                //set_level(0);  _delay_ms(100);
 
684
                i = mode_idx; // save space by not accessing mode_idx more than necessary
 
685
                // properly track hidden vs normal modes
 
686
                if (i >= solid_modes) {
 
687
                    // step down from blinky modes to medium
 
688
                    i = 2;
 
689
                } else if (i > 0) {
 
690
                    // step down from solid modes one at a time
 
691
                    i -= 1;
 
692
                } else { // Already at the lowest mode
 
693
                    i = 0;
 
694
                    // Turn off the light
 
695
                    set_level(0);
 
696
                    // Power down as many components as possible
 
697
                    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
698
                    sleep_mode();
 
699
                }
 
700
                set_mode(i);
 
701
                mode_idx = i;
 
702
                save_mode();
 
703
                lowbatt_cnt = 0;
 
704
                // Wait at least 2 seconds before lowering the level again
 
705
                _delay_ms(250);  // this will interrupt blinky modes
 
706
            }
 
707
 
 
708
            // Make sure conversion is running for next time through
 
709
            ADCSRA |= (1 << ADSC);
 
710
        }
 
711
#endif
 
712
#endif  // ifdef VOLTAGE_MON
 
713
        //sleep_mode();  // incompatible with blinky modes
 
714
 
 
715
        // If we got this far, the user has stopped fast-pressing.
 
716
        // So, don't enter config mode.
 
717
        //fast_presses = 0;  // doesn't interact well with strobe, too fast
 
718
    }
 
719
 
 
720
    //return 0; // Standard Return Code
 
721
}