~toykeeper/flashlight-firmware/fsm

« back to all changes in this revision

Viewing changes to gchart/babka/babka.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
 * "Biscotti" firmware (attiny13a version of "Bistro")
 
3
 * This code runs on a single-channel driver with attiny13a MCU.
 
4
 * It is intended specifically for nanjg 105d drivers from Convoy.
 
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
 * ATTINY13 Diagram
 
23
 *           ----
 
24
 *         -|1  8|- VCC
 
25
 *         -|2  7|- Voltage ADC
 
26
 *         -|3  6|-
 
27
 *     GND -|4  5|- PWM (Nx7135)
 
28
 *           ----
 
29
 *
 
30
 * FUSES
 
31
 *      I use these fuse settings on attiny13
 
32
 *      Low:  0x75
 
33
 *      High: 0xff
 
34
 *
 
35
 * CALIBRATION
 
36
 *
 
37
 *   To find out what values to use, flash the driver with battcheck.hex
 
38
 *   and hook the light up to each voltage you need a value for.  This is
 
39
 *   much more reliable than attempting to calculate the values from a
 
40
 *   theoretical formula.
 
41
 *
 
42
 *   Same for off-time capacitor values.  Measure, don't guess.
 
43
 */
 
44
// Choose your MCU here, or in the build script
 
45
//#define ATTINY 13
 
46
//#define ATTINY 25
 
47
// FIXME: make 1-channel vs 2-channel power a single #define option
 
48
//#define FET_7135_LAYOUT  // specify an I/O pin layout
 
49
#define NANJG_LAYOUT  // specify an I/O pin layout
 
50
// Also, assign I/O pins in this file:
 
51
#include "tk-attiny.h"
 
52
 
 
53
/*
 
54
 * =========================================================================
 
55
 * Settings to modify per driver
 
56
 */
 
57
 
 
58
// FIXME: make 1-channel vs 2-channel power a single #define option
 
59
//#define FAST 0x23           // fast PWM channel 1 only
 
60
//#define PHASE 0x21          // phase-correct PWM channel 1 only
 
61
#define FAST 0xA3           // fast PWM both channels
 
62
#define PHASE 0xA1          // phase-correct PWM both channels
 
63
 
 
64
#define VOLTAGE_MON         // Comment out to disable LVP
 
65
 
 
66
//#define OFFTIM3             // Use short/med/long off-time presses
 
67
                            // instead of just short/long
 
68
 
 
69
// ../../bin/level_calc.py 64 1 10 1300 y 3 0.23 140
 
70
#define RAMP_SIZE  7
 
71
// log curve
 
72
//#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
 
73
//#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
 
74
// x**2 curve
 
75
//#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
 
76
//#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
 
77
// x**3 curve
 
78
//#define RAMP_7135  3,3,4,5,6,8,10,12,15,19,23,28,33,40,47,55,63,73,84,95,108,122,137,153,171,190,210,232,255,255,255,255,255,255,255,255,255,255,255,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
 
79
//#define RAMP_FET   6,12,34,108,255
 
80
// level_calc.py 1 4 7135 9 8 700
 
81
// level_calc.py 1 3 7135 9 8 700
 
82
#define RAMP_FET   1,10,42,75,122,133,255
 
83
// x**5 curve
 
84
//#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
 
85
//#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
 
86
 
 
87
// uncomment to ramp up/down to a mode instead of jumping directly
 
88
//#define SOFT_START
 
89
 
 
90
// Enable battery indicator mode?
 
91
#define USE_BATTCHECK
 
92
// Choose a battery indicator style
 
93
#define BATTCHECK_4bars  // up to 4 blinks
 
94
//#define BATTCHECK_8bars  // up to 8 blinks
 
95
//#define BATTCHECK_VpT  // Volts + tenths
 
96
 
 
97
// output to use for blinks on battery check (and other modes)
 
98
//#define BLINK_BRIGHTNESS    RAMP_SIZE/4
 
99
#define BLINK_BRIGHTNESS    3
 
100
// ms per normal-speed blink
 
101
#define BLINK_SPEED         750
 
102
 
 
103
// Hidden modes are *before* the lowest (moon) mode, and should be specified
 
104
// in reverse order.  So, to go backward from moon to turbo to strobe to
 
105
// battcheck, use BATTCHECK,STROBE,TURBO .
 
106
//#define HIDDENMODES         BATTCHECK,STROBE,TURBO
 
107
 
 
108
#define TURBO     RAMP_SIZE       // Convenience code for turbo mode
 
109
#define BATTCHECK 254       // Convenience code for battery check mode
 
110
#define GROUP_SELECT_MODE 253
 
111
//#define TEMP_CAL_MODE 252
 
112
// Uncomment to enable tactical strobe mode
 
113
#define STROBE    251       // Convenience code for strobe mode
 
114
// Uncomment to unable a 2-level stutter beacon instead of a tactical strobe
 
115
#define BIKING_STROBE 250   // Convenience code for biking strobe mode
 
116
// comment out to use minimal version instead (smaller)
 
117
#define FULL_BIKING_STROBE
 
118
//#define RAMP 249       // ramp test mode for tweaking ramp shape
 
119
//#define POLICE_STROBE 248
 
120
//#define RANDOM_STROBE 247
 
121
#define SOS 246
 
122
 
 
123
// thermal step-down
 
124
//#define TEMPERATURE_MON
 
125
 
 
126
// Calibrate voltage and OTC in this file:
 
127
#include "tk-calibration.h"
 
128
 
 
129
/*
 
130
 * =========================================================================
 
131
 */
 
132
 
 
133
// Ignore a spurious warning, we did the cast on purpose
 
134
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
 
135
 
 
136
#include <avr/pgmspace.h>
 
137
//#include <avr/io.h>
 
138
#include <avr/interrupt.h>
 
139
#include <avr/eeprom.h>
 
140
#include <avr/sleep.h>
 
141
//#include <avr/power.h>
 
142
#include <string.h>
 
143
 
 
144
#define OWN_DELAY           // Don't use stock delay functions.
 
145
#define USE_DELAY_S         // Also use _delay_s(), not just _delay_ms()
 
146
#include "tk-delay.h"
 
147
 
 
148
#include "tk-voltage.h"
 
149
 
 
150
#ifdef RANDOM_STROBE
 
151
#include "tk-random.h"
 
152
#endif
 
153
 
 
154
/*
 
155
 * global variables
 
156
 */
 
157
 
 
158
// Config option variables
 
159
#ifdef USE_FIRSTBOOT
 
160
#define FIRSTBOOT 0b01010101
 
161
uint8_t firstboot = FIRSTBOOT;  // detect initial boot or factory reset
 
162
#endif
 
163
uint8_t modegroup = 0;     // which mode group (set above in #defines)
 
164
#define enable_moon 0   // Should we add moon to the set of modes?
 
165
#define reverse_modes 0 // flip the mode order?
 
166
uint8_t memory = 0;        // mode memory, or not (set via soldered star)
 
167
#ifdef OFFTIM3
 
168
uint8_t offtim3 = 1;       // enable medium-press?
 
169
#endif
 
170
#ifdef TEMPERATURE_MON
 
171
uint8_t maxtemp = 79;      // temperature step-down threshold
 
172
#endif
 
173
#define muggle_mode 0   // simple mode designed for muggles
 
174
// Other state variables
 
175
uint8_t mode_override = 0; // do we need to enter a special mode?
 
176
uint8_t mode_idx = 0;      // current or last-used mode number
 
177
uint8_t eepos = 0;
 
178
// counter for entering config mode
 
179
// (needs to be remembered while off, but only for up to half a second)
 
180
uint8_t fast_presses __attribute__ ((section (".noinit")));
 
181
 
 
182
// total length of current mode group's array
 
183
#ifdef OFFTIM3
 
184
uint8_t mode_cnt;
 
185
#endif
 
186
// number of regular non-hidden modes in current mode group
 
187
uint8_t solid_modes;
 
188
// number of hidden modes in the current mode group
 
189
// (hardcoded because both groups have the same hidden modes)
 
190
//uint8_t hidden_modes = NUM_HIDDEN;  // this is never used
 
191
 
 
192
 
 
193
//PROGMEM const uint8_t hiddenmodes[] = { HIDDENMODES };
 
194
// default values calculated by group_calc.py
 
195
// Each group must be 8 values long, but can be cut short with a zero.
 
196
#define NUM_MODEGROUPS 12  // don't count muggle mode
 
197
PROGMEM const uint8_t modegroups[] = {
 
198
     1,  2,  3,  5,  7,  STROBE, BIKING_STROBE, BATTCHECK,
 
199
     1,  2,  3,  5,  7,  0,  0,  0,
 
200
     7,  5,  3,  2,  1,  0,  0,  0,
 
201
     2,  4,  7,  STROBE, BIKING_STROBE, BATTCHECK, SOS,  0,
 
202
     2,  4,  7,  0,  0,  0,  0,  0,
 
203
     7,  4,  2,  0,  0,  0,  0,  0,
 
204
     1,  2,  3,  6,  STROBE, BIKING_STROBE, BATTCHECK, SOS,
 
205
     1,  2,  3,  6,  0,  0,  0,  0,
 
206
     6,  3,  2,  1,  0,  0,  0,  0,
 
207
     2,  3,  5,  7,  0,  0,  0,  0,
 
208
     7,  4, STROBE,0,0,  0,  0,  0,
 
209
     7,  0,
 
210
};
 
211
uint8_t modes[] = { 0,0,0,0,0,0,0,0, };  // make sure this is long enough...
 
212
 
 
213
// Modes (gets set when the light starts up based on saved config values)
 
214
//PROGMEM const uint8_t ramp_7135[] = { RAMP_7135 };
 
215
PROGMEM const uint8_t ramp_FET[]  = { RAMP_FET };
 
216
 
 
217
void save_mode() {  // save the current mode index (with wear leveling)
 
218
    uint8_t oldpos=eepos;
 
219
 
 
220
    eepos = (eepos+1) & ((EEPSIZE/2)-1);  // wear leveling, use next cell
 
221
    /*
 
222
    eepos ++;
 
223
    if (eepos > (EEPSIZE-4)) {
 
224
        eepos = 0;
 
225
    }
 
226
    */
 
227
 
 
228
    eeprom_write_byte((uint8_t *)(eepos), mode_idx);  // save current state
 
229
    eeprom_write_byte((uint8_t *)(oldpos), 0xff);     // erase old state
 
230
}
 
231
 
 
232
//#define OPT_firstboot (EEPSIZE-1)
 
233
#define OPT_modegroup (EEPSIZE-1)
 
234
#define OPT_memory (EEPSIZE-2)
 
235
//#define OPT_offtim3 (EEPSIZE-4)
 
236
//#define OPT_maxtemp (EEPSIZE-5)
 
237
#define OPT_mode_override (EEPSIZE-3)
 
238
//#define OPT_moon (EEPSIZE-7)
 
239
//#define OPT_revmodes (EEPSIZE-8)
 
240
//#define OPT_muggle (EEPSIZE-9)
 
241
void save_state() {  // central method for writing complete state
 
242
    save_mode();
 
243
#ifdef USE_FIRSTBOOT
 
244
    eeprom_write_byte((uint8_t *)OPT_firstboot, firstboot);
 
245
#endif
 
246
    eeprom_write_byte((uint8_t *)OPT_modegroup, modegroup);
 
247
    eeprom_write_byte((uint8_t *)OPT_memory, memory);
 
248
#ifdef OFFTIM3
 
249
    eeprom_write_byte((uint8_t *)OPT_offtim3, offtim3);
 
250
#endif
 
251
#ifdef TEMPERATURE_MON
 
252
    eeprom_write_byte((uint8_t *)OPT_maxtemp, maxtemp);
 
253
#endif
 
254
    eeprom_write_byte((uint8_t *)OPT_mode_override, mode_override);
 
255
    //eeprom_write_byte((uint8_t *)OPT_moon, enable_moon);
 
256
    //eeprom_write_byte((uint8_t *)OPT_revmodes, reverse_modes);
 
257
    //eeprom_write_byte((uint8_t *)OPT_muggle, muggle_mode);
 
258
}
 
259
 
 
260
inline void reset_state() {
 
261
    mode_idx = 0;
 
262
    modegroup = 0;
 
263
    save_state();
 
264
}
 
265
 
 
266
void restore_state() {
 
267
    uint8_t eep;
 
268
 
 
269
#ifdef USE_FIRSTBOOT
 
270
    // check if this is the first time we have powered on
 
271
    eep = eeprom_read_byte((uint8_t *)OPT_firstboot);
 
272
    if (eep != FIRSTBOOT) {
 
273
        // not much to do; the defaults should already be set
 
274
        // while defining the variables above
 
275
        save_state();
 
276
        return;
 
277
    }
 
278
#endif
 
279
 
 
280
    uint8_t first = 1;
 
281
    // find the mode index data
 
282
    for(eepos=0; eepos<(EEPSIZE-6); eepos++) {
 
283
        eep = eeprom_read_byte((const uint8_t *)eepos);
 
284
        if (eep != 0xff) {
 
285
            mode_idx = eep;
 
286
            first = 0;
 
287
            break;
 
288
        }
 
289
    }
 
290
    // if no mode_idx was found, assume this is the first boot
 
291
    if (first) {
 
292
        reset_state();
 
293
        return;
 
294
    }
 
295
 
 
296
    // load other config values
 
297
    modegroup = eeprom_read_byte((uint8_t *)OPT_modegroup);
 
298
    memory    = eeprom_read_byte((uint8_t *)OPT_memory);
 
299
#ifdef OFFTIM3
 
300
    offtim3   = eeprom_read_byte((uint8_t *)OPT_offtim3);
 
301
#endif
 
302
#ifdef TEMPERATURE_MON
 
303
    maxtemp   = eeprom_read_byte((uint8_t *)OPT_maxtemp);
 
304
#endif
 
305
    mode_override = eeprom_read_byte((uint8_t *)OPT_mode_override);
 
306
    //enable_moon   = eeprom_read_byte((uint8_t *)OPT_moon);
 
307
    //reverse_modes = eeprom_read_byte((uint8_t *)OPT_revmodes);
 
308
    //muggle_mode   = eeprom_read_byte((uint8_t *)OPT_muggle);
 
309
 
 
310
    // unnecessary, save_state handles wrap-around
 
311
    // (and we don't really care about it skipping cell 0 once in a while)
 
312
    //else eepos=0;
 
313
 
 
314
    if (modegroup >= NUM_MODEGROUPS) reset_state();
 
315
}
 
316
 
 
317
inline void next_mode() {
 
318
    mode_idx += 1;
 
319
    if (mode_idx >= solid_modes) {
 
320
        // Wrap around, skipping the hidden modes
 
321
        // (note: this also applies when going "forward" from any hidden mode)
 
322
        // FIXME? Allow this to cycle through hidden modes?
 
323
        mode_idx = 0;
 
324
    }
 
325
}
 
326
 
 
327
#ifdef OFFTIM3
 
328
inline void prev_mode() {
 
329
    // simple mode has no reverse
 
330
    //if (muggle_mode) { return next_mode(); }
 
331
 
 
332
    if (mode_idx == solid_modes) {
 
333
        // If we hit the end of the hidden modes, go back to moon
 
334
        mode_idx = 0;
 
335
    } else if (mode_idx > 0) {
 
336
        // Regular mode: is between 1 and TOTAL_MODES
 
337
        mode_idx -= 1;
 
338
    } else {
 
339
        // Otherwise, wrap around (this allows entering hidden modes)
 
340
        mode_idx = mode_cnt - 1;
 
341
    }
 
342
}
 
343
#endif
 
344
 
 
345
void count_modes() {
 
346
    /*
 
347
     * Determine how many solid and hidden modes we have.
 
348
     *
 
349
     * (this matters because we have more than one set of modes to choose
 
350
     *  from, so we need to count at runtime)
 
351
     */
 
352
    // copy config to local vars to avoid accidentally overwriting them in muggle mode
 
353
    // (also, it seems to reduce overall program size)
 
354
    uint8_t my_modegroup = modegroup;
 
355
    //uint8_t my_enable_moon = enable_moon;
 
356
    //uint8_t my_reverse_modes = reverse_modes;
 
357
 
 
358
    // override config if we're in simple mode
 
359
#if 0
 
360
    if (muggle_mode) {
 
361
        my_modegroup = NUM_MODEGROUPS;
 
362
        my_enable_moon = 0;
 
363
        my_reverse_modes = 0;
 
364
    }
 
365
#endif
 
366
 
 
367
    uint8_t *dest;
 
368
    const uint8_t *src = modegroups + (my_modegroup<<3);
 
369
    dest = modes;
 
370
 
 
371
    // Figure out how many modes are in this group
 
372
    //solid_modes = modegroup + 1;  // Assume group N has N modes
 
373
    // No, how about actually counting the modes instead?
 
374
    // (in case anyone changes the mode groups above so they don't form a triangle)
 
375
    for(solid_modes=0;
 
376
        (solid_modes<8) && pgm_read_byte(src);
 
377
        solid_modes++, src++ )
 
378
    {
 
379
        *dest++ = pgm_read_byte(src);
 
380
    }
 
381
 
 
382
    // add moon mode (or not) if config says to add it
 
383
#if 0
 
384
    if (my_enable_moon) {
 
385
        modes[0] = 1;
 
386
        dest ++;
 
387
    }
 
388
#endif
 
389
 
 
390
    // add regular modes
 
391
    //memcpy_P(dest, src, solid_modes);
 
392
    // add hidden modes
 
393
    //memcpy_P(dest + solid_modes, hiddenmodes, sizeof(hiddenmodes));
 
394
    // final count
 
395
#ifdef OFFTIM3
 
396
    //mode_cnt = solid_modes + sizeof(hiddenmodes);
 
397
    mode_cnt = solid_modes;
 
398
#endif
 
399
#if 0
 
400
    if (my_reverse_modes) {
 
401
        // TODO: yuck, isn't there a better way to do this?
 
402
        int8_t i;
 
403
        src += solid_modes;
 
404
        dest = modes;
 
405
        for(i=0; i<solid_modes; i++) {
 
406
            src --;
 
407
            *dest = pgm_read_byte(src);
 
408
            dest ++;
 
409
        }
 
410
        if (my_enable_moon) {
 
411
            *dest = 1;
 
412
        }
 
413
        mode_cnt --;  // get rid of last hidden mode, since it's a duplicate turbo
 
414
    }
 
415
#endif
 
416
#if 0
 
417
    if (my_enable_moon) {
 
418
        mode_cnt ++;
 
419
        solid_modes ++;
 
420
    }
 
421
#endif
 
422
}
 
423
 
 
424
#ifdef ALT_PWM_LVL
 
425
inline void set_output(uint8_t pwm1, uint8_t pwm2) {
 
426
#else
 
427
inline void set_output(uint8_t pwm1) {
 
428
#endif
 
429
    /* This is no longer needed since we always use PHASE mode.
 
430
    // Need PHASE to properly turn off the light
 
431
    if ((pwm1==0) && (pwm2==0)) {
 
432
        TCCR0A = PHASE;
 
433
    }
 
434
    */
 
435
    PWM_LVL = pwm1;
 
436
    #ifdef ALT_PWM_LVL
 
437
    ALT_PWM_LVL = pwm2;
 
438
    #endif
 
439
}
 
440
 
 
441
void set_level(uint8_t level) {
 
442
    if (level == 0) {
 
443
        //set_output(0,0);
 
444
        set_output(0);
 
445
    } else {
 
446
        level -= 1;
 
447
        if (level == 0) {
 
448
            // divide PWM speed by 8 for moon,
 
449
            // because the nanjg 105d chips are SLOW
 
450
            TCCR0B = 0x02;
 
451
        }
 
452
        if (level < 2) {
 
453
            // divide PWM speed by 2 for moon and low,
 
454
            // because the nanjg 105d chips are SLOW
 
455
            TCCR0A = PHASE;
 
456
        }
 
457
        //set_output(pgm_read_byte(ramp_FET  + level), 0);
 
458
        set_output(pgm_read_byte(ramp_FET  + level));
 
459
    }
 
460
}
 
461
 
 
462
void set_mode(uint8_t mode) {
 
463
#ifdef SOFT_START
 
464
    static uint8_t actual_level = 0;
 
465
    uint8_t target_level = mode;
 
466
    int8_t shift_amount;
 
467
    int8_t diff;
 
468
    do {
 
469
        diff = target_level - actual_level;
 
470
        shift_amount = (diff >> 2) | (diff!=0);
 
471
        actual_level += shift_amount;
 
472
        set_level(actual_level);
 
473
        //_delay_ms(RAMP_SIZE/20);  // slow ramp
 
474
        _delay_ms(RAMP_SIZE/4);  // fast ramp
 
475
    } while (target_level != actual_level);
 
476
#else
 
477
#define set_mode set_level
 
478
    //set_level(mode);
 
479
#endif  // SOFT_START
 
480
}
 
481
 
 
482
void blink(uint8_t val, uint16_t speed)
 
483
{
 
484
    for (; val>0; val--)
 
485
    {
 
486
        set_level(BLINK_BRIGHTNESS);
 
487
        _delay_ms(speed);
 
488
        set_level(0);
 
489
        _delay_ms(speed);
 
490
        _delay_ms(speed);
 
491
    }
 
492
}
 
493
 
 
494
#ifdef STROBE
 
495
inline void strobe(uint8_t ontime, uint8_t offtime) {
 
496
    uint8_t i;
 
497
    for(i=0;i<8;i++) {
 
498
        set_level(RAMP_SIZE);
 
499
        _delay_ms(ontime);
 
500
        set_level(0);
 
501
        _delay_ms(offtime);
 
502
    }
 
503
}
 
504
#endif
 
505
 
 
506
#ifdef SOS
 
507
inline void SOS_mode() {
 
508
#define SOS_SPEED 200
 
509
    blink(3, SOS_SPEED);
 
510
    _delay_ms(SOS_SPEED*5);
 
511
    blink(3, SOS_SPEED*5/2);
 
512
    //_delay_ms(SOS_SPEED);
 
513
    blink(3, SOS_SPEED);
 
514
    _delay_s(); _delay_s();
 
515
}
 
516
#endif
 
517
 
 
518
void toggle(uint8_t *var, uint8_t num) {
 
519
    // Used for config mode
 
520
    // Changes the value of a config option, waits for the user to "save"
 
521
    // by turning the light off, then changes the value back in case they
 
522
    // didn't save.  Can be used repeatedly on different options, allowing
 
523
    // the user to change and save only one at a time.
 
524
    blink(num, BLINK_SPEED/4);  // indicate which option number this is
 
525
    *var ^= 1;
 
526
    save_state();
 
527
    // "buzz" for a while to indicate the active toggle window
 
528
    blink(32, 500/32);
 
529
    /*
 
530
    for(uint8_t i=0; i<32; i++) {
 
531
        set_level(BLINK_BRIGHTNESS * 3 / 4);
 
532
        _delay_ms(30);
 
533
        set_level(0);
 
534
        _delay_ms(30);
 
535
    }
 
536
    */
 
537
    // if the user didn't click, reset the value and return
 
538
    *var ^= 1;
 
539
    save_state();
 
540
    _delay_s();
 
541
}
 
542
 
 
543
#ifdef TEMPERATURE_MON
 
544
uint8_t get_temperature() {
 
545
    ADC_on_temperature();
 
546
    // average a few values; temperature is noisy
 
547
    uint16_t temp = 0;
 
548
    uint8_t i;
 
549
    get_voltage();
 
550
    for(i=0; i<16; i++) {
 
551
        temp += get_voltage();
 
552
        _delay_ms(5);
 
553
    }
 
554
    temp >>= 4;
 
555
    return temp;
 
556
}
 
557
#endif  // TEMPERATURE_MON
 
558
 
 
559
#if 0  // there is no OTC
 
560
inline uint8_t read_otc() {
 
561
    // Read and return the off-time cap value
 
562
    // Start up ADC for capacitor pin
 
563
    // disable digital input on ADC pin to reduce power consumption
 
564
    DIDR0 |= (1 << CAP_DIDR);
 
565
    // 1.1v reference, left-adjust, ADC3/PB3
 
566
    ADMUX  = (1 << V_REF) | (1 << ADLAR) | CAP_CHANNEL;
 
567
    // enable, start, prescale
 
568
    ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;
 
569
 
 
570
    // Wait for completion
 
571
    while (ADCSRA & (1 << ADSC));
 
572
    // Start again as datasheet says first result is unreliable
 
573
    ADCSRA |= (1 << ADSC);
 
574
    // Wait for completion
 
575
    while (ADCSRA & (1 << ADSC));
 
576
 
 
577
    // ADCH should have the value we wanted
 
578
    return ADCH;
 
579
}
 
580
#endif
 
581
 
 
582
int main(void)
 
583
{
 
584
    // check the OTC immediately before it has a chance to charge or discharge
 
585
    //uint8_t cap_val = read_otc();  // save it for later
 
586
 
 
587
    // Set PWM pin to output
 
588
    DDRB |= (1 << PWM_PIN);     // enable main channel
 
589
    #ifdef ALT_PWM_PIN
 
590
    DDRB |= (1 << ALT_PWM_PIN); // enable second channel
 
591
    #endif
 
592
 
 
593
    // Set timer to do PWM for correct output pin and set prescaler timing
 
594
    //TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
 
595
    //TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
 
596
    TCCR0A = FAST;
 
597
    // Set timer to do PWM for correct output pin and set prescaler timing
 
598
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
 
599
 
 
600
    // Read config values and saved state
 
601
    restore_state();
 
602
 
 
603
    // Enable the current mode group
 
604
    count_modes();
 
605
 
 
606
 
 
607
    // TODO: Enable this?  (might prevent some corner cases, but requires extra room)
 
608
    // memory decayed, reset it
 
609
    // (should happen on med/long press instead
 
610
    //  because mem decay is *much* slower when the OTC is charged
 
611
    //  so let's not wait until it decays to reset it)
 
612
    //if (fast_presses > 0x20) { fast_presses = 0; }
 
613
 
 
614
    // check button press time, unless the mode is overridden
 
615
    if (! mode_override) {
 
616
        //if (cap_val > CAP_SHORT) {
 
617
        if (fast_presses < 0x20) {
 
618
            // Indicates they did a short press, go to the next mode
 
619
            // We don't care what the fast_presses value is as long as it's over 15
 
620
            fast_presses = (fast_presses+1) & 0x1f;
 
621
            next_mode(); // Will handle wrap arounds
 
622
#ifdef OFFTIM3
 
623
        } else if (cap_val > CAP_MED) {
 
624
            // User did a medium press, go back one mode
 
625
            fast_presses = 0;
 
626
            if (offtim3) {
 
627
                prev_mode();  // Will handle "negative" modes and wrap-arounds
 
628
            } else {
 
629
                next_mode();  // disabled-med-press acts like short-press
 
630
                              // (except that fast_presses isn't reliable then)
 
631
            }
 
632
#endif
 
633
        } else {
 
634
            // Long press, keep the same mode
 
635
            // ... or reset to the first mode
 
636
            fast_presses = 0;
 
637
            //if (muggle_mode  || (! memory)) {
 
638
            if (! memory) {
 
639
                // Reset to the first mode
 
640
                mode_idx = 0;
 
641
            }
 
642
        }
 
643
    }
 
644
    save_mode();
 
645
 
 
646
    #ifdef CAP_PIN
 
647
    // Charge up the capacitor by setting CAP_PIN to output
 
648
    DDRB  |= (1 << CAP_PIN);    // Output
 
649
    PORTB |= (1 << CAP_PIN);    // High
 
650
    #endif
 
651
 
 
652
    // Turn features on or off as needed
 
653
    #ifdef VOLTAGE_MON
 
654
    ADC_on();
 
655
    #else
 
656
    ADC_off();
 
657
    #endif
 
658
 
 
659
    uint8_t output;
 
660
    uint8_t actual_level;
 
661
#ifdef TEMPERATURE_MON
 
662
    uint8_t overheat_count = 0;
 
663
#endif
 
664
#ifdef VOLTAGE_MON
 
665
    uint8_t lowbatt_cnt = 0;
 
666
    uint8_t i = 0;
 
667
    uint8_t voltage;
 
668
    // Make sure voltage reading is running for later
 
669
    ADCSRA |= (1 << ADSC);
 
670
#endif
 
671
    //output = pgm_read_byte(modes + mode_idx);
 
672
    output = modes[mode_idx];
 
673
    actual_level = output;
 
674
    // handle mode overrides, like mode group selection and temperature calibration
 
675
    if (mode_override) {
 
676
        // do nothing; mode is already set
 
677
        //mode_idx = mode_override;
 
678
        fast_presses = 0;
 
679
        output = mode_idx;
 
680
    }
 
681
    while(1) {
 
682
        if (fast_presses > 9) {  // Config mode
 
683
            _delay_s();       // wait for user to stop fast-pressing button
 
684
            fast_presses = 0; // exit this mode after one use
 
685
            mode_idx = 0;
 
686
 
 
687
            // Enter or leave "muggle mode"?
 
688
            //toggle(&muggle_mode, 1);
 
689
            //if (muggle_mode) { continue; };  // don't offer other options in muggle mode
 
690
 
 
691
            //toggle(&memory, 2);
 
692
 
 
693
            //toggle(&enable_moon, 3);
 
694
 
 
695
            //toggle(&reverse_modes, 4);
 
696
 
 
697
            // Enter the mode group selection mode?
 
698
            mode_idx = GROUP_SELECT_MODE;
 
699
            toggle(&mode_override, 1);
 
700
            mode_idx = 0;
 
701
 
 
702
            toggle(&memory, 2);
 
703
 
 
704
#ifdef OFFTIM3
 
705
            toggle(&offtim3, 6);
 
706
#endif
 
707
 
 
708
#ifdef TEMPERATURE_MON
 
709
            // Enter temperature calibration mode?
 
710
            mode_idx = TEMP_CAL_MODE;
 
711
            toggle(&mode_override, 7);
 
712
            mode_idx = 0;
 
713
#endif
 
714
 
 
715
            //toggle(&firstboot, 8);
 
716
 
 
717
            //output = pgm_read_byte(modes + mode_idx);
 
718
            output = modes[mode_idx];
 
719
            actual_level = output;
 
720
        }
 
721
#ifdef STROBE
 
722
        else if (output == STROBE) {
 
723
            // 10Hz tactical strobe
 
724
            strobe(33,67);
 
725
        }
 
726
#endif // ifdef STROBE
 
727
#ifdef POLICE_STROBE
 
728
        else if (output == POLICE_STROBE) {
 
729
            // police-like strobe
 
730
            //for(i=0;i<8;i++) {
 
731
                strobe(20,40);
 
732
            //}
 
733
            //for(i=0;i<8;i++) {
 
734
                strobe(40,80);
 
735
            //}
 
736
        }
 
737
#endif // ifdef POLICE_STROBE
 
738
#ifdef RANDOM_STROBE
 
739
        else if (output == RANDOM_STROBE) {
 
740
            // pseudo-random strobe
 
741
            uint8_t ms = 34 + (pgm_rand() & 0x3f);
 
742
            strobe(ms, ms);
 
743
            strobe(ms, ms);
 
744
        }
 
745
#endif // ifdef RANDOM_STROBE
 
746
#ifdef BIKING_STROBE
 
747
        else if (output == BIKING_STROBE) {
 
748
            // 2-level stutter beacon for biking and such
 
749
#ifdef FULL_BIKING_STROBE
 
750
            // normal version
 
751
            for(i=0;i<4;i++) {
 
752
                //set_output(255,0);
 
753
                set_mode(RAMP_SIZE);
 
754
                _delay_ms(10);
 
755
                //set_output(0,255);
 
756
                set_mode(4);
 
757
                _delay_ms(60);
 
758
            }
 
759
            //_delay_ms(720);
 
760
            _delay_s();
 
761
#else
 
762
            // small/minimal version
 
763
            set_mode(RAMP_SIZE);
 
764
            //set_output(255,0);
 
765
            _delay_ms(10);
 
766
            set_mode(3);
 
767
            //set_output(0,255);
 
768
            _delay_s();
 
769
#endif
 
770
        }
 
771
#endif  // ifdef BIKING_STROBE
 
772
#ifdef SOS
 
773
        else if (output == SOS) { SOS_mode(); }
 
774
#endif // ifdef SOS
 
775
#ifdef RAMP
 
776
        else if (output == RAMP) {
 
777
            int8_t r;
 
778
            // simple ramping test
 
779
            for(r=1; r<=RAMP_SIZE; r++) {
 
780
                set_level(r);
 
781
                _delay_ms(25);
 
782
            }
 
783
            for(r=RAMP_SIZE; r>0; r--) {
 
784
                set_level(r);
 
785
                _delay_ms(25);
 
786
            }
 
787
        }
 
788
#endif  // ifdef RAMP
 
789
#ifdef BATTCHECK
 
790
        else if (output == BATTCHECK) {
 
791
#ifdef BATTCHECK_VpT
 
792
            // blink out volts and tenths
 
793
            _delay_ms(100);
 
794
            uint8_t result = battcheck();
 
795
            blink(result >> 5, BLINK_SPEED/8);
 
796
            _delay_ms(BLINK_SPEED);
 
797
            blink(1,5);
 
798
            _delay_ms(BLINK_SPEED*3/2);
 
799
            blink(result & 0b00011111, BLINK_SPEED/8);
 
800
#else  // ifdef BATTCHECK_VpT
 
801
            // blink zero to five times to show voltage
 
802
            // (~0%, ~25%, ~50%, ~75%, ~100%, >100%)
 
803
            blink(battcheck(), BLINK_SPEED/4);
 
804
#endif  // ifdef BATTCHECK_VpT
 
805
            // wait between readouts
 
806
            _delay_s(); _delay_s();
 
807
        }
 
808
#endif // ifdef BATTCHECK
 
809
        else if (output == GROUP_SELECT_MODE) {
 
810
            // exit this mode after one use
 
811
            mode_idx = 0;
 
812
            mode_override = 0;
 
813
 
 
814
            for(i=0; i<NUM_MODEGROUPS; i++) {
 
815
                modegroup = i;
 
816
                save_state();
 
817
 
 
818
                blink(i+1, BLINK_SPEED/4);
 
819
                _delay_s(); _delay_s();
 
820
            }
 
821
            _delay_s();
 
822
        }
 
823
#ifdef TEMP_CAL_MODE
 
824
        else if (output == TEMP_CAL_MODE) {
 
825
            // make sure we don't stay in this mode after button press
 
826
            mode_idx = 0;
 
827
            mode_override = 0;
 
828
 
 
829
            // Allow the user to turn off thermal regulation if they want
 
830
            maxtemp = 255;
 
831
            save_state();
 
832
            set_mode(RAMP_SIZE/4);  // start somewhat dim during turn-off-regulation mode
 
833
            _delay_s(); _delay_s();
 
834
 
 
835
            // run at highest output level, to generate heat
 
836
            set_mode(RAMP_SIZE);
 
837
 
 
838
            // measure, save, wait...  repeat
 
839
            while(1) {
 
840
                maxtemp = get_temperature();
 
841
                save_state();
 
842
                _delay_s(); _delay_s();
 
843
            }
 
844
        }
 
845
#endif  // TEMP_CAL_MODE
 
846
        else {  // Regular non-hidden solid mode
 
847
            set_mode(actual_level);
 
848
#ifdef TEMPERATURE_MON
 
849
            uint8_t temp = get_temperature();
 
850
 
 
851
            // step down? (or step back up?)
 
852
            if (temp >= maxtemp) {
 
853
                overheat_count ++;
 
854
                // reduce noise, and limit the lowest step-down level
 
855
                if ((overheat_count > 15) && (actual_level > (RAMP_SIZE/8))) {
 
856
                    actual_level --;
 
857
                    //_delay_ms(5000);  // don't ramp down too fast
 
858
                    overheat_count = 0;  // don't ramp down too fast
 
859
                }
 
860
            } else {
 
861
                // if we're not overheated, ramp up to the user-requested level
 
862
                overheat_count = 0;
 
863
                if ((temp < maxtemp - 2) && (actual_level < output)) {
 
864
                    actual_level ++;
 
865
                }
 
866
            }
 
867
            set_mode(actual_level);
 
868
 
 
869
            ADC_on();  // return to voltage mode
 
870
#endif
 
871
            // Otherwise, just sleep.
 
872
            _delay_ms(500);
 
873
 
 
874
            // If we got this far, the user has stopped fast-pressing.
 
875
            // So, don't enter config mode.
 
876
            //fast_presses = 0;
 
877
        }
 
878
        fast_presses = 0;
 
879
#ifdef VOLTAGE_MON
 
880
        if (ADCSRA & (1 << ADIF)) {  // if a voltage reading is ready
 
881
            voltage = ADCH;  // get the waiting value
 
882
            // See if voltage is lower than what we were looking for
 
883
            if (voltage < ADC_LOW) {
 
884
                lowbatt_cnt ++;
 
885
            } else {
 
886
                lowbatt_cnt = 0;
 
887
            }
 
888
            // See if it's been low for a while, and maybe step down
 
889
            if (lowbatt_cnt >= 8) {
 
890
                // DEBUG: blink on step-down:
 
891
                //set_level(0);  _delay_ms(100);
 
892
 
 
893
                if (actual_level > RAMP_SIZE) {  // hidden / blinky modes
 
894
                    // step down from blinky modes to medium
 
895
                    actual_level = RAMP_SIZE / 2;
 
896
                } else if (actual_level > 1) {  // regular solid mode
 
897
                    // step down from solid modes somewhat gradually
 
898
                    // drop by 25% each time
 
899
                    //actual_level = (actual_level >> 2) + (actual_level >> 1);
 
900
                    actual_level = actual_level - 1;
 
901
                    // drop by 50% each time
 
902
                    //actual_level = (actual_level >> 1);
 
903
                } else { // Already at the lowest mode
 
904
                    //mode_idx = 0;  // unnecessary; we never leave this clause
 
905
                    //actual_level = 0;  // unnecessary; we never leave this clause
 
906
                    // Turn off the light
 
907
                    set_level(0);
 
908
                    // Power down as many components as possible
 
909
                    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
910
                    sleep_mode();
 
911
                }
 
912
                set_mode(actual_level);
 
913
                output = actual_level;
 
914
                //save_mode();  // we didn't actually change the mode
 
915
                lowbatt_cnt = 0;
 
916
                // Wait before lowering the level again
 
917
                //_delay_ms(250);
 
918
                _delay_s();
 
919
            }
 
920
 
 
921
            // Make sure conversion is running for next time through
 
922
            ADCSRA |= (1 << ADSC);
 
923
        }
 
924
#endif  // ifdef VOLTAGE_MON
 
925
    }
 
926
 
 
927
    //return 0; // Standard Return Code
 
928
}