2
* "Crescendo" firmware (ramping UI for clicky-switch lights)
4
* Copyright (C) 2017 Selene Scriven
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.
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.
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/>.
25
* GND -|4 5|- PWM (Nx7135)
29
* I use these fuse settings on attiny13
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.
40
* Same for off-time capacitor values. Measure, don't guess.
42
// Choose your MCU here, or in the build script
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"
53
* =========================================================================
54
* Settings to modify per driver
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
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
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
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
96
// ../../bin/level_calc.py 3 80 7135 3 0.25 140 7135 3 1.5 660 FET 1 10 1200
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
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
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
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
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
116
// Enable battery indicator mode?
118
#define USE_BATTCHECK
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
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)
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
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)
140
// Modes start at 255 and count down
145
#define BATTCHECK 251
149
#define MEMTOGGLE // runtime config for memory (requires MEMORY)
151
#ifdef THERMAL_REGULATION
152
#define THERM_CALIBRATION_MODE 248 // let user configure temperature limit
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
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
175
#if defined(MEMTOGGLE) || defined(THERM_CALIBRATION_MODE)
179
// Calibrate voltage and OTC in this file:
180
#include "tk-calibration.h"
183
* =========================================================================
186
// Ignore a spurious warning, we did the cast on purpose
187
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
189
#include <avr/pgmspace.h>
190
#include <avr/interrupt.h>
191
#include <avr/eeprom.h>
192
#include <avr/sleep.h>
195
#define OWN_DELAY // Don't use stock delay functions.
196
#define USE_DELAY_4MS
199
#define USE_FINE_DELAY
201
#define USE_DELAY_S // Also use _delay_s(), not just _delay_ms()
202
#include "tk-delay.h"
204
#ifdef THERMAL_REGULATION
207
#include "tk-voltage.h"
210
#include "tk-random.h"
217
// Config option variables
221
#ifdef THERMAL_REGULATION
222
uint8_t therm_ceil = DEFAULT_THERM_CEIL;
224
// Other state variables
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
266
#ifdef PARTY_STROBE12
269
#ifdef PARTY_STROBE24
272
#ifdef PARTY_STROBE60
275
#ifdef PARTY_VARSTROBE1
278
#ifdef PARTY_VARSTROBE2
286
// Modes (gets set when the light starts up based on saved config values)
287
PROGMEM const uint8_t ramp_ch1[] = { RAMP_CH1 };
289
PROGMEM const uint8_t ramp_ch2[] = { RAMP_CH2 };
292
PROGMEM const uint8_t ramp_ch3[] = { RAMP_CH3 };
294
#define RAMP_SIZE sizeof(ramp_ch1)
296
void _delay_500ms() {
297
_delay_4ms(HALF_SECOND/4);
300
#if defined(MEMORY) || defined(CONFIG_MODE)
301
#if (ATTINY == 85) || (ATTINY == 45)
302
#define EEP_WEAR_LVL_LEN 128
304
#define EEP_WEAR_LVL_LEN 64
306
#define EEP_WEAR_LVL_LEN 32
310
void save_mode() { // save the current mode index (with wear leveling)
311
// only save when memory is enabled
313
eeprom_write_byte((uint8_t *)(eepos), 0xff); // erase old state
314
eeprom_write_byte((uint8_t *)(++eepos), 0xff); // erase old state
316
eepos = (eepos+1) & (EEP_WEAR_LVL_LEN-1); // wear leveling, use next cell
318
eeprom_write_byte((uint8_t *)(eepos), mode_idx);
319
// save current brightness
320
eeprom_write_byte((uint8_t *)(eepos+1), ramp_level);
326
#define OPT_memory (EEP_WEAR_LVL_LEN+1)
327
#define OPT_therm_ceil (EEP_WEAR_LVL_LEN+2)
333
eeprom_write_byte((uint8_t *)OPT_memory, memory);
335
#ifdef THERM_CALIBRATION_MODE
336
eeprom_write_byte((uint8_t *)OPT_therm_ceil, therm_ceil);
340
#define save_state save_mode
344
void restore_state() {
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; }
354
#ifdef THERM_CALIBRATION_MODE
356
eep = eeprom_read_byte((uint8_t *)OPT_therm_ceil);
357
if ((eep > 0) && (eep < MAX_THERM_CEIL)) {
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);
367
saved_mode_idx = eep;
368
eep = eeprom_read_byte((const uint8_t *)(eepos+1));
370
saved_ramp_level = eep;
377
#endif // ifdef CONFIG_MODE
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;
389
if (mode_idx >= sizeof(modes)) {
391
// (wrap to steady mode (1), not ramp (0))
397
inline void set_output(uint8_t pwm1, uint8_t pwm2, uint8_t pwm3) {
400
inline void set_output(uint8_t pwm1, uint8_t pwm2) {
402
inline void set_output(uint8_t pwm1) {
414
void set_level(uint8_t level) {
415
actual_level = level;
425
#endif // ifdef RAMP_CH2
426
#endif // ifdef RAMP_CH3
430
// divide PWM speed by 2 for lowest modes,
431
// to make them more stable
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));
441
set_output(pgm_read_byte(ramp_ch1 + level - 1),
442
pgm_read_byte(ramp_ch2 + level - 1));
444
set_output(pgm_read_byte(ramp_ch1 + level - 1));
450
#define set_mode set_level
452
void blink(uint8_t val, uint8_t speed)
456
set_level(BLINK_BRIGHTNESS);
466
void strobe(uint8_t ontime, uint8_t offtime) {
468
inline void strobe(uint8_t ontime, uint8_t offtime) {
472
set_level(RAMP_SIZE);
481
inline void party_strobe(uint8_t ontime, uint8_t offtime) {
482
set_level(RAMP_SIZE);
492
void party_strobe_loop(uint8_t ontime, uint8_t offtime) {
495
party_strobe(ontime, offtime);
501
inline void SOS_mode() {
502
#define SOS_SPEED (200/4)
504
_delay_4ms(SOS_SPEED*5);
505
blink(3, SOS_SPEED*5/2);
506
//_delay_4ms(SOS_SPEED);
508
_delay_s(); _delay_s();
513
inline void biking_mode(uint8_t lo, uint8_t hi) {
514
#ifdef FULL_BIKING_MODE
527
#else // smaller bike mode
528
// small/minimal version
535
#endif // ifdef FULL_BIKING_MODE
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)
549
temp += get_temperature();
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);
557
#endif // ifdef THERMAL_REGULATION
562
inline void poweroff() {
566
// Power down as many components as possible
567
ADCSRA &= ~(1<<7); //ADC off
568
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
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
583
// "buzz" for a while to indicate the active toggle window
585
// if the user didn't click, reset the value and return
590
#endif // ifdef CONFIG_MODE
595
// Set PWM pin to output
596
DDRB |= (1 << PWM_PIN); // enable main channel
598
DDRB |= (1 << ALT_PWM_PIN); // enable second channel
601
// enable second PWM counter (OC1B) and third channel (FET, PB4)
602
DDRB |= (1 << FET_PWM_PIN); // enable third channel (DDB4)
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...)
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...)
613
// Second PWM counter is ... weird
615
GTCCR = _BV (COM1B1) | _BV (PWM1B);
616
OCR1C = 255; // Set ceiling value to maximum
620
uint8_t mode_override = 0;
621
// Read config values and saved state
625
// check button press time, unless the mode is overridden
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
632
// Long press, use memorized level
633
// ... or reset to the first mode
641
if (memory) { mode_override = MEMORY; }
643
mode_override = MEMORY;
644
#endif // ifdef MEMTOGGLE
645
#endif // ifdef MEMORY
652
// Turn features on or off as needed
654
#ifndef THERMAL_REGULATION
663
uint8_t lowbatt_cnt = 0;
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;
673
uint8_t first_loop = 1;
674
uint8_t loop_count = 0;
676
if (mode_idx < sizeof(modes)) mode = modes[mode_idx];
677
else mode = mode_idx;
679
#if defined(VOLTAGE_MON) && defined(THERMAL_REGULATION)
680
// make sure a voltage reading has started, for LVP purposes
685
if (0) { // This can't happen
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
698
// turn memory on/off
699
// (click during the "buzz" to change the setting)
700
toggle(&memory, ++t);
701
#endif // ifdef MEMTOGGLE
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);
712
// if config mode ends with no changes,
713
// pretend this is the first loop
716
#endif // ifdef CONFIG_MODE
720
else if (mode_override == MEMORY) {
724
// moon mode for half a second
726
// if the user taps quickly, go to the real moon mode
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
736
// restart as if this were the first loop
741
// smooth ramp mode, lets user select any output level
743
set_mode(ramp_level); // turn light on
745
// ramp up by default
746
//if (fast_presses == 0) {
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
755
// triple-tap to enter turbo
756
else if (fast_presses == 2) {
757
next_mode_num = mode_idx + 2; // bypass "steady" mode
760
// wait a bit before actually ramping
761
// (give the user a chance to select moon, or double-tap)
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)
768
// ramp up on single tap
769
// (cancel earlier reversal)
770
if (fast_presses == 1) {
773
// don't want this confusing us any more
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);
783
((ramp_dir > 0) && (ramp_level >= RAMP_SIZE))
785
((ramp_dir < 0) && (ramp_level <= 1))
800
ramp_dir = -ramp_dir;
803
else if (mode == STEADY) {
804
// normal flashlight mode
806
set_mode(ramp_level);
807
target_level = ramp_level;
809
// User has 0.5s to tap again to advance to the next mode
810
//next_mode_num = 255;
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)
818
else if (mode == TURBO) {
819
// turbo is special because it's easier to handle that way
822
target_level = RAMP_SIZE;
824
//next_mode_num = 255;
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)
834
else if (mode == STROBE) {
835
// 10Hz tactical strobe
838
#endif // ifdef STROBE
841
else if (mode == POLICE_STROBE) {
842
// police-like strobe
846
#endif // ifdef POLICE_STROBE
849
else if (mode == RANDOM_STROBE) {
850
// pseudo-random strobe
851
uint8_t ms = (34 + (pgm_rand() & 0x3f))>>2;
853
set_level(RAMP_SIZE);
859
#endif // ifdef RANDOM_STROBE
862
else if (mode == BIKING_MODE) {
863
// 2-level stutter beacon for biking and such
864
biking_mode(RAMP_SIZE/2, RAMP_SIZE);
866
#endif // ifdef BIKING_MODE
869
else if (mode == BIKING_MODE2) {
870
// 2-level stutter beacon for biking and such
871
biking_mode(RAMP_SIZE/4, RAMP_SIZE/2);
873
#endif // ifdef BIKING_MODE
876
else if (mode == SOS) { SOS_mode(); }
880
else if (mode == HEART_BEACON) {
892
#ifdef PARTY_STROBE12
893
else if (mode == PARTY_STROBE12) {
894
party_strobe_loop(1,79);
898
#ifdef PARTY_STROBE24
899
else if (mode == PARTY_STROBE24) {
900
party_strobe_loop(0,41);
904
#ifdef PARTY_STROBE60
905
else if (mode == PARTY_STROBE60) {
906
party_strobe_loop(0,15);
910
#ifdef PARTY_VARSTROBE1
911
else if (mode == PARTY_VARSTROBE1) {
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);
921
#ifdef PARTY_VARSTROBE2
922
else if (mode == PARTY_VARSTROBE2) {
924
for(j=0; j<100; j++) {
925
if (j<50) { speed = j; }
926
else { speed = 100-j; }
927
party_strobe(0, speed+9);
933
// battery check mode, show how much power is left
934
else if (mode == BATTCHECK) {
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);
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();
953
#endif // ifdef BATTCHECK
956
// "good night" mode, slowly ramps down and shuts off
957
else if (mode == GOODNIGHT) {
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)
965
for (i=1; i<=GOODNIGHT_TOP; i++) {
967
_delay_4ms(2*RAMP_TIME/RAMP_SIZE/4);
970
// ramp down over about an hour
971
for(i=GOODNIGHT_TOP; i>=1; 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++) {
991
#endif // ifdef GOODNIGHT
993
else { // shouldn't happen (compiler omits this entire clause)
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) {
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);
1014
if (mode != STEADY) {
1015
// step "down" from special modes to medium-low
1018
ramp_level = RAMP_SIZE/4;
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
1029
set_mode(ramp_level);
1030
target_level = ramp_level;
1031
//save_mode(); // we didn't actually change the mode
1033
// Wait before lowering the level again
1037
// Make sure conversion is running for next time through
1038
// (not relevant with thermal regulation also active)
1039
//ADCSRA |= (1 << ADSC);
1041
#endif // ifdef VOLTAGE_MON
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
1059
int16_t temperature = current_temperature();
1060
int16_t projected; // Fight the future!
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;
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];
1074
temperatures[THERM_HISTORY_SIZE-1] = temperature;
1076
// guess what the temp will be several seconds in the future
1077
diff = temperature - temperatures[0];
1078
projected = temperature + (diff<<THERM_PREDICTION_STRENGTH);
1080
// never step down in thermal calibration mode
1081
if (mode == THERM_CALIBRATION_MODE) {
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);
1090
// turn power up all the way for calibration purposes
1091
set_mode(RAMP_SIZE);
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;
1101
// save state periodically (but not too often)
1107
// don't repeat for a little while
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) {
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;
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;
1130
// really, don't try to regulate below the floor
1131
if (actual_level > THERM_FLOOR) {
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
1155
#endif // ifdef THERMAL_REGULATION