29
29
#include <avr/interrupt.h>
30
30
#include <avr/wdt.h>
31
31
#include <avr/eeprom.h>
32
#include <avr/sleep.h>
33
#include <avr/power.h>
34
36
* configure the driver here. For fixed modes, also change the order and/or
35
37
* function variables in the initial EEPROM image down below to your needs.
37
#define NUM_MODES 10 // how many modes should the flashlight have
38
#define PWM_PIN PB1 // look at your PCB to find out which pin the FET
39
#define PWM_OCR OCR0B // or 7135 is connected to, then consult the
40
// data-sheet on which pin and OCR to use
42
#define PWM_TCR 0x21 // phase corrected PWM. Set to 0x81 for PB0,
45
//#define PROGRAMMABLE // #define for programmable modes
46
#define NUM_PROG_CLICKS 6 // how many clicks to enter programming mode
47
#define MEMORY // #undef to disable mode memory
50
* override configurations if built from an IDE config
52
* IDE build "Programmable", 3 modes, memory, 6 clicks to go into prog mode
54
#ifdef BUILD_PROGRAMMABLE
61
#undef NUM_PROG_CLICKS
62
#define NUM_PROG_CLICKS 6
66
* IDE build "Fixed Modes", Low-Med-High-Lowest with memory
78
* necessary typedef and forward declarations
82
typedef void (*mode_func)(uint8_t, uint8_t, uint8_t);
83
void const_level(uint8_t mode, uint8_t flags, uint8_t setup);
85
typedef void (*mode_func)(uint8_t);
39
#define PWM_PIN PB1 // look at your PCB to find out which pin the FET
40
#define PWM_LVL OCR0B // or 7135 is connected to, then consult the
41
// data-sheet on which pin and OCR to use
43
#define PWM_TCR 0x21 // phase corrected PWM. Set to 0x81 for PB0,
46
#define NUM_MODES 3 // how many modes should the flashlight have
47
#define NUM_EXT_CLICKS 6 // how many clicks to enter programming mode
48
#define EXTENDED_MODES // enable to make all mode lines available
49
#define PROGRAMMABLE // user can re-program the mode slots
50
#define PROGHELPER // indicate programming timing by short flashes
51
//#define NOMEMORY // #define to disable mode memory
54
// no sense to include programming code if extended modes are disabled
55
#ifndef EXTENDED_MODES
59
// no need for the programming helper if programming is disabled
65
* necessary typedefs and forward declarations
67
typedef void(*mode_func)(uint8_t);
87
* working copy of the first part of the eeprom, which will be loaded on
88
* start up. If you change anything here, make sure to bring the EE_* #defines
93
uint8_t mode; // index of regular mode slot last used
94
uint8_t clicks; // number of consecutive taps so far
95
uint8_t last_click; // type of last tap (short, long, none)
96
uint8_t target_mode; // index of slot selected for reprogramming
97
uint8_t chosen_mode; // index of chosen mode-line to be stored
98
uint8_t prog_stage; // keep track of programming stages
99
uint8_t extended; // whether to use normal or extended mode list
100
uint8_t ext_mode; // current mode-line in extended mode
101
uint8_t mode_arr[NUM_MODES]; // array holding offsets to the mode lines for
102
// the configured modes
86
105
void const_level(uint8_t mode);
87
106
void strobe(uint8_t mode);
88
void sos(uint8_t mode);
89
void alpine(uint8_t mode);
90
void fade(uint8_t mode);
94
110
* array holding pointers to the mode functions
96
mode_func mode_func_arr[] = {
112
mode_func mode_func_arr[] =
110
121
* define some mode configurations. Format is
111
122
* "offset in mode_func_arr", "parameter 1", "parameter 2", "parameter 3"
113
#define MODE_MIN 0x00, 0x01, 0x00, 0x00 // lowest possible level
114
#define MODE_MAX 0x00, 0xFF, 0x00, 0x00 // highest possible level
115
#define MODE_LOW 0x00, 0x10, 0x00, 0x00 // low level, 1/16th of maximum
116
#define MODE_MED 0x00, 0x80, 0x00, 0x00 // medium level, half of maximum
117
#define MODE_SOS 0x01, 0x00, 0x00, 0x00 // can't have a flashlight without SOS, no sir
118
#define MODE_STROBE 0x02, 0x14, 0xFF, 0x00 // same for strobe modes
119
#define MODE_POLICE 0x02, 0x14, 0x0A, 0x01
120
#define MODE_BEACON 0x02, 0x14, 0x01, 0x0A // beacon might actually be useful
121
#define MODE_ALPINE 0x03, 0x00, 0x00, 0x00 // might as well throw this one in, too
122
#define MODE_FADE 0x04, 0xFF, 0x01, 0x01 // fade in/out. Just a gimmick
124
#define MODE_LVL001 0x00, 0x01, 0x00, 0x00 // lowest possible level
125
#define MODE_LVL002 0x00, 0x02, 0x00, 0x00 // .
126
#define MODE_LVL004 0x00, 0x04, 0x00, 0x00 // .
127
#define MODE_LVL008 0x00, 0x08, 0x00, 0x00 // .
128
#define MODE_LVL016 0x00, 0x10, 0x00, 0x00 // .
129
#define MODE_LVL032 0x00, 0x20, 0x00, 0x00 // .
130
#define MODE_LVL064 0x00, 0x40, 0x00, 0x00 // .
131
#define MODE_LVL128 0x00, 0x80, 0x00, 0x00 // .
132
#define MODE_LVL255 0x00, 0xFF, 0x00, 0x00 // highest possible level
133
#define MODE_STROBE 0x01, 0x14, 0xFF, 0x00 // simple strobe mode
134
#define MODE_POLICE 0x01, 0x14, 0x0A, 0x01 // police type strobe
135
#define MODE_BEACON 0x01, 0x14, 0x01, 0x0A // beacon, might actually be useful
136
#define MODE_EMPTY 0xFF, 0xFF, 0xFF, 0xFF // empty mode slot
125
139
* initialise EEPROM
126
140
* This will be used to build the initial eeprom image.
129
const uint8_t EEMEM eeprom[64] =
130
{ 0x00, 0x00, 0x00, 0x00,
131
0x00, 0x00, 0x00, 0x00,
132
0x00, 0x00, 0x00, 0x00,
133
0x00, 0x00, 0x00, 0x00,
134
0x00, 0x00, 0x00, 0x00,
135
0x00, 0x00, 0x00, 0x00,
136
// mode configuration starts here. Format is:
137
// offset in mode_func_arr, func data1, func data2, func data3
150
const uint8_t EEMEM eeprom[64] =
151
{ 0x00, 0x00, 0x00, 0x00,
152
0x00, 0x00, 0x00, 0x00,
153
0x00, 0x00, 0x00, 0x00,
154
0x00, 0x00, 0x00, 0x00,
155
0x00, 0x00, 0x00, 0x00,
156
0x00, 0x00, 0x00, 0x00,
157
// mode configuration starts here. Format is:
158
// offset in mode_func_arr, func data1, func data2, func data3
170
#endif //PROGRAMMABLE
142
const uint8_t EEMEM eeprom[64] =
143
{ 0x00, 0x00, 0x00, 0xFF,
144
0xFF, 0x00, 0x00, 0x00,
145
0x03, 0x06, 0x08, 0x00, // initial mode programming
146
0x00, 0x00, 0x00, 0x00,
147
// mode configuration starts here. Format is:
148
// offset in mode_func_arr, func data1, func data2, func data3
173
164
* The serious stuff begins below this line
178
* addresses of permanent memory variables in EEPROM
169
* override #defines set above if called with build profiles from the IDE
180
#define EE_MODE 0 // mode to start in
181
#define EE_CLICKS 1 // number of consecutive clicks so far
182
#define EE_PROGSTAGE 2 // current stage during programming
183
#define EE_PROGMODE 3 // currently programming mode x
184
#define EE_PROGFUNC 4 // index of function currently being configured
185
#define EE_PROGFLAGS 5 // misc flags used during programming
186
#define EE_MODEDATA_BACKUP 20 // Backup of mode data while programming a mode
187
#define EE_MODEDATA_BASE 24 // base address of mode data array
188
// space for 4 bytes per mode, 10 slots
172
#ifdef BUILD_PROGRAMMABLE
174
#undef EXTENDED_MODES
176
#define EXTENDED_MODES
183
#undef EXTENDED_MODES
185
#define EXTENDED_MODES
190
#undef EXTENDED_MODES
191
* Flags used by mode programming
195
* addresses of permanent memory variables in EEPROM. If you change anything
196
* here, make sure to update struct State_t
193
#define PF_SETUP_COMPLETE 0 // function setup is complete
198
#define EE_MODE 0 // index of regular mode slot last used
199
#define EE_CLICKS 1 // number of consecutive taps so far
200
#define EE_LAST_CLICK 2 // type of last tap (short, long, none)
201
#define EE_TARGETMODE 3 // index of slot selected for reprogramming
202
#define EE_CHOSENMODE 4 // index of chosen mode-line to be store
203
#define EE_PROGSTAGE 5 // keep track of programming stages
204
#define EE_EXTENDED 6 // whether to use normal or extended mode list
205
#define EE_EXTMODE 7 // current mode-line in extended mode
206
#define EE_MODES_BASE 8 // start of mode slot table
207
#define EE_MODEDATA_BASE 16 // start of mode data array
208
// space for 4 bytes per mode, 10 lines
209
#define NUM_EXT_MODES 12 // number of mode data lines in EEPROM
211
#define EMPTY_MODE 255
197
214
* global variables
201
uint8_t global_flags;
216
uint8_t ticks; // how many times the watchdog timer has been triggered
217
State_t state; // struct holding a partial copy of the EEPROM
205
* We're using the watchdog timer to clear the mode switch indicator
206
* and maybe later monitor the battery voltage
220
* The watchdog timer is called every 250ms and this way we keep track of
221
* whether the light has been turned on for less than a second (up to 4 ticks)
222
* or less than 2 seconds (8 ticks). If PROGHELPER is defined, we also give
223
* hints on when to switch off to follow the programming sequence
211
* flashlight has been switched on longer than timeout for mode switching,
212
* reset the click counter and either store current mode in memory or reset
213
* mode memory to 0, depending on the build configuration.
219
eeprom_write_byte((uint8_t *) EE_MODE, mode);
221
eeprom_write_byte((uint8_t *) EE_MODE, 0);
223
eeprom_write_byte((uint8_t *) EE_CLICKS, 0);
229
* set up the watchdog timer
231
void start_wdt(uint8_t prescaler)
236
* prepare new watchdog config beforehand, as it needs to be set within
237
* four clock cycles after unlocking the WDTCR register.
238
* Set interrupt mode prescaler bits.
240
wdt_mode = ((uint8_t) _BV(WDTIE) | (uint8_t)(prescaler & 0x07));
243
WDTCR = ((uint8_t)_BV(WDCE) | (uint8_t) _BV(WDE)); // unlock register
244
WDTCR = wdt_mode; // set new mode and prescaler
250
* blink blink_cnt times. Useful for debugging
252
void blink(unsigned char blink_cnt)
261
// prepare PWM_PIN for output
262
DDRB |= (uint8_t) (_BV(PWM_PIN));
263
PORTB &= (uint8_t) ~(_BV(PWM_PIN));
265
// blink blink_cnt times
266
while(blink_cnt > 0){
267
PORTB |= (uint8_t) (_BV(PWM_PIN));
269
PORTB &= (uint8_t) ~(_BV(PWM_PIN));
282
* Constant light level
283
* Set PWM to the level stored in the mode's first variable. If driver was
284
* built as programmable, also allows for setting the mode's level by cycling
285
* through all possible levels until the light is switched off. As during
286
* cycling each level has to be stored in EEPROM, this can wear out a mode's
287
* memory cell very rapidly (~400 cycles). Avoid unnecessary programming
291
void const_level(const uint8_t mode, uint8_t flags, uint8_t setup)
293
void const_level(const uint8_t mode)
296
uint8_t level, offset;
298
// calculate offset into mode data array
301
//set up PORTB for output on pin PWM_PIN and set PWM_PIN to low
302
DDRB |= (uint8_t) (_BV(PWM_PIN));
303
PORTB &= (uint8_t) ~(_BV(PWM_PIN));
305
// Initialise PWM on output pin
311
// setup mode. Cycle through all possible light levels and write
312
// the current one to permanent memory. Also, mark config as complete
313
flags |= (uint8_t) _BV(PF_SETUP_COMPLETE);
314
eeprom_write_byte((uint8_t *)EE_PROGFLAGS, flags);
318
eeprom_write_byte((uint8_t *)EE_MODEDATA_BASE + offset + 1, level);
320
TCNT0 = 0; // Reset TCNT0
323
// blink once and pause for one second at lowest, middle and
325
if(level == 0 || level == 128 || level == 255){
337
#endif // PROGRAMMABLE
339
level = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset + 1);
341
TCNT0 = 0; // Reset TCNT0
352
* Delay for ms millisecond
231
/* last_click is initialised to tap_short in main() on startup. By the
232
* time we reach four ticks, we change it to tap_long (more than a
233
* second). After eight ticks (two seconds) we clear last_click.
236
eeprom_write_byte((uint8_t *) EE_LAST_CLICK, tap_none);
241
eeprom_write_byte((uint8_t *)EE_LAST_CLICK, tap_long);
244
/* give hints on when to switch off in programming mode. Programming
245
* stages 1,2 and 4 expect a short tap (0s - 1s), so we signal at
246
* 250ms. Stage 3 expects a long tap (1s - 2s), so we signal at
247
* 1s. Signalling is done by toggling the PWM-level's MSB for 100ms.
249
if(state.prog_stage == prog_3){
250
PWM_LVL ^= (uint8_t) 0x80;
252
PWM_LVL ^= (uint8_t) 0x80;
258
if(state.prog_stage == prog_1
259
|| state.prog_stage == prog_2
260
|| state.prog_stage == prog_4)
262
PWM_LVL ^= (uint8_t) 0x80;
264
PWM_LVL ^= (uint8_t) 0x80;
268
#endif // PROGRAMMABLE
276
* set up the watchdog timer to trigger an interrupt every 250ms
278
inline void start_wdt()
283
* prepare new watchdog config beforehand, as it needs to be set within
284
* four clock cycles after unlocking the WDTCR register.
285
* Set interrupt mode prescaler bits.
287
wdt_mode = ((uint8_t) _BV(WDTIE)
288
| (uint8_t) (WDTO_250MS & (uint8_t) 0x07)
289
| (uint8_t) ((WDTO_250MS & (uint8_t) 0x08) << 2));
295
WDTCR = ((uint8_t) _BV(WDCE) | (uint8_t) _BV(WDE));
297
// set new mode and prescaler
304
* Delay for ms milliseconds
353
305
* Calling the avr-libc _delay_ms() with a variable argument will pull in the
354
306
* whole floating point handling code and increase flash image size by about
357
309
static void inline sleep_ms(uint16_t ms)
450
379
void strobe(uint8_t mode)
452
uint8_t offset, pulse, count, pause, i;
454
// calculate offset into mode data array
457
pulse = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset + 1);
458
count = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset + 2);
459
pause = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset + 3);
463
for(i = 0; i < count; ++i){
464
PORTB |= _BV(PWM_PIN);
466
PORTB &= ~(_BV(PWM_PIN));
467
sleep_ms(pulse << 1); // 2 * pulse
475
* This is more or less a demonstration with no real use I can see.
476
* Mode uses three variables:
477
* max: maximum level the light will rise to
478
* rise: value the level is increased by during rising cycle
479
* fall: value the level is decreased by during falling cycle
481
* Can produce triangle or saw tooth curves: /\/\... /|/|... |\|\...
482
* As I said, nice toy with no real world use ;)
484
void fade(uint8_t mode)
486
uint8_t offset, max, rise, fall, level, oldlevel;
488
// calculate offset into mode data array
491
max = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset + 1);
492
rise = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset + 2);
493
fall = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset + 3);
495
DDRB |= (uint8_t) _BV(PWM_PIN); // Set PORTB as Output
496
PORTB &= (uint8_t) ~(_BV(PWM_PIN));
498
// Initialise PWM depending on selected output pin
508
if(oldlevel > level) // catch integer overflow
519
if(oldlevel < level) // catch integer underflow
528
#endif // not PROGRAMMABLE
533
* back up a given mode so it can be restored if programming is aborted
535
void inline backup_mode(const uint8_t mode)
537
uint8_t buff, offset;
540
// calculate mode * 4 without the compiler pulling in the full-blown
541
// multiplication lib (would add ~200 bytes of code in flash image)
544
// copy the for bytes defining the mode to the backup area
545
for(uint8_t i = 0; i < 4; ++i){
546
buff = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset + i);
547
eeprom_write_byte((uint8_t *)EE_MODEDATA_BACKUP + i, buff);
552
* restore a given mode from previously saved backup
554
void restore_mode(const uint8_t mode)
556
uint8_t buff, offset;
560
for(uint8_t i = 0; i < 4; ++i){
561
buff = eeprom_read_byte((uint8_t *)EE_MODEDATA_BACKUP + i);
562
eeprom_write_byte((uint8_t *)EE_MODEDATA_BASE + offset + i, buff);
567
* strobe for one second to indicate chances to abort programming
577
// set PWM pin for output
578
DDRB |= (uint8_t) _BV(PWM_PIN);
579
PORTB &= (uint8_t) ~(_BV(PWM_PIN));
581
// strobe for one second
582
for(uint8_t i = 0; i < 20; ++i){
583
PORTB |= (uint8_t) _BV(PWM_PIN);
585
PORTB &= (uint8_t) ~(_BV(PWM_PIN));
595
* First stage of programming.
596
* We give warning by strobing for 2 seconds. If the light is switched off
597
* during strobe, abort programming. Wait 1 second after strobing and then
598
* start cycling through the mode slots. Mode slot is indicated by blinking
599
* x times, then sleeping 2 seconds. If light is switched off during this
600
* time, proceed programming with second stage for the selected mode
602
static void inline progstage0()
606
// clear progflags in eeprom and signal for 2 seconds, wait another .5s
607
eeprom_write_byte((uint8_t *)EE_PROGFLAGS, 0);
611
// user didn't abort, advance programming stage and cycle through
613
eeprom_write_byte((uint8_t *)EE_PROGSTAGE, 1);
616
while(mode < NUM_MODES){
617
// blink to indicate the mode slot, then give user 2 seconds to chose
619
eeprom_write_byte((uint8_t *)EE_PROGMODE, mode);
626
// no mode selected, give signal and leave programming mode
627
eeprom_write_byte((uint8_t *)EE_PROGSTAGE, 0);
632
* second stage of programming.
633
* Back up old mode data and set up advance to stage 3
635
static void inline progstage1(const uint8_t mode)
637
// back up old mode data, set programming to stage 2, function to first
638
// in array and clear programming flags
640
eeprom_write_byte((uint8_t *)EE_PROGSTAGE, 2);
641
eeprom_write_byte((uint8_t *)EE_PROGFUNC, 0);
642
eeprom_write_byte((uint8_t *)EE_PROGFLAGS, 0);
646
* Third stage of mode programming.
647
* If current mode func has not finished setup, call it in setup mode.
648
* Otherwise give user the choice of discarding this and moving on to the next
649
* function (if there is any left), or locking the mode in. If user does
650
* nothing, restore old mode and exit programming
652
static void inline progstage2(const uint8_t mode, uint8_t func, uint8_t flags)
658
// only try configuring the mode if there are still modefuncs left
659
if(func < sizeof(mode_func_arr) / sizeof(mode_func)){
661
// if the current function has not been configured. Store the func's
662
// index in the mode slot's first byte and call func in setup mode
663
if(!((uint8_t)flags & (uint8_t) _BV(PF_SETUP_COMPLETE))){
664
eeprom_write_byte((uint8_t *)EE_MODEDATA_BASE + offset, func);
665
(*mode_func_arr[func])(mode, flags, 1);
666
// mode funcs never return
668
// the modefunc is done configuring itself, give user a chance to
669
// discard the chosen level and start a new cycle
670
flags &= (uint8_t) ~(_BV(PF_SETUP_COMPLETE));
671
eeprom_write_byte((uint8_t *)EE_PROGFLAGS, flags);
674
* at this point we could move on to an other function, but since
675
* there is absolutely no space left for one we just stay with
679
// eeprom_write_byte((uint8_t *)EE_PROGFUNC, func);
682
// user did not discard this function config. Give him 2 seconds
683
// to store the config
684
eeprom_write_byte((uint8_t *)EE_PROGSTAGE, 0);
688
// we ran out of mode funcs, leave programming mode
690
eeprom_write_byte((uint8_t *)EE_PROGSTAGE, 0);
692
// we either ran out of mode funcs or the user didn't lock in the func
693
// after it finished its setup. Give a single flash and restore the old
703
static void inline start_programming()
705
uint8_t mode, stage, func, flags;
707
// reset click counter
708
eeprom_write_byte((uint8_t *)EE_CLICKS, 0);
710
// read programming data from eeprom
711
mode = eeprom_read_byte((uint8_t *)EE_PROGMODE);
712
stage = eeprom_read_byte((uint8_t *)EE_PROGSTAGE);
723
func = eeprom_read_byte((uint8_t *)EE_PROGFUNC);
724
flags = eeprom_read_byte((uint8_t *)EE_PROGFLAGS);
726
progstage2(mode, func, flags);
729
// something went wrong, abort
731
eeprom_write_byte((uint8_t *)EE_PROGSTAGE, 0);
736
#endif // PROGRAMMABLE
381
uint8_t offset, pulse, pulse_off, count, pause, i;
383
// calculate offset into mode data array
386
pulse = eeprom_read_byte((uint8_t *) EE_MODEDATA_BASE + offset + 1);
387
count = eeprom_read_byte((uint8_t *) EE_MODEDATA_BASE + offset + 2);
388
pause = eeprom_read_byte((uint8_t *) EE_MODEDATA_BASE + offset + 3);
390
pulse_off = (uint8_t) pulse << (uint8_t) 2; // pause between pulses,
395
for(i = 0; i < count; ++i){
402
// pause between groups
741
uint8_t nextmode, offset, func_idx;
743
//debounce the switch
749
// get the number of consecutive mode switches from permanent memory,
750
// increment it and write it back
751
clicks = eeprom_read_byte((uint8_t *) EE_CLICKS);
753
eeprom_write_byte((uint8_t *) EE_CLICKS, clicks);
755
// check if we are in programming mode or should enter it
756
progstage = eeprom_read_byte((uint8_t *)EE_PROGSTAGE);
758
if(clicks > NUM_PROG_CLICKS || progstage > 0){
761
#endif // PROGRAMMABLE
763
// get start-up mode from permanent memory and write back next mode
764
mode = eeprom_read_byte(EE_MODE);
767
if(nextmode >= NUM_MODES)
770
eeprom_write_byte(EE_MODE, nextmode);
772
// set whole PORTB initially to output
776
// start watchdog timer with approx. 2 seconds delay.
781
func_idx = eeprom_read_byte((uint8_t *)EE_MODEDATA_BASE + offset);
783
(*mode_func_arr[func_idx])(mode, 0, 0);
785
(*mode_func_arr[func_idx])(mode);
789
* mode funcs do not return, so this is never reached.
790
* Alas, removing the following loop will increase code size by 10 bytes,
791
* even when declaring main void and not calling return...
796
return 0; // Standard Return Code
409
uint8_t offset, mode_idx, func_idx, signal = 0;
411
// set whole PORTB initially to output
413
// PORTB = 0x00; // initialised to 0 anyway
415
// Initialise PWM on output pin and set level to zero
418
// PWM_LVL = 0; // initialised to 0 anyway
420
// read the state data at the start of the eeprom into a struct
421
eeprom_read_block(&state, 0, sizeof(State_t));
423
#ifdef EXTENDED_MODES
424
// if we are in standard mode and got NUM_EXT_CLICKS in a row, change to
426
if(!state.extended && state.clicks >= NUM_EXT_CLICKS){
428
state.ext_mode = EMPTY_MODE;
429
state.prog_stage = prog_undef;
432
// delay signal until state is saved in eeprom
436
// handling of extended mode
439
// in extended mode, we can cycle through modes indefinitely until
440
// one mode is held for more than two seconds
441
if(state.last_click != tap_none){
444
if(state.ext_mode >= NUM_EXT_MODES)
447
mode_idx = state.ext_mode;
449
// leave extended mode if previous mode was on longer than 2 seconds
451
signal = 1; // wait with signal until eeprom is written
454
// remember last mode and init programming
455
state.chosen_mode = state.ext_mode;
456
state.prog_stage = prog_init;
463
* mode programming. We have the mode slot to be programmed saved in
464
* state.target_mode, the mode to store in state.chosen_mode. User needs
465
* to acknowledge by following a tapping pattern of short-short-long-short.
467
if(state.prog_stage >= prog_init){
469
switch(state.prog_stage){
471
state.prog_stage = prog_1;
475
if(state.last_click == tap_short)
478
state.prog_stage = prog_nak;
481
if(state.last_click == tap_long)
484
state.prog_stage = prog_nak;
487
if(state.last_click == tap_short){
488
// sequence completed, update mode_arr and eeprom
489
state.mode_arr[state.target_mode] = state.chosen_mode;
490
eeprom_write_byte((uint8_t *)EE_MODES_BASE + state.target_mode,
496
// clean up when leaving programming mode
497
state.last_click = tap_none;
498
state.prog_stage = prog_undef;
499
state.target_mode = EMPTY_MODE;
500
state.chosen_mode = EMPTY_MODE;
506
#endif // PROGRAMMABLE
507
#endif // EXTENDED_MODES
509
// standard mode operation
511
if(state.last_click != tap_none){
512
// we're coming back from a tap, increment mode
514
#ifdef EXTENDED_MODES
515
// ...and count consecutive clicks
519
// start up from regular previous use (longer than 2 seconds)
520
#ifdef EXTENDED_MODES
522
// remember current mode slot in case it is to be programmed
523
if(state.prog_stage == prog_undef)
524
state.target_mode = state.mode;
526
// reset click counter
536
if(state.mode >= NUM_MODES)
539
// get index of mode stored in the current slot
540
mode_idx = state.mode_arr[state.mode];
543
// initialise click type for next start up
544
state.last_click = tap_short;
546
// write back state to eeprom but omit the mode configuration.
547
// Minimises risk of corruption. Everything else will right itself
548
// eventually, but modes will stay broken until reprogrammed.
549
eeprom_write_block(&state, 0, sizeof(State_t) - sizeof(state.mode_arr));
552
#ifdef EXTENDED_MODES
553
// signal entering or leaving extended mode
558
// sanity check in case of corrupted eeprom
559
if(mode_idx >= NUM_EXT_MODES)
562
// fetch pointer to selected mode func from array
563
offset = mode_idx << 2;
564
func_idx = eeprom_read_byte((uint8_t *) EE_MODEDATA_BASE + offset);
566
// start watchdog timer with approx. 250ms delay.
570
(*mode_func_arr[func_idx])(mode_idx);
573
* mode funcs do not return, so this is never reached.
574
* Alas, removing the following loop will increase code size by 10 bytes,
575
* even when declaring main void and not calling return...
580
return 0; // Standard Return Code