~gabe/flashlight-firmware/anduril2

« back to all changes in this revision

Viewing changes to ToyKeeper/crescendo/crescendo.c

  • Committer: Selene Scriven
  • Date: 2017-09-12 23:34:36 UTC
  • mto: (188.1.3 trunk)
  • mto: This revision was merged to the branch mainline in revision 331.
  • Revision ID: bzr@toykeeper.net-20170912233436-d3w6nln0ts1subue
Added Flintrock's Bistro-HD 1.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * "Crescendo" firmware (ramping UI for clicky-switch lights)
 
3
 *
 
4
 * Copyright (C) 2017 Selene Scriven
 
5
 *
 
6
 * This program is free software: you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation, either version 3 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 *
 
19
 *
 
20
 * ATTINY13 Diagram
 
21
 *           ----
 
22
 *         -|1  8|- VCC
 
23
 *         -|2  7|- Voltage ADC
 
24
 *         -|3  6|-
 
25
 *     GND -|4  5|- PWM (Nx7135)
 
26
 *           ----
 
27
 *
 
28
 * FUSES
 
29
 *      I use these fuse settings on attiny13
 
30
 *      Low:  0x75
 
31
 *      High: 0xff
 
32
 *
 
33
 * CALIBRATION
 
34
 *
 
35
 *   To find out what values to use, flash the driver with battcheck.hex
 
36
 *   and hook the light up to each voltage you need a value for.  This is
 
37
 *   much more reliable than attempting to calculate the values from a
 
38
 *   theoretical formula.
 
39
 *
 
40
 *   Same for off-time capacitor values.  Measure, don't guess.
 
41
 */
 
42
// Choose your MCU here, or in the build script
 
43
//#define ATTINY 13
 
44
//#define ATTINY 25
 
45
// Pick your driver type:
 
46
//#define NANJG_LAYOUT
 
47
#define FET_7135_LAYOUT
 
48
//#define TRIPLEDOWN_LAYOUT
 
49
// Also, assign I/O pins in this file:
 
50
#include "tk-attiny.h"
 
51
 
 
52
/*
 
53
 * =========================================================================
 
54
 * Settings to modify per driver
 
55
 */
 
56
 
 
57
#define VOLTAGE_MON         // Comment out to disable LVP and battcheck
 
58
#define THERMAL_REGULATION  // Comment out to disable thermal regulation
 
59
#define MAX_THERM_CEIL 70   // Highest allowed temperature ceiling
 
60
#define DEFAULT_THERM_CEIL 50  // Temperature limit when unconfigured
 
61
 
 
62
// FET-only or Convoy red driver
 
63
// ../../bin/level_calc.py 1 64 7135 1 0.25 1000
 
64
//#define RAMP_CH1   1,1,1,1,1,2,2,2,2,3,3,4,5,5,6,7,8,9,10,11,13,14,16,18,20,22,24,26,29,32,34,38,41,44,48,51,55,60,64,68,73,78,84,89,95,101,107,113,120,127,134,142,150,158,166,175,184,193,202,212,222,233,244,255
 
65
 
 
66
// Common nanjg driver
 
67
// ../../bin/level_calc.py 1 64 7135 4 0.25 1000
 
68
//#define RAMP_CH1   4,4,4,4,4,5,5,5,5,6,6,7,7,8,9,10,11,12,13,14,16,17,19,21,23,25,27,29,32,34,37,40,43,47,50,54,58,62,66,71,75,80,86,91,97,103,109,115,122,129,136,143,151,159,167,176,184,194,203,213,223,233,244,255
 
69
// ../../bin/level_calc.py 1 96 7135 4 0.25 1000
 
70
//#define RAMP_CH1   4,4,4,4,4,4,4,5,5,5,5,5,5,6,6,6,7,7,7,8,8,9,9,10,11,11,12,13,14,15,16,17,18,19,20,21,22,24,25,26,28,30,31,33,35,37,39,41,43,45,47,49,52,54,57,60,62,65,68,71,74,78,81,84,88,92,95,99,103,107,111,116,120,124,129,134,139,144,149,154,159,165,170,176,182,188,194,200,207,213,220,226,233,240,248,255
 
71
// ../../bin/level_calc.py 1 128 7135 4 0.25 1000
 
72
//#define RAMP_CH1   4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,9,9,10,10,11,11,12,12,13,13,14,15,15,16,17,18,19,19,20,21,22,23,24,25,26,27,29,30,31,32,34,35,36,38,39,41,42,44,46,47,49,51,53,55,57,59,61,63,65,67,69,72,74,76,79,81,84,86,89,92,95,98,100,103,106,109,113,116,119,122,126,129,133,136,140,144,148,152,155,159,164,168,172,176,181,185,189,194,199,203,208,213,218,223,228,233,239,244,249,255
 
73
 
 
74
// MTN17DDm FET+1 tiny25, 36 steps
 
75
// ../../bin/level_calc.py 2 36 7135 2 0.25 140 FET 1 10 1300
 
76
//#define RAMP_CH1 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,14,21,29,37,47,57,68,80,93,107,121,137,154,172,191,211,232,255
 
77
//#define RAMP_CH2 2,3,5,8,12,18,26,37,49,65,84,106,131,161,195,233,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0
 
78
// MTN17DDm FET+1 tiny25, 56 steps
 
79
// ../../bin/level_calc.py 2 56 7135 2 0.25 140 FET 1 10 1300
 
80
//#define RAMP_CH1 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,8,12,17,22,26,32,37,43,49,56,63,70,78,86,94,103,112,121,131,142,152,164,175,187,200,213,226,240,255
 
81
//#define RAMP_CH2 2,3,3,5,6,8,11,15,19,24,30,37,45,53,64,75,88,102,117,134,153,173,195,219,244,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
 
82
// MTN17DDm FET+1 tiny25, 64 steps
 
83
// ../../bin/level_calc.py 2 64 7135 2 0.25 140 FET 1 10 1300
 
84
//#define RAMP_CH1 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,5,9,12,16,20,24,29,33,38,44,49,55,61,67,73,80,87,94,102,110,118,126,135,144,154,164,174,184,195,206,218,230,242,255
 
85
//#define RAMP_CH2 2,2,3,4,5,7,9,12,15,18,23,27,33,39,46,54,63,73,84,96,109,123,138,154,172,191,211,233,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
// MTN17DDm FET+1 tiny25, 128 steps (smooth!)
 
87
// ../../bin/level_calc.py 2 128 7135 2 0.25 140 FET 1 10 1300
 
88
//#define RAMP_CH1 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,0,0,0,0,0,0,0,0,0,0,0,1,3,4,6,8,9,11,13,15,17,19,21,23,25,27,30,32,34,37,39,42,45,47,50,53,56,59,62,65,68,71,74,78,81,84,88,92,95,99,103,107,111,115,119,123,127,132,136,141,145,150,155,159,164,169,174,180,185,190,196,201,207,213,218,224,230,236,242,249,255
 
89
//#define RAMP_CH2 2,2,2,3,3,4,4,5,5,6,7,8,9,10,11,13,14,16,18,20,22,24,27,30,32,35,39,42,46,49,53,58,62,67,72,77,82,88,94,100,106,113,120,127,135,143,151,160,168,178,187,197,207,217,228,239,251,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,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
 
90
// MTN17DDm FET+1 tiny25, 128 steps (smooth!), 2000lm max, 380mA 7135 chip
 
91
// ../../bin/level_calc.py 2 128 7135 6 0.25 140 FET 1 10 2000
 
92
#define RAMP_CH1 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,0,0,0,1,2,4,5,6,7,9,10,12,13,14,16,18,19,21,23,25,26,28,30,32,34,36,39,41,43,45,48,50,53,55,58,61,63,66,69,72,75,78,81,84,88,91,94,98,101,105,109,112,116,120,124,128,132,136,141,145,149,154,158,163,168,173,177,182,187,193,198,203,209,214,220,225,231,237,243,249,255
 
93
#define RAMP_CH2 6,6,7,7,7,8,9,9,10,11,12,14,15,17,19,21,23,25,28,31,34,37,41,45,49,53,58,63,68,73,79,85,92,99,106,114,122,130,139,148,157,167,178,188,200,211,224,236,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,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
 
94
 
 
95
// TripleDown
 
96
// ../../bin/level_calc.py 3 80 7135 3 0.25 140 7135 3 1.5 660 FET 1 10 1200
 
97
// Nx7135
 
98
//#define RAMP_CH1 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,6,10,15,19,24,29,34,40,46,52,58,64,71,78,85,92,100,108,116,125,133,143,152,162,172,182,192,203,215,226,238,250,255,255,255,255,255,255,255,255,255,255,0
 
99
// 1x7135
 
100
//#define RAMP_CH2 3,3,4,4,5,6,7,9,11,13,15,17,20,24,28,32,36,41,47,53,59,67,74,83,91,101,111,122,134,146,159,173,187,203,219,236,254,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
 
101
// FET
 
102
//#define RAMP_CH3 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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,30,52,75,99,124,149,174,200,227,255
 
103
 
 
104
// How many ms should it take to ramp all the way up?
 
105
// (recommended values 2000 to 5000 depending on personal preference)
 
106
#define RAMP_TIME  3000
 
107
 
 
108
// How long to wait at ramp ends, and
 
109
// how long the user has to continue multi-taps after the light comes on
 
110
// (higher makes it slower and easier to do double-taps / triple-taps,
 
111
//  lower makes the UI faster)
 
112
// (recommended values 250 to 750)
 
113
//#define HALF_SECOND 500
 
114
#define HALF_SECOND 333
 
115
 
 
116
// Enable battery indicator mode?
 
117
#ifdef VOLTAGE_MON
 
118
#define USE_BATTCHECK
 
119
#endif
 
120
// Choose a battery indicator style
 
121
//#define BATTCHECK_4bars  // up to 4 blinks
 
122
#define BATTCHECK_8bars  // up to 8 blinks
 
123
//#define BATTCHECK_VpT  // Volts + tenths
 
124
 
 
125
// output to use for blinks on battery check (and other modes)
 
126
#define BLINK_BRIGHTNESS    RAMP_SIZE/4
 
127
// ms per normal-speed blink
 
128
#define BLINK_SPEED         (500/4)
 
129
 
 
130
// Uncomment this if you want the ramp to stop when it reaches maximum
 
131
//#define STOP_AT_TOP     HOP_ON_POP
 
132
// Uncomment this if you want it to blink when it reaches maximum
 
133
#define BLINK_AT_TOP
 
134
 
 
135
// 255 is the default eeprom state, don't use
 
136
// (actually, no longer applies...  using a different algorithm now)
 
137
// (previously tried to store mode type plus ramp level in a single byte
 
138
//  for mode memory purposes, but it was a bad idea)
 
139
#define DONOTUSE  255
 
140
// Modes start at 255 and count down
 
141
#define TURBO     254
 
142
#define RAMP      253
 
143
#define STEADY    252
 
144
#ifdef VOLTAGE_MON
 
145
#define BATTCHECK 251
 
146
#endif
 
147
#define MEMORY    250
 
148
#ifdef MEMORY
 
149
#define MEMTOGGLE // runtime config for memory (requires MEMORY)
 
150
#endif
 
151
#ifdef THERMAL_REGULATION
 
152
#define THERM_CALIBRATION_MODE 248  // let user configure temperature limit
 
153
#endif
 
154
#define BIKING_MODE 247   // steady on with pulses at 1Hz
 
155
//#define BIKING_MODE2 246   // steady on with pulses at 1Hz
 
156
// comment out to use minimal version instead (smaller)
 
157
#define FULL_BIKING_MODE
 
158
// Required for any of the strobes below it
 
159
//#define ANY_STROBE
 
160
//#define STROBE    245         // Simple tactical strobe
 
161
//#define POLICE_STROBE 244     // 2-speed tactical strobe
 
162
//#define RANDOM_STROBE 243     // variable-speed tactical strobe
 
163
//#define SOS 242               // distress signal
 
164
#define HEART_BEACON 241      // 1Hz heartbeat-pattern beacon
 
165
// next line required for any of the party strobes to work
 
166
#define PARTY_STROBES
 
167
#define PARTY_STROBE12 240    // 12Hz party strobe
 
168
#define PARTY_STROBE24 239    // 24Hz party strobe
 
169
#define PARTY_STROBE60 238    // 60Hz party strobe
 
170
//#define PARTY_VARSTROBE1 237  // variable-speed party strobe (slow)
 
171
//#define PARTY_VARSTROBE2 236  // variable-speed party strobe (fast)
 
172
#define GOODNIGHT 235         // hour-long ramp down then poweroff
 
173
 
 
174
 
 
175
#if defined(MEMTOGGLE) || defined(THERM_CALIBRATION_MODE)
 
176
#define CONFIG_MODE
 
177
#endif
 
178
 
 
179
// Calibrate voltage and OTC in this file:
 
180
#include "tk-calibration.h"
 
181
 
 
182
/*
 
183
 * =========================================================================
 
184
 */
 
185
 
 
186
// Ignore a spurious warning, we did the cast on purpose
 
187
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
 
188
 
 
189
#include <avr/pgmspace.h>
 
190
#include <avr/interrupt.h>
 
191
#include <avr/eeprom.h>
 
192
#include <avr/sleep.h>
 
193
#include <string.h>
 
194
 
 
195
#define OWN_DELAY           // Don't use stock delay functions.
 
196
#define USE_DELAY_4MS
 
197
#ifdef PARTY_STROBES
 
198
#define USE_DELAY_MS
 
199
#define USE_FINE_DELAY
 
200
#endif
 
201
#define USE_DELAY_S         // Also use _delay_s(), not just _delay_ms()
 
202
#include "tk-delay.h"
 
203
 
 
204
#ifdef THERMAL_REGULATION
 
205
#define TEMP_10bit
 
206
#endif
 
207
#include "tk-voltage.h"
 
208
 
 
209
#ifdef RANDOM_STROBE
 
210
#include "tk-random.h"
 
211
#endif
 
212
 
 
213
/*
 
214
 * global variables
 
215
 */
 
216
 
 
217
// Config option variables
 
218
#ifdef MEMTOGGLE
 
219
uint8_t memory;
 
220
#endif
 
221
#ifdef THERMAL_REGULATION
 
222
uint8_t therm_ceil = DEFAULT_THERM_CEIL;
 
223
#endif
 
224
// Other state variables
 
225
uint8_t eepos;
 
226
uint8_t saved_mode_idx = 0;
 
227
uint8_t saved_ramp_level = 1;
 
228
// counter for entering config mode
 
229
// (needs to be remembered while off, but only for up to half a second)
 
230
uint8_t fast_presses __attribute__ ((section (".noinit")));
 
231
uint8_t long_press __attribute__ ((section (".noinit")));
 
232
// current or last-used mode number
 
233
uint8_t mode_idx __attribute__ ((section (".noinit")));
 
234
uint8_t ramp_level __attribute__ ((section (".noinit")));
 
235
int8_t ramp_dir __attribute__ ((section (".noinit")));
 
236
uint8_t next_mode_num __attribute__ ((section (".noinit")));
 
237
uint8_t target_level;  // ramp level before thermal stepdown
 
238
uint8_t actual_level;  // last ramp level activated
 
239
 
 
240
uint8_t modes[] = {
 
241
    RAMP, STEADY, TURBO,
 
242
#ifdef USE_BATTCHECK
 
243
    BATTCHECK,
 
244
#endif
 
245
#ifdef GOODNIGHT
 
246
    GOODNIGHT,
 
247
#endif
 
248
#ifdef BIKING_MODE2
 
249
    BIKING_MODE2,
 
250
#endif
 
251
#ifdef BIKING_MODE
 
252
    BIKING_MODE,
 
253
#endif
 
254
#ifdef RANDOM_STROBE
 
255
    RANDOM_STROBE,
 
256
#endif
 
257
#ifdef POLICE_STROBE
 
258
    POLICE_STROBE,
 
259
#endif
 
260
#ifdef STROBE
 
261
    STROBE,
 
262
#endif
 
263
#ifdef HEART_BEACON
 
264
    HEART_BEACON,
 
265
#endif
 
266
#ifdef PARTY_STROBE12
 
267
    PARTY_STROBE12,
 
268
#endif
 
269
#ifdef PARTY_STROBE24
 
270
    PARTY_STROBE24,
 
271
#endif
 
272
#ifdef PARTY_STROBE60
 
273
    PARTY_STROBE60,
 
274
#endif
 
275
#ifdef PARTY_VARSTROBE1
 
276
    PARTY_VARSTROBE1,
 
277
#endif
 
278
#ifdef PARTY_VARSTROBE2
 
279
    PARTY_VARSTROBE2,
 
280
#endif
 
281
#ifdef SOS
 
282
    SOS,
 
283
#endif
 
284
};
 
285
 
 
286
// Modes (gets set when the light starts up based on saved config values)
 
287
PROGMEM const uint8_t ramp_ch1[]  = { RAMP_CH1 };
 
288
#ifdef RAMP_CH2
 
289
PROGMEM const uint8_t ramp_ch2[] = { RAMP_CH2 };
 
290
#endif
 
291
#ifdef RAMP_CH3
 
292
PROGMEM const uint8_t ramp_ch3[] = { RAMP_CH3 };
 
293
#endif
 
294
#define RAMP_SIZE  sizeof(ramp_ch1)
 
295
 
 
296
void _delay_500ms() {
 
297
    _delay_4ms(HALF_SECOND/4);
 
298
}
 
299
 
 
300
#if defined(MEMORY) || defined(CONFIG_MODE)
 
301
#if (ATTINY == 85) || (ATTINY == 45)
 
302
#define EEP_WEAR_LVL_LEN 128
 
303
#elif (ATTINY == 25)
 
304
#define EEP_WEAR_LVL_LEN 64
 
305
#elif (ATTINY == 13)
 
306
#define EEP_WEAR_LVL_LEN 32
 
307
#endif
 
308
#endif
 
309
#ifdef MEMORY
 
310
void save_mode() {  // save the current mode index (with wear leveling)
 
311
    // only save when memory is enabled
 
312
    if (memory) {
 
313
        eeprom_write_byte((uint8_t *)(eepos), 0xff);     // erase old state
 
314
        eeprom_write_byte((uint8_t *)(++eepos), 0xff);     // erase old state
 
315
 
 
316
        eepos = (eepos+1) & (EEP_WEAR_LVL_LEN-1);  // wear leveling, use next cell
 
317
        // save current mode
 
318
        eeprom_write_byte((uint8_t *)(eepos), mode_idx);
 
319
        // save current brightness
 
320
        eeprom_write_byte((uint8_t *)(eepos+1), ramp_level);
 
321
    }
 
322
}
 
323
#endif
 
324
 
 
325
#ifdef CONFIG_MODE
 
326
#define OPT_memory (EEP_WEAR_LVL_LEN+1)
 
327
#define OPT_therm_ceil (EEP_WEAR_LVL_LEN+2)
 
328
void save_state() {
 
329
    #ifdef MEMORY
 
330
    save_mode();
 
331
    #endif
 
332
    #ifdef MEMTOGGLE
 
333
    eeprom_write_byte((uint8_t *)OPT_memory, memory);
 
334
    #endif
 
335
    #ifdef THERM_CALIBRATION_MODE
 
336
    eeprom_write_byte((uint8_t *)OPT_therm_ceil, therm_ceil);
 
337
    #endif
 
338
}
 
339
#else
 
340
#define save_state save_mode
 
341
#endif
 
342
 
 
343
#ifdef CONFIG_MODE
 
344
void restore_state() {
 
345
    uint8_t eep;
 
346
    #ifdef MEMTOGGLE
 
347
    // memory is either 1 or 0
 
348
    // (if it's unconfigured, 0xFF, assume it's off)
 
349
    eep = eeprom_read_byte((uint8_t *)OPT_memory);
 
350
    if (eep < 2) { memory = eep; }
 
351
    else { memory = 0; }
 
352
    #endif
 
353
 
 
354
    #ifdef THERM_CALIBRATION_MODE
 
355
    // load therm_ceil
 
356
    eep = eeprom_read_byte((uint8_t *)OPT_therm_ceil);
 
357
    if ((eep > 0) && (eep < MAX_THERM_CEIL)) {
 
358
        therm_ceil = eep;
 
359
    }
 
360
    #endif
 
361
 
 
362
    #ifdef MEMORY
 
363
    // find the mode index and last brightness level
 
364
    for(eepos=0; eepos<EEP_WEAR_LVL_LEN; eepos+=2) {
 
365
        eep = eeprom_read_byte((const uint8_t *)eepos);
 
366
        if (eep != 0xff) {
 
367
            saved_mode_idx = eep;
 
368
            eep = eeprom_read_byte((const uint8_t *)(eepos+1));
 
369
            if (eep != 0xff) {
 
370
                saved_ramp_level = eep;
 
371
            }
 
372
            break;
 
373
        }
 
374
    }
 
375
    #endif
 
376
}
 
377
#endif  // ifdef CONFIG_MODE
 
378
 
 
379
inline void next_mode() {
 
380
    // allow an override, if it exists
 
381
    //if (next_mode_num < sizeof(modes)) {
 
382
    if (next_mode_num < 255) {
 
383
        mode_idx = next_mode_num;
 
384
        next_mode_num = 255;
 
385
        return;
 
386
    }
 
387
 
 
388
    mode_idx += 1;
 
389
    if (mode_idx >= sizeof(modes)) {
 
390
        // Wrap around
 
391
        // (wrap to steady mode (1), not ramp (0))
 
392
        mode_idx = 1;
 
393
    }
 
394
}
 
395
 
 
396
#ifdef RAMP_CH3
 
397
inline void set_output(uint8_t pwm1, uint8_t pwm2, uint8_t pwm3) {
 
398
#else
 
399
#ifdef RAMP_CH2
 
400
inline void set_output(uint8_t pwm1, uint8_t pwm2) {
 
401
#else
 
402
inline void set_output(uint8_t pwm1) {
 
403
#endif
 
404
#endif
 
405
    PWM_LVL = pwm1;
 
406
    #ifdef RAMP_CH2
 
407
    ALT_PWM_LVL = pwm2;
 
408
    #endif
 
409
    #ifdef RAMP_CH3
 
410
    FET_PWM_LVL = pwm3;
 
411
    #endif
 
412
}
 
413
 
 
414
void set_level(uint8_t level) {
 
415
    actual_level = level;
 
416
    TCCR0A = PHASE;
 
417
    if (level == 0) {
 
418
        #ifdef RAMP_CH3
 
419
        set_output(0,0,0);
 
420
        #else
 
421
        #ifdef RAMP_CH2
 
422
        set_output(0,0);
 
423
        #else
 
424
        set_output(0);
 
425
        #endif  // ifdef RAMP_CH2
 
426
        #endif  // ifdef RAMP_CH3
 
427
    } else {
 
428
        /*
 
429
        if (level > 2) {
 
430
            // divide PWM speed by 2 for lowest modes,
 
431
            // to make them more stable
 
432
            TCCR0A = FAST;
 
433
        }
 
434
        */
 
435
        #ifdef RAMP_CH3
 
436
        set_output(pgm_read_byte(ramp_ch1 + level - 1),
 
437
                   pgm_read_byte(ramp_ch2 + level - 1),
 
438
                   pgm_read_byte(ramp_ch3 + level - 1));
 
439
        #else
 
440
        #ifdef RAMP_CH2
 
441
        set_output(pgm_read_byte(ramp_ch1 + level - 1),
 
442
                   pgm_read_byte(ramp_ch2 + level - 1));
 
443
        #else
 
444
        set_output(pgm_read_byte(ramp_ch1 + level - 1));
 
445
        #endif
 
446
        #endif
 
447
    }
 
448
}
 
449
 
 
450
#define set_mode set_level
 
451
 
 
452
void blink(uint8_t val, uint8_t speed)
 
453
{
 
454
    for (; val>0; val--)
 
455
    {
 
456
        set_level(BLINK_BRIGHTNESS);
 
457
        _delay_4ms(speed);
 
458
        set_level(0);
 
459
        _delay_4ms(speed);
 
460
        _delay_4ms(speed);
 
461
    }
 
462
}
 
463
 
 
464
#ifdef ANY_STROBE
 
465
#ifdef POLICE_STROBE
 
466
void strobe(uint8_t ontime, uint8_t offtime) {
 
467
#else
 
468
inline void strobe(uint8_t ontime, uint8_t offtime) {
 
469
#endif
 
470
    uint8_t i;
 
471
    for(i=0;i<8;i++) {
 
472
        set_level(RAMP_SIZE);
 
473
        _delay_4ms(ontime);
 
474
        set_level(0);
 
475
        _delay_4ms(offtime);
 
476
    }
 
477
}
 
478
#endif
 
479
 
 
480
#ifdef PARTY_STROBES
 
481
inline void party_strobe(uint8_t ontime, uint8_t offtime) {
 
482
    set_level(RAMP_SIZE);
 
483
    if (ontime) {
 
484
        _delay_ms(ontime);
 
485
    } else {
 
486
        _delay_zero();
 
487
    }
 
488
    set_level(0);
 
489
    _delay_ms(offtime);
 
490
}
 
491
 
 
492
void party_strobe_loop(uint8_t ontime, uint8_t offtime) {
 
493
    uint8_t i;
 
494
    for(i=0;i<32;i++) {
 
495
        party_strobe(ontime, offtime);
 
496
    }
 
497
}
 
498
#endif
 
499
 
 
500
#ifdef SOS
 
501
inline void SOS_mode() {
 
502
#define SOS_SPEED (200/4)
 
503
    blink(3, SOS_SPEED);
 
504
    _delay_4ms(SOS_SPEED*5);
 
505
    blink(3, SOS_SPEED*5/2);
 
506
    //_delay_4ms(SOS_SPEED);
 
507
    blink(3, SOS_SPEED);
 
508
    _delay_s(); _delay_s();
 
509
}
 
510
#endif
 
511
 
 
512
#ifdef BIKING_MODE
 
513
inline void biking_mode(uint8_t lo, uint8_t hi) {
 
514
    #ifdef FULL_BIKING_MODE
 
515
    // normal version
 
516
    uint8_t i;
 
517
    for(i=0;i<4;i++) {
 
518
        //set_output(255,0);
 
519
        set_mode(hi);
 
520
        _delay_4ms(2);
 
521
        //set_output(0,255);
 
522
        set_mode(lo);
 
523
        _delay_4ms(15);
 
524
    }
 
525
    //_delay_ms(720);
 
526
    _delay_s();
 
527
    #else  // smaller bike mode
 
528
    // small/minimal version
 
529
    set_mode(hi);
 
530
    //set_output(255,0);
 
531
    _delay_4ms(4);
 
532
    set_mode(lo);
 
533
    //set_output(0,255);
 
534
    _delay_s();
 
535
    #endif  // ifdef FULL_BIKING_MODE
 
536
}
 
537
#endif
 
538
 
 
539
#ifdef THERMAL_REGULATION
 
540
#define TEMP_ORIGIN 275  // roughly 0 C or 32 F (ish)
 
541
int16_t current_temperature() {
 
542
    ADC_on_temperature();
 
543
    // average a few values; temperature is noisy
 
544
    // (use some of the noise as extra precision, ish)
 
545
    uint16_t temp = 0;
 
546
    uint8_t i;
 
547
    get_temperature();
 
548
    for(i=0; i<8; i++) {
 
549
        temp += get_temperature();
 
550
        _delay_4ms(1);
 
551
    }
 
552
    // convert 12.3 fixed-point to 13.2 fixed-point
 
553
    // ... and center it at 0 C
 
554
    temp = (temp>>1) - (TEMP_ORIGIN<<2);
 
555
    return temp;
 
556
}
 
557
#endif  // ifdef THERMAL_REGULATION
 
558
 
 
559
#ifdef GOODNIGHT
 
560
void poweroff() {
 
561
#else
 
562
inline void poweroff() {
 
563
#endif
 
564
    // Turn off main LED
 
565
    set_level(0);
 
566
    // Power down as many components as possible
 
567
    ADCSRA &= ~(1<<7); //ADC off
 
568
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
569
    sleep_mode();
 
570
}
 
571
 
 
572
#ifdef CONFIG_MODE
 
573
void toggle(uint8_t *var, uint8_t num) {
 
574
    // Used for config mode
 
575
    // Changes the value of a config option, waits for the user to "save"
 
576
    // by turning the light off, then changes the value back in case they
 
577
    // didn't save.  Can be used repeatedly on different options, allowing
 
578
    // the user to change and save only one at a time.
 
579
    blink(num, BLINK_SPEED/8);  // indicate which option number this is
 
580
    _delay_4ms(250/4);
 
581
    *var ^= 1;
 
582
    save_state();
 
583
    // "buzz" for a while to indicate the active toggle window
 
584
    blink(32, 500/32/4);
 
585
    // if the user didn't click, reset the value and return
 
586
    *var ^= 1;
 
587
    save_state();
 
588
    _delay_s();
 
589
}
 
590
#endif  // ifdef CONFIG_MODE
 
591
 
 
592
 
 
593
int main(void)
 
594
{
 
595
    // Set PWM pin to output
 
596
    DDRB |= (1 << PWM_PIN);     // enable main channel
 
597
    #ifdef RAMP_CH2
 
598
    DDRB |= (1 << ALT_PWM_PIN); // enable second channel
 
599
    #endif
 
600
    #ifdef RAMP_CH3
 
601
    // enable second PWM counter (OC1B) and third channel (FET, PB4)
 
602
    DDRB |= (1 << FET_PWM_PIN); // enable third channel (DDB4)
 
603
    #endif
 
604
 
 
605
    // Set timer to do PWM for correct output pin and set prescaler timing
 
606
    //TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
 
607
    //TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
 
608
    //TCCR0A = FAST;
 
609
    // Set timer to do PWM for correct output pin and set prescaler timing
 
610
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
 
611
 
 
612
    #ifdef RAMP_CH3
 
613
    // Second PWM counter is ... weird
 
614
    TCCR1 = _BV (CS10);
 
615
    GTCCR = _BV (COM1B1) | _BV (PWM1B);
 
616
    OCR1C = 255;  // Set ceiling value to maximum
 
617
    #endif
 
618
 
 
619
    #ifdef CONFIG_MODE
 
620
    uint8_t mode_override = 0;
 
621
    // Read config values and saved state
 
622
    restore_state();
 
623
    #endif
 
624
 
 
625
    // check button press time, unless the mode is overridden
 
626
    if (! long_press) {
 
627
        // Indicates they did a short press, go to the next mode
 
628
        // We don't care what the fast_presses value is as long as it's over 15
 
629
        fast_presses = (fast_presses+1) & 0x1f;
 
630
        next_mode(); // Will handle wrap arounds
 
631
    } else {
 
632
        // Long press, use memorized level
 
633
        // ... or reset to the first mode
 
634
        fast_presses = 0;
 
635
        ramp_level = 1;
 
636
        ramp_dir = 1;
 
637
        next_mode_num = 255;
 
638
        mode_idx = 0;
 
639
        #ifdef MEMORY
 
640
        #ifdef MEMTOGGLE
 
641
        if (memory) { mode_override = MEMORY; }
 
642
        #else
 
643
        mode_override = MEMORY;
 
644
        #endif  // ifdef MEMTOGGLE
 
645
        #endif  // ifdef MEMORY
 
646
    }
 
647
    long_press = 0;
 
648
    #ifdef MEMORY
 
649
    save_mode();
 
650
    #endif
 
651
 
 
652
    // Turn features on or off as needed
 
653
    #ifdef VOLTAGE_MON
 
654
    #ifndef THERMAL_REGULATION
 
655
    ADC_on();
 
656
    #endif
 
657
    #else
 
658
    ADC_off();
 
659
    #endif
 
660
 
 
661
    uint8_t mode;
 
662
    #ifdef VOLTAGE_MON
 
663
    uint8_t lowbatt_cnt = 0;
 
664
    uint8_t voltage;
 
665
    #endif
 
666
    #ifdef THERMAL_REGULATION
 
667
    #define THERM_HISTORY_SIZE 8
 
668
    uint8_t temperatures[THERM_HISTORY_SIZE];
 
669
    uint8_t overheat_count = 0;
 
670
    uint8_t underheat_count = 0;
 
671
    uint8_t first_temp_reading = 1;
 
672
    #endif
 
673
    uint8_t first_loop = 1;
 
674
    uint8_t loop_count = 0;
 
675
    while(1) {
 
676
        if (mode_idx < sizeof(modes)) mode = modes[mode_idx];
 
677
        else mode = mode_idx;
 
678
 
 
679
        #if defined(VOLTAGE_MON) && defined(THERMAL_REGULATION)
 
680
        // make sure a voltage reading has started, for LVP purposes
 
681
        ADC_on();
 
682
        #endif
 
683
 
 
684
 
 
685
        if (0) {  // This can't happen
 
686
        }
 
687
 
 
688
        #ifdef CONFIG_MODE
 
689
        else if (fast_presses > 15) {
 
690
            _delay_s();       // wait for user to stop fast-pressing button
 
691
            fast_presses = 0; // exit this mode after one use
 
692
            //mode = STEADY;
 
693
            mode_idx = 1;
 
694
            next_mode_num = 255;
 
695
 
 
696
            uint8_t t = 0;
 
697
            #ifdef MEMTOGGLE
 
698
            // turn memory on/off
 
699
            // (click during the "buzz" to change the setting)
 
700
            toggle(&memory, ++t);
 
701
            #endif  // ifdef MEMTOGGLE
 
702
 
 
703
            #ifdef THERM_CALIBRATION_MODE
 
704
            // Enter temperature calibration mode?
 
705
            next_mode_num = THERM_CALIBRATION_MODE;
 
706
            // mode_override does nothing here; just a dummy value
 
707
            toggle(&mode_override, ++t);
 
708
            mode_idx = 1;
 
709
            next_mode_num = 255;
 
710
            #endif
 
711
 
 
712
            // if config mode ends with no changes,
 
713
            // pretend this is the first loop
 
714
            continue;
 
715
        }
 
716
        #endif  // ifdef CONFIG_MODE
 
717
 
 
718
        #ifdef MEMORY
 
719
        // memorized level
 
720
        else if (mode_override == MEMORY) {
 
721
            // only do this once
 
722
            mode_override = 0;
 
723
 
 
724
            // moon mode for half a second
 
725
            set_mode(1);
 
726
            // if the user taps quickly, go to the real moon mode
 
727
            next_mode_num = 1;
 
728
 
 
729
            _delay_500ms();
 
730
 
 
731
            // if they didn't tap quickly, go to the memorized mode/level
 
732
            mode_idx = saved_mode_idx;
 
733
            ramp_level = saved_ramp_level;
 
734
            // remember for next time
 
735
            save_mode();
 
736
            // restart as if this were the first loop
 
737
            continue;
 
738
        }
 
739
        #endif
 
740
 
 
741
        // smooth ramp mode, lets user select any output level
 
742
        if (mode == RAMP) {
 
743
            set_mode(ramp_level);  // turn light on
 
744
 
 
745
            // ramp up by default
 
746
            //if (fast_presses == 0) {
 
747
            //    ramp_dir = 1;
 
748
            //}
 
749
            // double-tap to ramp down
 
750
            //else if (fast_presses == 1) {
 
751
            if (fast_presses == 1) {
 
752
                next_mode_num = mode_idx;  // stay in ramping mode
 
753
                ramp_dir = -1;             // ... but go down
 
754
            }
 
755
            // triple-tap to enter turbo
 
756
            else if (fast_presses == 2) {
 
757
                next_mode_num = mode_idx + 2;  // bypass "steady" mode
 
758
            }
 
759
 
 
760
            // wait a bit before actually ramping
 
761
            // (give the user a chance to select moon, or double-tap)
 
762
            _delay_500ms();
 
763
 
 
764
            // if we got through the delay, assume normal operation
 
765
            // (not trying to double-tap or triple-tap)
 
766
            // (next mode should be normal)
 
767
            next_mode_num = 255;
 
768
            // ramp up on single tap
 
769
            // (cancel earlier reversal)
 
770
            if (fast_presses == 1) {
 
771
                ramp_dir = 1;
 
772
            }
 
773
            // don't want this confusing us any more
 
774
            fast_presses = 0;
 
775
 
 
776
            // Just in case (SRAM could have partially decayed)
 
777
            //ramp_dir = (ramp_dir == 1) ? 1 : -1;
 
778
            // Do the actual ramp
 
779
            for (;; ramp_level += ramp_dir) {
 
780
                set_mode(ramp_level);
 
781
                _delay_4ms(RAMP_TIME/RAMP_SIZE/4);
 
782
                if (
 
783
                    ((ramp_dir > 0) && (ramp_level >= RAMP_SIZE))
 
784
                    ||
 
785
                    ((ramp_dir < 0) && (ramp_level <= 1))
 
786
                    )
 
787
                    break;
 
788
            }
 
789
            if (ramp_dir == 1) {
 
790
                #ifdef STOP_AT_TOP
 
791
                // go to steady mode
 
792
                mode_idx += 1;
 
793
                #endif
 
794
                #ifdef BLINK_AT_TOP
 
795
                // blink at the top
 
796
                set_mode(0);
 
797
                _delay_4ms(2);
 
798
                #endif
 
799
            }
 
800
            ramp_dir = -ramp_dir;
 
801
        }
 
802
 
 
803
        else if (mode == STEADY) {
 
804
            // normal flashlight mode
 
805
            if (first_loop) {
 
806
                set_mode(ramp_level);
 
807
                target_level = ramp_level;
 
808
            }
 
809
            // User has 0.5s to tap again to advance to the next mode
 
810
            //next_mode_num = 255;
 
811
            _delay_500ms();
 
812
            // After a delay, assume user wants to adjust ramp
 
813
            // instead of going to next mode (unless they're
 
814
            // tapping rapidly, in which case we should advance to turbo)
 
815
            next_mode_num = 0;
 
816
        }
 
817
 
 
818
        else if (mode == TURBO) {
 
819
            // turbo is special because it's easier to handle that way
 
820
            if (first_loop) {
 
821
                set_mode(RAMP_SIZE);
 
822
                target_level = RAMP_SIZE;
 
823
            }
 
824
            //next_mode_num = 255;
 
825
            _delay_500ms();
 
826
            // go back to the previously-memorized level
 
827
            // if the user taps after a delay,
 
828
            // instead of advancing to blinkies
 
829
            // (allows something similar to "momentary" turbo)
 
830
            next_mode_num = 1;
 
831
        }
 
832
 
 
833
        #ifdef STROBE
 
834
        else if (mode == STROBE) {
 
835
            // 10Hz tactical strobe
 
836
            strobe(33/4,67/4);
 
837
        }
 
838
        #endif // ifdef STROBE
 
839
 
 
840
        #ifdef POLICE_STROBE
 
841
        else if (mode == POLICE_STROBE) {
 
842
            // police-like strobe
 
843
            strobe(20/4,40/4);
 
844
            strobe(40/4,80/4);
 
845
        }
 
846
        #endif // ifdef POLICE_STROBE
 
847
 
 
848
        #ifdef RANDOM_STROBE
 
849
        else if (mode == RANDOM_STROBE) {
 
850
            // pseudo-random strobe
 
851
            uint8_t ms = (34 + (pgm_rand() & 0x3f))>>2;
 
852
            //strobe(ms, ms);
 
853
            set_level(RAMP_SIZE);
 
854
            _delay_4ms(ms);
 
855
            set_level(0);
 
856
            _delay_4ms(ms);
 
857
            //strobe(ms, ms);
 
858
        }
 
859
        #endif // ifdef RANDOM_STROBE
 
860
 
 
861
        #ifdef BIKING_MODE
 
862
        else if (mode == BIKING_MODE) {
 
863
            // 2-level stutter beacon for biking and such
 
864
            biking_mode(RAMP_SIZE/2, RAMP_SIZE);
 
865
        }
 
866
        #endif  // ifdef BIKING_MODE
 
867
 
 
868
        #ifdef BIKING_MODE2
 
869
        else if (mode == BIKING_MODE2) {
 
870
            // 2-level stutter beacon for biking and such
 
871
            biking_mode(RAMP_SIZE/4, RAMP_SIZE/2);
 
872
        }
 
873
        #endif  // ifdef BIKING_MODE
 
874
 
 
875
        #ifdef SOS
 
876
        else if (mode == SOS) { SOS_mode(); }
 
877
        #endif // ifdef SOS
 
878
 
 
879
        #ifdef HEART_BEACON
 
880
        else if (mode == HEART_BEACON) {
 
881
            set_mode(RAMP_SIZE);
 
882
            _delay_4ms(1);
 
883
            set_mode(0);
 
884
            _delay_4ms(250/4);
 
885
            set_mode(RAMP_SIZE);
 
886
            _delay_4ms(1);
 
887
            set_mode(0);
 
888
            _delay_4ms(750/4);
 
889
        }
 
890
        #endif
 
891
 
 
892
        #ifdef PARTY_STROBE12
 
893
        else if (mode == PARTY_STROBE12) {
 
894
            party_strobe_loop(1,79);
 
895
        }
 
896
        #endif
 
897
 
 
898
        #ifdef PARTY_STROBE24
 
899
        else if (mode == PARTY_STROBE24) {
 
900
            party_strobe_loop(0,41);
 
901
        }
 
902
        #endif
 
903
 
 
904
        #ifdef PARTY_STROBE60
 
905
        else if (mode == PARTY_STROBE60) {
 
906
            party_strobe_loop(0,15);
 
907
        }
 
908
        #endif
 
909
 
 
910
        #ifdef PARTY_VARSTROBE1
 
911
        else if (mode == PARTY_VARSTROBE1) {
 
912
            uint8_t j, speed;
 
913
            for(j=0; j<66; j++) {
 
914
                if (j<33) { speed = j; }
 
915
                else { speed = 66-j; }
 
916
                party_strobe(1,(speed+33-6)<<1);
 
917
            }
 
918
        }
 
919
        #endif
 
920
 
 
921
        #ifdef PARTY_VARSTROBE2
 
922
        else if (mode == PARTY_VARSTROBE2) {
 
923
            uint8_t j, speed;
 
924
            for(j=0; j<100; j++) {
 
925
                if (j<50) { speed = j; }
 
926
                else { speed = 100-j; }
 
927
                party_strobe(0, speed+9);
 
928
            }
 
929
        }
 
930
        #endif
 
931
 
 
932
        #ifdef BATTCHECK
 
933
        // battery check mode, show how much power is left
 
934
        else if (mode == BATTCHECK) {
 
935
            _delay_500ms();
 
936
            #ifdef BATTCHECK_VpT
 
937
            // blink out volts and tenths
 
938
            uint8_t result = battcheck();
 
939
            blink(result >> 5, BLINK_SPEED/5);
 
940
            _delay_4ms(BLINK_SPEED*2/3);
 
941
            blink(1,8/4);
 
942
            _delay_4ms(BLINK_SPEED*4/3);
 
943
            blink(result & 0b00011111, BLINK_SPEED/5);
 
944
            #else  // ifdef BATTCHECK_VpT
 
945
            // blink zero to five times to show voltage
 
946
            // (or zero to nine times, if 8-bar mode)
 
947
            // (~0%, ~25%, ~50%, ~75%, ~100%, >100%)
 
948
            blink(battcheck(), BLINK_SPEED/4);
 
949
            #endif  // ifdef BATTCHECK_VpT
 
950
            // wait between readouts
 
951
            _delay_s(); _delay_s();
 
952
        }
 
953
        #endif // ifdef BATTCHECK
 
954
 
 
955
        #ifdef GOODNIGHT
 
956
        // "good night" mode, slowly ramps down and shuts off
 
957
        else if (mode == GOODNIGHT) {
 
958
            uint8_t i, j;
 
959
            // signal that this is *not* the STEADY mode
 
960
            blink(2, BLINK_SPEED/16);
 
961
            #define GOODNIGHT_TOP (RAMP_SIZE/6)
 
962
            // ramp up instead of going directly to the top level
 
963
            // (probably pointless in this UI)
 
964
            /*
 
965
            for (i=1; i<=GOODNIGHT_TOP; i++) {
 
966
                set_mode(i);
 
967
                _delay_4ms(2*RAMP_TIME/RAMP_SIZE/4);
 
968
            }
 
969
            */
 
970
            // ramp down over about an hour
 
971
            for(i=GOODNIGHT_TOP; i>=1; i--) {
 
972
                set_mode(i);
 
973
                // how long the down ramp should last, in seconds
 
974
                #define GOODNIGHT_TIME 60*60
 
975
                // how long does _delay_s() actually last, in seconds?
 
976
                // (calibrate this per driver, probably)
 
977
                #define ONE_SECOND 1.03
 
978
                #define GOODNIGHT_STEPS (1+GOODNIGHT_TOP)
 
979
                #define GOODNIGHT_LOOPS (uint8_t)((GOODNIGHT_TIME) / ((2*ONE_SECOND) * GOODNIGHT_STEPS))
 
980
                // NUM_LOOPS = (60*60) / ((2*ONE_SECOND) * (1+MODE_LOW-MODE_MOON))
 
981
                // (where ONE_SECOND is how many seconds _delay_s() actually lasts)
 
982
                // (in my case it's about 0.89)
 
983
                for(j=0; j<GOODNIGHT_LOOPS; j++) {
 
984
                    _delay_s();
 
985
                    _delay_s();
 
986
                    //_delay_ms(10);
 
987
                }
 
988
            }
 
989
            poweroff();
 
990
        }
 
991
        #endif // ifdef GOODNIGHT
 
992
 
 
993
        else {  // shouldn't happen  (compiler omits this entire clause)
 
994
        }
 
995
        fast_presses = 0;
 
996
 
 
997
 
 
998
        #ifdef VOLTAGE_MON
 
999
        //if (ADCSRA & (1 << ADIF)) {  // if a voltage reading is ready
 
1000
        {  // nope, always execute
 
1001
            //voltage = ADCH;  // get the waiting value
 
1002
            voltage = get_voltage();  // get a new value, first is unreliable
 
1003
            // See if voltage is lower than what we were looking for
 
1004
            if (voltage < ADC_LOW) {
 
1005
                lowbatt_cnt ++;
 
1006
            } else {
 
1007
                lowbatt_cnt = 0;
 
1008
            }
 
1009
            // See if it's been low for a while, and maybe step down
 
1010
            if (lowbatt_cnt >= 8) {
 
1011
                // DEBUG: blink on step-down:
 
1012
                //set_level(0);  _delay_ms(100);
 
1013
 
 
1014
                if (mode != STEADY) {
 
1015
                    // step "down" from special modes to medium-low
 
1016
                    mode_idx = 1;
 
1017
                    //mode = STEADY;
 
1018
                    ramp_level = RAMP_SIZE/4;
 
1019
                }
 
1020
                else {
 
1021
                    if (ramp_level > 1) {  // solid non-moon mode
 
1022
                        // drop by 50% each time
 
1023
                        ramp_level = (actual_level >> 1);
 
1024
                    } else { // Already at the lowest mode
 
1025
                        // Turn off the light
 
1026
                        poweroff();
 
1027
                    }
 
1028
                }
 
1029
                set_mode(ramp_level);
 
1030
                target_level = ramp_level;
 
1031
                //save_mode();  // we didn't actually change the mode
 
1032
                lowbatt_cnt = 0;
 
1033
                // Wait before lowering the level again
 
1034
                _delay_s();
 
1035
            }
 
1036
 
 
1037
            // Make sure conversion is running for next time through
 
1038
            // (not relevant with thermal regulation also active)
 
1039
            //ADCSRA |= (1 << ADSC);
 
1040
        }
 
1041
        #endif  // ifdef VOLTAGE_MON
 
1042
 
 
1043
        #ifdef THERMAL_REGULATION
 
1044
        if ((mode == STEADY) || (mode == TURBO) || (mode == THERM_CALIBRATION_MODE)) {
 
1045
            // how far ahead should we predict?
 
1046
            #define THERM_PREDICTION_STRENGTH 4
 
1047
            // how proportional should the adjustments be?
 
1048
            #define THERM_DIFF_ATTENUATION 4
 
1049
            // how low is the lowpass filter?
 
1050
            #define THERM_LOWPASS 8
 
1051
            // lowest ramp level; never go below this (sanity check)
 
1052
            #define THERM_FLOOR (RAMP_SIZE/4)
 
1053
            // highest temperature allowed
 
1054
            // (convert configured value to 13.2 fixed-point)
 
1055
            #define THERM_CEIL (therm_ceil<<2)
 
1056
            // acceptable temperature window size in C
 
1057
            #define THERM_WINDOW_SIZE 8
 
1058
 
 
1059
            int16_t temperature = current_temperature();
 
1060
            int16_t projected;  // Fight the future!
 
1061
            int16_t diff;
 
1062
 
 
1063
            // initial setup, only once
 
1064
            if (first_temp_reading) {
 
1065
                first_temp_reading = 0;
 
1066
                for (uint8_t t=0; t<THERM_HISTORY_SIZE; t++)
 
1067
                    temperatures[t] = temperature;
 
1068
            }
 
1069
 
 
1070
            // rotate measurements and add a new one
 
1071
            for(uint8_t t=0; t<THERM_HISTORY_SIZE-1; t++) {
 
1072
                temperatures[t] = temperatures[t+1];
 
1073
            }
 
1074
            temperatures[THERM_HISTORY_SIZE-1] = temperature;
 
1075
 
 
1076
            // guess what the temp will be several seconds in the future
 
1077
            diff = temperature - temperatures[0];
 
1078
            projected = temperature + (diff<<THERM_PREDICTION_STRENGTH);
 
1079
 
 
1080
            // never step down in thermal calibration mode
 
1081
            if (mode == THERM_CALIBRATION_MODE) {
 
1082
                if (first_loop) {
 
1083
                    // TODO: blink out current temperature limit
 
1084
                    // let user set default or max limit?
 
1085
                    therm_ceil = DEFAULT_THERM_CEIL;
 
1086
                    set_mode(RAMP_SIZE/4);
 
1087
                    save_state();
 
1088
                    _delay_s();
 
1089
                    _delay_s();
 
1090
                    // turn power up all the way for calibration purposes
 
1091
                    set_mode(RAMP_SIZE);
 
1092
                }
 
1093
                // use the current temperature as the new ceiling value
 
1094
                //tempCeil = projected >> 2;
 
1095
                // less aggressive prediction
 
1096
                therm_ceil = (temperature + (diff<<(THERM_PREDICTION_STRENGTH-1))) >> 2;
 
1097
                // Don't let user exceed maximum limit
 
1098
                if (therm_ceil > MAX_THERM_CEIL) {
 
1099
                    therm_ceil = MAX_THERM_CEIL;
 
1100
                }
 
1101
                // save state periodically (but not too often)
 
1102
                if (loop_count > 3)
 
1103
                {
 
1104
                    loop_count = 0;
 
1105
                    save_state();
 
1106
                }
 
1107
                // don't repeat for a little while
 
1108
                _delay_500ms();
 
1109
            }
 
1110
 
 
1111
            // too hot, step down (maybe)
 
1112
            else if (projected >= THERM_CEIL) {
 
1113
                underheat_count = 0;  // we're definitely not too cold
 
1114
                if (overheat_count > THERM_LOWPASS) {
 
1115
                    overheat_count = 0;
 
1116
 
 
1117
                    // how far above the ceiling?
 
1118
                    int16_t exceed = (projected - THERM_CEIL) >> THERM_DIFF_ATTENUATION;
 
1119
                    if (exceed < 1) { exceed = 1; }
 
1120
                    uint8_t stepdown = actual_level - exceed;
 
1121
                    // never go under the floor; zombies in the cellar
 
1122
                    if (stepdown < THERM_FLOOR) {
 
1123
                        stepdown = THERM_FLOOR;
 
1124
                    }
 
1125
                    // avoid a bug: stepping "down" from moon to THERM_FLOOR
 
1126
                    // if user turned the light down during lowpass period
 
1127
                    if (stepdown > target_level) {
 
1128
                        stepdown = target_level;
 
1129
                    }
 
1130
                    // really, don't try to regulate below the floor
 
1131
                    if (actual_level > THERM_FLOOR) {
 
1132
                        set_mode(stepdown);
 
1133
                    }
 
1134
                }
 
1135
                else {
 
1136
                    overheat_count ++;
 
1137
                }
 
1138
            }
 
1139
            else {  // not too hot
 
1140
                overheat_count = 0;  // we're definitely not too hot
 
1141
                // too cold?  step back up?
 
1142
                if (projected < (THERM_CEIL - (THERM_WINDOW_SIZE<<2))) {
 
1143
                    if (underheat_count > (THERM_LOWPASS/2)) {
 
1144
                        underheat_count = 0;
 
1145
                        // never go above the user's requested level
 
1146
                        if (actual_level < target_level) {
 
1147
                            set_mode(actual_level + 1);  // step up slowly
 
1148
                        }
 
1149
                    } else {
 
1150
                        underheat_count ++;
 
1151
                    }
 
1152
                }
 
1153
            }
 
1154
        }
 
1155
        #endif  // ifdef THERMAL_REGULATION
 
1156
 
 
1157
        first_loop = 0;
 
1158
        loop_count ++;
 
1159
    }
 
1160
 
 
1161
}