3
* This code runs on a single-channel or dual-channel (or tripple or quad) driver (FET+7135)
4
* with an attiny13/25/45/85 MCU and several options for measuring off time.
6
* Original version Copyright (C) 2015 Selene Scriven,
7
* Modified significantly by Texas Ace (triple mode groups) and
8
* Flintrock (code size, Vcc, OTSM, eswitch, 4-chan, delay-sleep,.. more, see manual)
10
* This program is free software: you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation, either version 3 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23
* TA adds many great custom mode groups and nice build scripts
25
* Implements OTSM "off-time sleep mode" to determine click length based on watchdog timer with mcu powered by CAP.
26
* Adds Vcc inverted voltage read option, with calibration table, allows voltage read of 1S lights without R1/R2 divider hardware.
27
* Implemented 4th PWM channel. (untested, it could even work!)
28
* Now supports E-switches.
29
* Algorithm-generated calibration tables now allow voltage adjustment with one or two configs in fr-calibration.h
30
* Modified tk-attiny.h to simplify layout definitions and make way for more easily-customizable layouts.
31
* Added BODS to voltage shutdown (and E-switch poweroff) to protect low batteries longer (~4uA for supported chips).
32
* Implements space savings (required for other features):
33
* ... See Changes.txt for details.
35
* see fr-tk-attiny.h for mcu layout.
39
* #fuses (for attin25/45/85): high:
40
* DD => BOD disabled early revision chips may not work with BOD and OTSM, but disabling it risks corruption.
41
* DE => BOD set to 1.8V Non V-version chips are still not specced for this and may corrupt. late model V chips with this setting is best.
42
* DF => BOD set to 2.7V Safe on all chips, but may not work well with OTSM, without huge caps.
44
* low C2, 0ms startup time. Probably won't work with BODS capable late model chips, but should improve OTSM a little if not using one anyway.
45
* D2, 4ms Testing finds this seems to work well on attiny25 BODS capable chip, datasheet maybe implies 64 is safer (not clear and hardware dependent).
46
E2 64ms startup. Will probably consume more power during off clicks and might break click timing.
49
* Tested with high:DE low:D2, Ext 0xff on non-V attiny25, but it's probably not spec compliant with that chip.
51
* For more details on these settings
52
* http://www.engbedded.com/cgi-bin/fcx.cgi?P_PREV=ATtiny25&P=ATtiny25&M_LOW_0x3F=0x12&M_HIGH_0x07=0x06&M_HIGH_0x20=0x00&B_SPIEN=P&B_SUT0=P&B_CKSEL3=P&B_CKSEL2=P&B_CKSEL0=P&B_BODLEVEL0=P&V_LOW=E2&V_HIGH=DE&V_EXTENDED=FF
56
* FR's new method Just adjust parameters in fr-calibration.h
57
* Now uses something between fully calculated and fully measured method.
58
* You can make simple adjustments to the calculations to get a good result.
60
* To find out what values to use, flash the driver with battcheck.hex
61
* and hook the light up to each voltage you need a value for. This is
62
* much more reliable than attempting to calculate the values from a
63
* theoretical formula.
65
* Same for off-time capacitor values. Measure, don't guess.
72
* Fixed minor startup lag. (hopefully doesn't mess up voltage or temp ADC stabilization).
73
* Fixed an array overwrite, in some cases messed up first boot initialization.
78
/************ Choose your MCU here, or override in Makefile or build script*********/
79
// The build script will override choices here
81
// choices are now 13, 25, 45, and 85. Yes, 45 and 85 are now different
85
//#define ATTINY 45 // yes these are different now, hopefully only in ways we already know.
86
//#define ATTINY 85 // bust specifically they have a 2 byte stack pointer that OTSM accesses.
90
/**************Select config file here or in build script*****************/
93
///// Use the default CONFIG FILE? /////
94
// This one will be maintained with all the latest configs available even if commented out.
95
// It should be the template for creating new custom configs.
96
#define CONFIG_FILE_H "configs/config_default.h"
98
///Or select alternative configuration file, last one wins.///
99
#define CONFIG_FILE_H "configs/config_testing-HD.h"
100
//#define CONFIG_FILE_H "configs/config_BLFA6_EMU-HD.h"
101
//#define CONFIG_FILE_H "configs/config_biscotti-HD.h"
102
//#define CONFIG_FILE_H "configs/config_trippledown-HD.h"
103
//#define CONFIG_FILE_H "configs/config_classic-HD.h"
104
//#define CONFIG_FILE_H "configs/config_TAv1-OTC-HD.h"
105
//#define CONFIG_FILE_H "configs/config_dual-switch-TA-HD.h"
106
//#define CONFIG_FILE_H "configs/config_4channel-dual-switch-HD.h"
108
//Make it a battcheck build?
109
//#define VOLTAGE_CAL
111
//Note: the modegroups file is specified in the config file, since they must be compatible.
115
/**********************************************************************************
116
**********************END OF CONFIGURATION*****************************************
117
***********************************************************************************/
119
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // this is here for actual_level.
120
#include <avr/pgmspace.h>
121
//#include <avr/io.h>
122
#include <avr/interrupt.h>
123
#include <avr/eeprom.h>
124
#include <avr/sleep.h>
125
#include <avr/power.h>
126
#include <util/delay_basic.h>
127
//#include <string.h>
129
#include CONFIG_FILE_H
131
void blink_value(uint8_t value); // declare early so we can use it anywhere
133
//*************** Defaults, including ones needed before modegroups.h ***********/
134
#ifdef NO_LOOP_TOGGLES
140
#ifndef INLINE_STROBE
141
#define INLINE_STROBE //inline keyword for strobe function.
144
#if defined(USE_ESWITCH) && (OTSM_PIN != ESWITCH_PIN) && defined(USE_ESWITCH_LOCKOUT_TOGGLE)
145
#define USE_LOCKSWITCH
148
#ifndef TURBO_STEPDOWN
149
#define TURBO_STEPDOWN RAMP_SIZE/2
152
#define GROUP_SELECT_MODE 254
154
#define TEMP_CAL_MODE 253
158
#if defined(FULL_BIKING_STROBE) && !defined(BIKING_STROBE)
159
#define BIKING_STROBE
162
#define OWN_DELAY // Don't use stock delay functions.
163
// This is actually not optional anymore. since built in delay requires a compile time constant and strobe()
164
// cannot provide that.
166
#define USE_DELAY_S // Also use _delay_s(), not just _delay_ms()
168
#if !defined(OFFTIM3)
169
#define HIDDENMODES // No hiddenmodes.
172
#include "fr-tk-attiny.h" // should be compatible with old ones, but it might not be, so renamed it.
174
#include MODEGROUPS_H
176
#define LOOP_SLEEP 500 // in ms, how many ms to sleep between voltage/temp/stepdown checks.
179
// Won't compile with -O0 (sometimes useful for debugging) without following:
186
#define Quote(x) Q(x) // for placing expanded defines into inline assembly with quotes around them.
187
// the double expansion is a weird but necessary quirk, found this SO I think.
190
//#define PATH(x,y) Quote(IDENT(x)IDENT(y))
191
//#include PATH(CONFIG_DIR,CONFIG_FILE_H)
195
#if (ATTINY==13) && defined (TEMPERATURE_MON)
196
#undef TEMPERATURE_MON
197
#warning disabling TEMPERATURE_MON for attiny13
200
#if (ATTINY==13) && defined (OTSM_powersave)
201
#undef OTSM_powersave
202
#warning disabling OTSM_powersave for attiny13
208
uint8_t modes[MAX_MODES + sizeof(hiddenmodes)]; // make sure this is long enough
210
// Modes (gets set when the light starts up based on saved config values)
211
#if defined(PWM1_LVL)&&defined(RAMP_PWM1)
212
PROGMEM const uint8_t ramp_pwm1[] = { RAMP_PWM1 };
215
#if defined(PWM2_LVL)&&defined(RAMP_PWM2)
216
PROGMEM const uint8_t ramp_pwm2[] = { RAMP_PWM2 };
219
#if defined(PWM3_LVL)&&defined(RAMP_PWM3)
220
PROGMEM const uint8_t ramp_pwm3[] = { RAMP_PWM3 };
223
#if defined(PWM4_LVL)&&defined(RAMP_PWM4)
224
PROGMEM const uint8_t ramp_pwm4[] = { RAMP_PWM4 };
229
// Calibrate voltage and OTC in this file:
230
#include "fr-calibration.h"
232
#ifdef OTSM_powersave
233
#include "fr-delay.h" // must include them in this order.
234
#define _delay_ms _delay_sleep_ms
235
#define _delay_s _delay_sleep_s
237
#include "tk-delay.h"
242
#include "tk-random.h"
245
#include "tk-voltage.h"
248
///////////////////////REGISTER VARIABLES///////////////////////////////////
249
// make it a register variable. Saves many i/o instructions.
250
// but could change as code evolves. Worth testing what works best again later.
252
// ************NOTE global_counter is now reserved as r2 in tk-delay.h. (well, commented out maybe)**********
254
register uint8_t mode_idx asm("r6"); // current or last-used mode number
255
register uint8_t eepos asm("r7");
258
#if defined(USE_OTSM) || defined(USE_ESWITCH)
259
//Reserving a register for this allows checking it in re-entrant interrupt without needing register maintenance
260
// as a side effect it saves several in/out operations that save more space.
261
register uint8_t wake_count asm ("r8");
263
/////////////////////END REGISTERVARIABLE/////////////////////////////////
266
// counter for entering config mode, remembers click count with tk noinit trick.
267
// If No OTC or OTSM is used it also detects off time by RAM decay
268
// However that's very unreliable with one byte.
269
// FR adds USE_SAFE_PRESSES options that compares 4 bytes to detect RAM decay
270
// if 0 is equal probability to 1 (maybe not quite true) this gives a safety factor of 2^24 so about 16 million.
271
// (needs to be remembered while off, but only for up to half a second)
274
#if !(defined(USE_OTC)||defined(USE_OTSM))&& defined(USE_SAFE_PRESSES)
278
#define N_SAFE_BYTES 4
282
uint8_t fast_presses_array[N_SAFE_BYTES] __attribute__ ((section (".noinit")));
283
#define fast_presses fast_presses_array[0]
284
#else // using fast presses for click timing, use redundancy to check RAM decay:
285
uint8_t fast_presses __attribute__ ((section (".noinit")));
290
// total length of current mode group's array
292
// number of regular non-hidden modes in current mode group
294
// number of hidden modes in the current mode
295
// (hardcoded because both groups have the same hidden modes)
296
//uint8_t hidden_modes = NUM_HIDDEN; // this is never used
299
#define FAST 0x03 // fast PWM
300
#define PHASE 0x01 // phase-correct PWM
302
// FR makes these all aray variables now
303
// can now loop to save, loop to load, and loop to toggle
304
// saves about 30 subtroutine calls, so a bunch of flash space.
306
// define the order of save variables
307
// Yes, they could just be put in the array aliases below
308
// This a messy way to allow not allocating a couple of bytes later.
309
#define muggle_mode_IDX 1 // start at 1 to match EEPSIZE math
310
#define memory_IDX 2 // these all get saved at EEPSIZE-N
311
#define enable_moon_IDX 3
312
#define reverse_modes_IDX 4
313
#define MODEGROUP_IDX 5 //GROUP_SELECT don't need to define mod_override entries here, just leave a space.
314
#define offtim3_IDX 6
315
#define TEMP_CAL_IDX 7 // TEMPERATURE_MON
316
#define firstboot_IDX 8
317
#define lockswitch_IDX 9 // don't forget to update n_saves above.
318
#define TOTAL_TOGGLES 9 // all saves above are toggle variables
320
// assign aliases for array entries for toggle variables.
321
#define OPT_firstboot (EEPSIZE-1-8) // only one that uses individual reads.
322
#define muggle_mode OPT_array[muggle_mode_IDX] // start at 1 to match EEPSIZE math
323
#define memory OPT_array[memory_IDX] // these all get saved at EEPSIZE-N
324
#define enable_moon OPT_array[enable_moon_IDX]
325
#define reverse_modes OPT_array[reverse_modes_IDX]
326
// next memory element will serve as a dummy toggle variable for all mode-override toggles.
327
#define mode_override OPT_array[5] //GROUP_SELECT
328
#define offtim3 OPT_array[offtim3_IDX]
329
//#define TEMPERATURE_MON_IDX OPT_array[7] // TEMPERATURE_MON
330
#define firstboot OPT_array[firstboot_IDX]
331
#define lockswitch OPT_array[lockswitch_IDX] // don't forget to update n_saves above.
333
// this allows to save a few bytes by not initializing unneeded toggles at end of array:
334
// hmm, heck of a bunch of mess just to save 2 to 8 bytes though.
335
#if defined(USE_ESWITCH_LOCKOUT_TOGGLE)
336
#define n_toggles (TOTAL_TOGGLES) // number of options to save/restore
337
#elif defined(USE_FIRSTBOOT)
338
#define n_toggles (TOTAL_TOGGLES - 1) // number of options to save/restore
339
#elif defined(TEMPERATURE_MON)
340
#define n_toggles (TOTAL_TOGGLES - 2) // number of options to save/restore
341
#elif defined(OFFTIM3)
342
#define n_toggles (TOTAL_TOGGLES - 3) // number of options to save/restore
344
#define n_toggles (TOTAL_TOGGLES - 4)
345
#endif // we must have the MODEGROUP menu, so can't go below here.
347
// defined non-toggles saves:
348
#define modegroup OPT_array[n_toggles+1]
349
#define maxtemp OPT_array[n_toggles+2]
350
#define n_extra_saves 2 // non-toggle saves
351
#ifdef USE_TURBO_TIMEOUT
353
// #define disable_next OPT_array[n_toggles+3]
354
#define NEXT_LOCKOUT 1
355
#define n_extra_saves 3
357
#define NEXT_LOCKOUT 0
359
#define DISABLE_NEXT 255
361
#define n_saves (n_toggles + n_extra_saves)
362
uint8_t OPT_array[n_saves+1] ;
364
#define final_toggles (-1) //disable loop toggles.
365
// redefining n_toggles breaks modegroup macro and fixing that situation seems ugly.
367
//#define _configs OPT_array[12]
369
uint8_t overrides[n_toggles+1]; // will hold values override mode_idx if any for each toggle.
372
#define FIRSTBOOT 0b01010101
374
// define a bit field in an I/O register with sbi/cbi support, for efficient boolean manipulation:
378
unsigned char bit0:1;
379
unsigned char bit1:1;
380
unsigned char bit2:1;
381
unsigned char bit3:1;
382
unsigned char bit4:1;
383
unsigned char bit5:1;
384
unsigned char bit6:1;
385
unsigned char bit7:1;
387
/***************LETS RESERVE GPIOR0 FOR LOCAL VARIABLE USE ********************/
388
// This seemed more useful at one point than it maybe actually is, but it works.
389
//define a global bitfield in lower 32 IO space with in/out sbi/cbi access
390
// unfortunately, attiny13 has no GPIORs,.
392
#define gbit *((volatile uint8_t*)_SFR_MEM_ADDR(GPIOR2)) // pointer to whole status byte.
393
#define gbit_pwm4zero ((volatile io_reg*)_SFR_MEM_ADDR(GPIOR2))->bit0 // pwm4 disable toggle.
394
#define gbit_epress ((volatile io_reg*)_SFR_MEM_ADDR(GPIOR2))->bit1 // eswitch was pressed.
396
#define gbit_addr "0x13" // hack, but whatever, 0x13 is GPIOR2 but GPIOR2 macro is just too clever to work.
397
//There's surely a better way, but not worth finding out.
398
#define gbit_pwm4zero_bit "0" // This gets used for inline asm in PWM ISR.
402
#if defined(USE_OTSM) || defined(USE_ESWITCH)
403
// convert wake time thresholds to counts, math done by compiler, not runtime:
404
// plus 1 because there's always an extra un-timed pin-change wake:
405
#define wake_count_short (uint8_t)(1+((double)wake_time_short)*((uint16_t)1<<(6-SLEEP_TIME_EXPONENT)))
406
#define wake_count_med (uint8_t)(1+((double)wake_time_med)*((uint16_t)1<<(6-SLEEP_TIME_EXPONENT)))
410
/**************WARN ON SOME BROKEN COMBINATIONS******************/
412
#error You must define ATTINY inbistro.c or in the build script/Makefile.
415
#ifndef CONFIG_FILE_H
416
#error You must define CONFIG_FILE_H inbistro.c or in the build script/Makefile.
420
#error You must define MODEGROUPS_H in the configuration file.
425
#error You must define an ESWITCH_PIN in fr-tk-attiny.h or undefine USE_ESWITCH
431
#error You must define a CAP_PIN in fr-tk-attiny.h or undefine USE_OTC
437
#error You must define an OTSM_PIN in fr-tk-attiny.h or undefine USE_OTSM
441
#if ATTINY==13 && defined(READ_VOLTAGE_FROM_VCC)
442
#error You cannot use READ_VOLTAGE_FROM_VCC with the attiny 13.
445
#if ATTINY==13 && (defined(PWM3_LVL)||defined (PWM4_LVL))
446
#error attiny13 does not support PWM3 or PWM4, modify layout or select a new one.
450
#if defined(VOLTAGE_MON)&&!(defined(READ_VOLTAGE_FROM_VCC)||defined(READ_VOLTAGE_FROM_DIVIDER))
451
#error You must define READ_VOLTAGE_FROM_VCC or READ_VOLTAGE_FROM_DIVEDER when VOLTAGE_MON is defined
454
#if defined(VOLTAGE_MON)&&defined(READ_VOLTAGE_FROM_VCC)&&defined(READ_VOLTAGE_FROM_DIVIDER)
455
#error You cannot define READ_VOLTAGE_FROM_VCC at the same time as READ_VOLTAGE_FROM_DIVIDER
458
#if defined(READ_VOLTAGE_FROM_DIVIDER)&&!defined(REFERENCE_DIVIDER_READS_TO_VCC)&&defined(USE_OTSM)&&(OTSM_PIN==VOLTAGE_PIN)&&defined(VOLTAGE_MON)
459
#error You cannot use 1.1V reference to read voltage on the same pin as the OTSM. OTSM power-on voltage must be >1.8V.
460
#error Use REFERENCE_DIVIDER_READS_TO_VCC instead and set divider resistors to provide > 1.8V on-voltage to voltage pin.
461
#error For 1S non-LDO or 1-S 5.0V LDO lights you can use READ_VOLTAGE_FROM_VCC instead
464
#if defined(READ_VOLTAGE_FROM_DIVIDER)&&!defined(REFERENCE_DIVIDER_READS_TO_VCC)&&defined(USE_ESWITCH)&&(ESWITCH_PIN==VOLTAGE_PIN)&&defined(VOLTAGE_MON)
465
#error You cannot use 1.1V reference to read voltage on the same pin as the e-switch. E-switch on-voltage must be >1.8V.
466
#error Use REFERENCE_DIVIDER_READS_TO_VCC instead and set divider resistors to provide > 1.8V on-voltage to voltage pin.
467
#error For 1S non-LDO or 1-S 5.0V-LDO lights you can use READ_VOLTAGE_FROM_VCC instead.
470
#if !defined(USE_OTC)&&!defined(USE_OTSM)&&!defined(USE_ESWITCH)&&defined(OFFTIM3)
471
#error You must define either USE_OTC or USE_OTSM or USE_ESWITCH when OFFTIM3 is defined.
474
/* If the eswitch is used it's impossible to know if there's also a clicky switch
475
So this warning doesn't catch everything */
476
#if !defined(USE_OTC)&&!defined(USE_OTSM)&&!defined(USE_SAFE_PRESSES)&&!defined(USE_ESWITCH)
477
#warning It is highly recommend to define USE_SAFE_PRESSES for capacitor-less off-time detection
482
//#define DETECT_ONE_S // auto-detect 1s vs multi-s light make prev.
483
// requiers 5V LDO for multi-s light and will use VCC for 1S.
484
// incomplete, needs calibration table switching, costs memory, probably 160 bytes when done.
487
/****************************END OF PREPROCESSOR DEFINES**************************/
490
inline void check_stars() { // including from BLFA6
491
// Configure options based on stars
492
// 0 being low for soldered, 1 for pulled-up for not soldered
493
#if 0 // not implemented, STAR2_PIN is used for second PWM channel
496
if ((PINB & (1 << STAR2_PIN)) == 0) {
497
modes[mode_cnt++] = MODE_MOON;
500
#if 0 // Mode order not as important as mem/no-mem
502
if ((PINB & (1 << STAR3_PIN)) == 0) {
510
if ((PINB & (1 << STAR3_PIN)) == 0) {
511
memory = 1; // solder to enable memory
513
memory = 0; // unsolder to disable memory
519
// FR 2017 adds redundancy to check RAM decay without flakiness.
520
// Expand fast_presses to mulitple copies. Set and increment all.
521
// Check that all are equal to see if RAM has is still intact (short click) and value still valid.
522
void clear_presses() {
523
for (uint8_t i=0;i<N_SAFE_BYTES;++i){
524
fast_presses_array[i]=0;
527
inline uint8_t check_presses(){
528
uint8_t i=N_SAFE_BYTES-1;
529
while (i&&(fast_presses_array[i]==fast_presses_array[i-1])){
532
return !i; // if we got to 0, they're all equal
534
inline void inc_presses(){
535
for (uint8_t i=0;i<N_SAFE_BYTES;++i){
536
++fast_presses_array[i];
539
inline void set_presses(uint8_t val){
540
for (uint8_t i=0;i<N_SAFE_BYTES;++i){
541
fast_presses_array[i]=val;
545
#define check_presses() (fast_presses < 0x20)
546
#define clear_presses() fast_presses=0
547
#define inc_presses() fast_presses=(fast_presses+1)& 0x1f
548
#define set_presses(val) fast_presses=(val)
552
inline void initial_values() {//FR 2017
553
//for (uint8_t i=1;i<n_toggles+1;i++){ // disable all toggles, enable one by one.
556
// configure initial values here, 255 disables the toggle... doesn't save space.
558
firstboot = FIRSTBOOT; // detect initial boot or factory reset
559
#elif firstboot_IDX <= final_toggles
560
// #elif defined(LOOP_TOGGLES)
561
firstboot=255; // disables menu toggle
565
enable_moon = INIT_ENABLE_MOON; // Should we add moon to the set of modes?
566
#elif enable_moon_IDX <= final_toggles
567
// #elif defined(LOOP_TOGGLES)
568
enable_moon=255; //disable menu toggle,
571
#if defined(USE_REVERSE_MODES) && defined(OFFTIM3)
572
reverse_modes = INIT_REVERSE_MODES; // flip the mode order?
573
#elif reverse_modes_IDX <= final_toggles
574
// #elif defined(LOOP_TOGGLES)
575
reverse_modes=255; //disable menu toggle,
577
memory = INIT_MEMORY; // mode memory, or not
580
offtim3 = INIT_OFFTIM3; // enable medium-press?
581
#elif offtim3_IDX <= final_toggles
582
// #elif defined(LOOP_TOGGLES)
583
offtim3=255; //disable menu toggle,
586
#ifdef USE_MUGGLE_MODE
587
muggle_mode = INIT_MUGGLE_MODE; // simple mode designed for muggles
588
#elif muggle_mode_IDX <= final_toggles
589
// #elif defined(LOOP_TOGGLES)
590
muggle_mode=255; //disable menu toggle,
593
#ifdef USE_LOCKSWITCH
594
lockswitch=INIT_LOCKSWITCH; // E-swtich enabled.
595
#elif lockswitch_IDX <= final_toggles
596
// #elif defined(LOOP_TOGGLES)
601
overrides[5]=GROUP_SELECT_MODE;
602
#if defined(TEMPERATURE_MON)&&defined(TEMP_CAL_MODE)
603
overrides[7]=TEMP_CAL_MODE, //7
604
#elif TEMP_CAL_IDX <= final_toggles
610
// Handle non-toggle saves.
611
modegroup = INIT_MODEGROUP; // which mode group will be default, mode groups below start at zero, select the mode group you want and subtract one from the number to get it by defualt here
612
#ifdef TEMPERATURE_MON
613
maxtemp = INIT_MAXTEMP; // temperature step-down threshold, each number is roughly equal to 4c degrees
615
mode_idx=0; // initial mode
623
void save_mode() { // save the current mode index (with wear leveling)
624
uint8_t oldpos=eepos;
626
eepos = (eepos+1) & ((EEPSIZE/2)-1); // wear leveling, use next cell
628
eeprom_write_byte((uint8_t *)((uint16_t)eepos),mode_idx); // save current state
629
eeprom_write_byte((uint8_t *)((uint16_t)oldpos), 0xff); // erase old state
637
void getsetstate(uint8_t rw){// double up the function to save space.
641
if (rw==gssWRITE){// conditional inside loop for space.
642
eeprom_write_byte((uint8_t *)(EEPSIZE-i-1),OPT_array[i]);
644
OPT_array[i]=eeprom_read_byte((uint8_t *)(EEPSIZE-i-1));
647
} while(i); // don't include 0
651
void save_state() { // central method for writing complete state
653
getsetstate(gssWRITE);
657
//#ifndef USE_FIRSTBOOT // obsolete
658
//inline void reset_state() {
665
inline void restore_state() {
669
//check if this is the first time we have powered on
670
eep = eeprom_read_byte((uint8_t *)OPT_firstboot);
671
if (eep != FIRSTBOOT) {// confusing: if eep = FIRSTBOOT actually means the first boot already happened
672
// so eep != FIRSTBOOT means this IS the first boot.
673
// not much to do; the defaults should already be set
674
// while defining the variables above
675
save_state(); // this will save FIRSTBOOT to the OPT_firstboot byte.
680
do { // Read until we get a result. Tightened this up slightly -FR
681
mode_idx = eeprom_read_byte((const uint8_t *)((uint16_t)eepos));
682
} while((mode_idx == 0xff) && eepos++<(EEPSIZE/2) ) ; // the && left to right eval prevents the last ++.
683
#ifndef USE_FIRSTBOOT
685
// if no mode_idx was found, assume this is the first boot
686
if (mode_idx==0xff) {
687
save_state(); //redundant with check below -FR
691
// load other config values
692
getsetstate(gssREAD);
694
#ifndef USE_FIRSTBOOT
695
// if (modegroup >= NUM_MODEGROUPS) reset_state(); // redundant with check above
696
// With this commented out, disabling firstboot just eeks out 12 bytes of saving,
697
// largely because reset_state can now become = save_state above.
698
// before doing getsetstate, the initial values are still good for the save.
699
// this is a nice safety check, but that's not what it's here for.
704
inline void next_mode() {
706
if (mode_idx >= solid_modes) {
707
// Wrap around, skipping the hidden modes
708
// (note: this also applies when going "forward" from any hidden mode)
709
// FIXME? Allow this to cycle through hidden modes?
715
inline void prev_mode() {
716
// simple mode has no reverse
717
#ifdef USE_MUGGLE_MODE
718
if (muggle_mode) { return next_mode(); }
720
if (mode_idx == solid_modes) {
721
// If we hit the end of the hidden modes, go back to first mode
723
} else if (mode_idx > 0) {
724
// Regular mode: is between 1 and TOTAL_MODES
727
// Otherwise, wrap around (this allows entering hidden modes)
728
mode_idx = mode_cnt - 1;
733
inline void copy_hidden_modes(uint8_t mode_cnt){
734
// Helper for count_modes. At one point seemed potentially
735
// useful to break it out for preprocessor choices. -FR
736
// copy starting from end, so takes mode_cnt as input.
737
for(uint8_t j=mode_cnt, i=sizeof(hiddenmodes);i>0; )
739
// predecrement to get the minus 1 for free and avoid the temp,
740
// probably optimizer knows all this anyway.
741
modes[--j] = pgm_read_byte((uint8_t *)(hiddenmodes+(--i)));
745
inline void count_modes() {
747
* Determine how many solid and hidden modes we have.
749
* (this matters because we have more than one set of modes to choose
750
* from, so we need to count at runtime)
753
* FR: What this routine really does is combine the moon mode, the defined group modes,
754
* and the hidden modes into one array according to configuration options
755
* such as mode reversal, enable mood mode etc.
756
* The list should like this:
757
* modes ={ moon, solid1, solid2,...,last_solid,hidden1,hidden2,...,last_hidden}
758
* unless reverse_modes is enabled then it looks like this:
759
* modes={last_solid,last_solid-1,..solid1,moon,hidden1,hidden2,...last_hidden}
760
* or if moon is disabled it is just left out of either ordering.
761
* If reverse clicks are disabled the hidden modes are left out.
762
* mode_cnt will hold the final count of modes -FR.
764
* Now updated to construct the modes in one pass, even for reverse modes.
765
* Reverse modes are constructed backward and pointer gets moved to begining when done.
768
// copy config to local vars to avoid accidentally overwriting them in muggle mode
769
// (also, it seems to reduce overall program size)
770
uint8_t my_modegroup = modegroup;
772
uint8_t my_enable_moon = enable_moon;
774
#define my_enable_moon 0
776
#if defined(USE_REVERSE_MODES) && defined(OFFTIM3)
777
uint8_t my_reverse_modes = reverse_modes;
779
#define my_reverse_modes 0
782
// override config if we're in simple mode
783
#ifdef USE_MUGGLE_MODE
785
my_modegroup = NUM_MODEGROUPS;
789
#if defined(USE_REVERSE_MODES)&&defined(OFFTIM3)
790
my_reverse_modes = 0;
795
//my_reverse_modes=0; // FOR TESTING
798
// const uint8_t *src = modegroups + (my_modegroup<<3);
800
uint8_t *src=(void *)modegroups;
801
// FR adds 0-terminated variable length mode groups, saves a bunch in big builds.
802
// some inspiration from gchart here too in tightening this up even more.
803
// scan for enough 0's, leave the pointer on the first mode of the group.
808
// now find start and end in one pass
811
start=src; // set start to beginning of mode group
812
#if defined(USE_REVERSE_MODES)&&defined(OFFTIM3) //Must find end before we can reverse the copy
813
// so copy will happen in second pass below.
814
while(pgm_read_byte(src++)){
815
#else // if no reverse, can do the copy here too.
816
while((modes[solid_modes+my_enable_moon]=pgm_read_byte(src++))){
818
solid_modes=(uint8_t)(src-start);
819
} // every 0 starts a new modegroup, decrement i
824
// Now handle reverse order in same step. -FR
825
#if defined(USE_REVERSE_MODES)&&defined(OFFTIM3)
827
j=solid_modes; // this seems a little redundant now.
829
//note my_enable_moon and my_reverse_modes are either 1 or 0, unlike solid_modes.
830
modes[(my_reverse_modes?solid_modes-j:j-1+my_enable_moon)] = pgm_read_byte(start+(j-1));
836
solid_modes+=my_enable_moon;
837
if (my_enable_moon) {// moon placement already handled, but have to fill in the value.
838
modes[(my_reverse_modes?solid_modes-1:0)] = 1;
845
mode_cnt = solid_modes+sizeof(hiddenmodes);
846
copy_hidden_modes(mode_cnt); // copy hidden modes starts at the end.
848
mode_cnt-=!(modes[0]^modes[mode_cnt-1]);// cheapest syntax I could find, but the check still costs 20 bytes. -FR
851
mode_cnt = solid_modes;
855
// This is getting too silly
856
// and tk already removed all usages of it anyway, except from set_level, so just do it there.
858
//inline void set_output(uint8_t pwm1, uint8_t pwm2, uint8_t pwm3, uint8_t pwm4) {
859
//#elif defined(PWM3_LVL)
860
//inline void set_output(uint8_t pwm1, uint8_t pwm2, uint8_t pwm3) {
861
//#elif defined(PWM2_LVL)
862
//inline void set_output(uint8_t pwm1, uint8_t pwm2) {
864
//inline void set_output(uint8_t pwm1,) {
867
//inline void set_output() {
868
///* This is no longer needed since we always use PHASE mode.
869
//// Need PHASE to properly turn off the light
870
//if ((pwm1==0) && (pwm2==0)) {
874
//FET_PWM1_LVL = pwm1;
876
//#ifdef ALT_PWM1_LVL
877
//ALT_PWM1_LVL = pwm3;
882
void set_level(uint8_t level) {
885
gbit_pwm4zero=1; // we can't disable the interrupt because we use it for other timing
886
// so have to signal the interrupt instead.
889
#if defined(USE_PWM3)
892
#if defined(USE_PWM2)
901
PWM4_LVL=pgm_read_byte(ramp_pwm4 + level);
905
PWM3_LVL=pgm_read_byte(ramp_pwm3 + level);
908
PWM2_LVL=pgm_read_byte(ramp_pwm2 + level);
911
PWM1_LVL=pgm_read_byte(ramp_pwm1 + level);
917
void set_mode(uint8_t mode) {
919
static uint8_t actual_level = 0;
920
uint8_t target_level = mode;
924
diff = target_level - actual_level;
925
shift_amount = (diff >> 2) | (diff!=0);
926
actual_level += shift_amount;
927
set_level(actual_level);
928
_delay_ms(RAMP_SIZE/20); // slow ramp
929
//_delay_ms(RAMP_SIZE/4); // fast ramp
930
} while (target_level != actual_level);
932
#define set_mode set_level
937
void blink(uint8_t val, uint16_t speed)
941
set_level(BLINK_BRIGHTNESS);
949
// utility routine to blink out 8bit value as a 3 digit decimal.
950
// The compiler will omit it if it's not used. Good for debugging. -FR.
951
// uses much memory though.
952
inline void blink_value(uint8_t value){
955
blink((value/100)%10,200); // blink hundreds
957
blink((value/10)%10,200); // blink tens
959
blink(value % 10,200); // blink ones
966
INLINE_STROBE void strobe(uint8_t ontime, uint8_t offtime) {
967
// TK added this loop. The point seems to be to slow down one strobe cycle
968
// so fast_presses timeout is not reached too quickly.
969
// FR has a partial implementation of a global clock in tk-delay
970
// that would solve this more generally, but for now this is slightly smaller and does the job.
973
set_level(RAMP_SIZE);
981
inline void SOS_mode() {
982
#define SOS_SPEED 200
984
_delay_ms(SOS_SPEED*5/2);
985
blink(3, SOS_SPEED*5/2);
986
//_delay_ms(SOS_SPEED);
988
_delay_s(); _delay_s();
993
inline void toggles() {
994
// New FR version loops over all toggles, avoids variable passing, saves ~50 bytes.
995
// mode_overrides ( toggles that cause startup in a special mode or menu)
996
// are handled by an array entry for each toggle that provides the mod_idx to set.
997
// For normal config toggles, the array value is 0, so the light starts in
998
// the first normal mode.
999
// For override toggles the array value is an identifier for the special mode
1000
// All special modes have idx values above MINUMUM_OVERRIDE_MODE.
1001
// On startup mode_idx is checked to be in the override range or not.
1003
// Used for config mode
1004
// Changes the value of a config option, waits for the user to "save"
1005
// by turning the light off, then changes the value back in case they
1006
// didn't save. Can be used repeatedly on different options, allowing
1007
// the user to change and save only one at a time.
1011
if(OPT_array[i]!=255){
1012
blink(i, BLINK_SPEED/8); // indicate which option number this is
1013
mode_idx=overrides[i];
1016
// "buzz" for a while to indicate the active toggle window
1021
#ifdef USE_MUGGLE_MODE
1022
if (muggle_mode) {break;} // go through once on muggle mode
1023
// this check adds 10 bytes. Is it really needed?
1026
}while((i<n_toggles));
1029
#else // use the old way, can come close in space for simple menus:
1031
void toggle(uint8_t *var, uint8_t num) {
1032
// Used for config mode
1033
// Changes the value of a config option, waits for the user to "save"
1034
// by turning the light off, then changes the value back in case they
1035
// didn't save. Can be used repeatedly on different options, allowing
1036
// the user to change and save only one at a time.
1037
blink(num, BLINK_SPEED/8); // indicate which option number this is
1040
// "buzz" for a while to indicate the active toggle window
1043
for(uint8_t i=0; i<32; i++) {
1044
set_level(BLINK_BRIGHTNESS * 3 / 4);
1050
// if the user didn't click, reset the value and return
1057
inline void toggles(){
1058
// The old way to do the toggles, in case we need it back.
1059
// Enter or leave "muggle mode"?
1060
#ifdef USE_MUGGLE_MODE
1061
toggle(&muggle_mode, 1);
1062
if (muggle_mode) return; // don't offer other options in muggle mode
1066
toggle(&enable_moon, 3);
1068
#if defined(USE_REVERSE_MODES) && defined(OFFTIM3)
1069
toggle(&reverse_modes, 4);
1071
// Enter the mode group selection mode?
1072
mode_idx = GROUP_SELECT_MODE;
1073
toggle(&mode_override, 5);
1077
toggle(&offtim3, 6);
1080
#ifdef TEMPERATURE_MON
1081
// Enter temperature calibration mode?
1082
mode_idx = TEMP_CAL_MODE;
1083
toggle(&mode_override, 7);
1087
#ifdef USE_FIRSTBOOT
1088
toggle(&firstboot, 8);
1091
#ifdef USE_LOCKSWITCH
1092
toggle(&lockswitch, 9);
1099
#ifdef TEMPERATURE_MON
1100
uint8_t get_temperature() {
1101
// average a few values; temperature is noisy
1104
ADC_on_temperature(); // do it before calling, inconsistent with get_voltage and
1106
for(i=0; i<16; i++) {
1108
temp += get_voltage();
1113
#endif // TEMPERATURE_MON
1115
#if defined(OFFTIM3)&&defined(USE_OTC)
1116
inline uint8_t read_otc() {
1117
// Read and return the off-time cap value
1118
// Start up ADC for capacitor pin
1119
// disable digital input on ADC pin to reduce power consumption
1120
//DIDR0 |= (1 << CAP_DIDR); // will just do it for all pins on init.
1121
// 1.1v reference, left-adjust, ADC3/PB3
1122
ADMUX = (1 << V_REF) | (1 << ADLAR) | CAP_PIN;
1123
// enable, start, prescale
1124
ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;
1125
// Wait for completion
1126
while (ADCSRA & (1 << ADSC));
1127
// Start again as datasheet says first result is unreliable
1128
ADCSRA |= (1 << ADSC);
1129
// Wait for completion
1130
while (ADCSRA & (1 << ADSC));
1132
// ADCH should have the value we wanted
1137
inline void init_mcu(){ // complete revamp by FR to allow use of any combination of 4 outputs, OTSM, and more
1138
// 2017 by Flintrock (C)
1140
// setup all our initial mcu configuration, mostly including interrupts.
1141
//DDRB, 1 bit per pin, 1=output default =0.
1142
//PORTB 1 is ouput-high or input-pullup. 0 is output-low or input floating/tri-stated. Default=0.
1143
//DIDR0 Digital input disable, 1 disable, 0 enable. disable for analog pins to save power. Default 0 (enabled)
1145
// start by disabling all digital input.
1146
// PWM pins will get set as output anyway.
1147
DIDR0=0b00111111 ; // tests say makes no difference during sleep,
1148
// but datasheet claims it helps drain in middle voltages, so during power-off detection maybe.
1150
// Charge up the capacitor by setting CAP_PIN to output
1152
// if using OTSM but no OTC cap, probably better to stay input high on the unused pin.
1153
// If USE_ESWITCH and eswitch pin is defined same as cap pin, the eswitch define overrides,
1154
// so again, leave it as input (but not high).
1155
#if ( (defined(USE_OTSM) && !defined(OTSM_USES_OTC) ) || (defined(USE_ESWITCH) && ESWITCH_PIN == CAP_PIN ) )
1156
// just leave cap_pin as an input pin (raised high by default lower down)
1158
// Charge up the capacitor by setting CAP_PIN to output
1159
DDRB |= (1 << CAP_PIN); // Output
1160
PORTB |= (1 << CAP_PIN); // High
1164
// Set PWM pins to output
1165
// Regardless if in use or not, we can't set them input high (might have a chip even if unused in config)
1166
// so better set them as output low.
1168
DDRB |= (1 << PWM_PIN) ;
1171
DDRB |= (1 << PWM2_PIN);
1174
DDRB |= (1 << PWM3_PIN);
1177
DDRB |= (1 << PWM4_PIN);
1181
// Set Timer 0 to do PWM1 and PWM2 or for OTSM powersave timing
1182
#if defined(USE_PWM1) || defined (USE_PWM2) || defined OTSM_powersave // should alias the last one to something better
1184
TCCR0A = PHASE; // phase means counter counts up and down and
1185
// compare register triggers on and off symmetrically at same value.
1186
// This doubles the time so half the max frequency.
1187
// Set prescaler timing
1188
// This and the phase above now directly impact the delay function in tk-delay.h..
1189
// make changes there to compensate if this is changed
1190
TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) 1 => 16khz in phase mode or 32 in fast mode.
1193
TCCR0A |= (1<<COM0B1); // enable PWM on PB1
1196
TCCR0A |= (1<<COM0A1); // enable PWM on PB0
1200
//Set Timer1 to do PWM3 and PWM4
1201
#if defined(USE_PWM3) || defined (USE_PWM4)
1203
// FR: this timer does not appear to have any phase mode.
1204
// The frequency appears to be just system clock/255
1207
TCCR1 = _BV (CS10); // prescale of 1 (32 khz PWM)
1208
GTCCR = (1<<COM1B1) | (1<<PWM1B) ; // enable pwm on OCR1B but not OCR1B compliment (PB4 only).
1209
// FR: this timer does not appear to have any phase mode.
1210
// The frequency appears to be just system clock/255
1213
TCCR1 = _BV (CS11); // override, use prescale of 2 (16khz PWM) for PWM4 because it will have high demand from interrupts.
1214
// This will still be just as fast as timer 0 in phase mode.
1215
TCCR1 |= _BV (PWM1A) ; // for PB3 enable pwm for OCR1A but leave it disconnected.
1216
// Its pin is already in use.
1217
// Must handle it with an interrupt.
1218
TIMSK |= (1<<OCIE1A) | (1<<TOIE1); // enable interrupt for compare match and overflow on channel 4 to control PB3 output
1219
// Note: this will then override timer0 as the delay clock interrupt for tk-delay.h.
1224
PORTB|=~DDRB&~(1<<VOLTAGE_PIN); // Anything that is not an output
1225
// or the voltage sense pin, gets a pullup resistor
1226
// again, no change measured during sleep, but maybe helps with shutdown?
1227
// exceptions handled below.
1229
// leave pullup set on E-switch pin
1230
PCMSK |= 1<< ESWITCH_PIN; // catch pin change on eswitch pin
1232
#if defined(USE_OTSM)
1233
// no pull-up on OTSM-PIN.
1234
PORTB=PORTB&~(1<<OTSM_PIN);
1235
PCMSK |= 1<< OTSM_PIN; // catch pin change on OTSM PIn
1237
#if defined(USE_ESWITCH) || defined(USE_OTSM)
1238
GIMSK |= 1<<PCIE; // enable PIN change interrupt
1240
GIFR |= PCIF; // Clear pin change interrupt flag
1242
#if defined(USE_ESWITCH) || defined(USE_OTSM) || defined(OTSM_powersave)
1243
sleep_enable(); // just leave it enabled. It's fine and will help elsewhere.
1244
sei(); //Enable Global Interrupt
1247
//timer overflow interrupt is presently setup in tk-delay.h for OTS_powersave
1251
#if defined(USE_OTSM) || defined(USE_ESWITCH) || !defined(USE_OTC)
1252
// decide which mode to switch to based on user input
1253
inline void change_mode() { // just use global variable
1255
inline void change_mode(uint8_t cap_val) {
1258
// if (! mode_override) {
1259
if (mode_idx<MINIMUM_OVERRIDE_MODE) {
1260
#if defined(USE_OTSM) || defined(USE_ESWITCH)
1261
if (wake_count < wake_count_short ) {
1262
#elif defined(USE_OTC)
1263
if (cap_val > CAP_SHORT) {
1265
// if (fast_presses < 0x20) { // fallback, but this trick needs improvements.
1266
if ( check_presses() ) {// Indicates they did a short press, go to the next mode
1268
// after turbo timeout, forward click "stays" in turbo (never truly left).
1269
// conditional gets optimized out if NEXT_LOCKOUT is 0
1270
if ( (NEXT_LOCKOUT) && fast_presses == DISABLE_NEXT ){
1271
clear_presses(); // one time only.
1273
next_mode(); // Will handle wrap arounds
1275
//// We don't care what the fast_presses value is as long as it's over 15
1276
// fast_presses = (fast_presses+1) & 0x1f;
1279
#if defined(USE_OTSM) || defined(USE_ESWITCH)
1280
} else if (wake_count < wake_count_med ) {
1282
} else if (cap_val > CAP_MED) {
1285
// User did a medium press, go back one mode
1286
// fast_presses = 0;
1289
prev_mode(); // Will handle "negative" modes and wrap-arounds
1291
next_mode(); // disabled-med-press acts like short-press
1292
// (except that fast_presses isn't reliable then)
1296
// Long press, keep the same mode
1297
// ... or reset to the first mode
1298
// fast_presses = 0;
1300
#ifdef USE_MUGGLE_MODE
1301
if (muggle_mode || (! memory)) {
1305
// Reset to the first mode
1313
inline void voltage_cal(){
1317
blink_value(get_voltage());
1323
/*********************ISRs***************************************************/
1324
/******One more is in FR-delay.h*******************************************/
1327
// 2017 by Flintrock.
1328
// turn on PWM4_PIN at bottom of clock ramp
1329
// this will also replace the delay-clock interrupt used in fr-delay.h
1330
// Since SBI,CBI, and SBIC touch no registers, so no register protection is needed:
1331
// PWM this way without a phase-mode counter would not shut off the light completely
1332
// Added a control flag for 0 level to disable the light. We need the interrupts running for the delay clock.
1334
ISR(TIMER1_OVF_vect,ISR_NAKED){ // hits when counter 1 reaches max
1335
__asm__ __volatile__ ( //0x18 is PORTB
1336
"cbi 0x18 , " Quote(PWM4_PIN) " \n\t"
1341
// turn off PWM4_PIN at COMPA register match
1342
// this one is only defined here though:
1343
ISR(TIMER1_COMPA_vect, ISR_NAKED){ //hits when counter 1 reaches compare value
1344
__asm__ __volatile__ ( //0x18 is PORTB
1345
"sbic " gbit_addr " , " gbit_pwm4zero_bit " \n\t" // if pwm4zero isn't set...
1347
"sbi 0x18 , " Quote(PWM4_PIN) " \n\t" //set bit in PORTB (0x18) to make PW4_PIN high.
1353
#if defined(USE_OTSM) || defined(USE_ESWITCH)
1354
// Off-time sleep mode by -FR, thanks to flashy Mike and Mike C for early feasibility test with similar methods.
1356
//need to declare main here to jump to it from ISR.
1359
// OS_task is a bit safer than naked,still allocates locals on stack if needed, although presently avoided.
1360
void __attribute__((OS_task, used, externally_visible)) PCINT0_vect (void) {
1361
//ISR(PCINT0_vect, ISR_NAKED){// Dual watchdog pin change power-on wake by FR
1363
// 2017 by Flintrock (C)
1365
//PIN change interrupt. This serves as the power down and power up interrupt, and starts the watchdog.
1367
/* IS_NAKED (or OS_task) IS ***DANGEROUS** remove it if you edit this function significantly
1368
* and aren't sure. You can remove it, and change the asm reti call below to a return.
1369
* and remove the CLR R1. However, it saves about 40 bytes, which matters.
1370
* The idea here, the compiler normally stores all registers used by the interrupt and
1371
* restores them at the end of the interrupt. This costs instructions (space).
1372
* We won't return to the caller anyway, we're going to reset (so this is similar to a
1373
* tail call optimization).
1374
* One tricky bit then is that we get a re-entrant call here because
1375
* sleep and wake use the same interrupt, so we'll interrupt the sleep command below with a re-entry
1376
* into this function on wake. The re-entry will pass the "if wake_count" conditional and immediately
1377
* return to the original instance.
1378
* We avoid touching much there by using a global register variable for wake_count.
1379
* SREG is probably changed but since it only breaks out of the sleep there are
1380
* no pending checks of result flags occurring.
1382
* Another issue is allocation of locals. Naked has no stack frame,
1383
* but seems to properly force variables to register (better anyway) until it can't,
1384
* and then fails to compile (gcc 4.9.2) OS_task however will create a stack frame if needed and is
1385
* more documented/gauranteed/future-proof probably.
1390
//#if defined(USE_OTSM)
1391
//DIDR0&=~(1<<OTSM_PIN);
1393
//#if defined(USE_ESWITCH)
1394
//DIDR0&=~(1<<ESWITCH_PIN);
1397
__asm__ __volatile__ ("CLR R1"); // We do need a clean zero-register (yes, that's R1).
1398
#ifdef USE_ESWITCH // for eswtich we'll modify the sleep loop after a few seconds.
1399
register uint8_t sleep_time_exponent=SLEEP_TIME_EXPONENT;
1401
#define sleep_time_exponent SLEEP_TIME_EXPONENT
1403
if( wake_count ){// if we've already slept, so we're waking up.
1404
// This is a register variable; no need to clean space for it.
1405
// return; // we are waking up, do nothing and continue from where we slept (below).
1406
__asm__ __volatile__ ("reti");
1407
} // otherwise, we're going to sleep
1408
// we only pass this section once, can do initialization here:
1409
// e_status=0b00000001; //startoff in standby with pin low (button pressed)
1411
ADCSRA = 0; //disable the ADC. We're not coming back, no need to save it.
1412
set_level(0); // Set all the outputs low.
1413
// Just the output-low of above, by itself, doesn't play well with 7135s. Input high doesn't either
1414
// Even though in high is high impedance, I guess it's still too much current.
1415
// What does work.. is input low:
1417
DDRB &= ~(1 << PWM_PIN) ;
1420
DDRB &= ~(1 << PWM2_PIN) ;
1423
DDRB &= ~(1 << PWM3_PIN) ;
1426
DDRB &= ~(1 << PWM4_PIN) ;
1430
register uint8_t e_standdown=1; // pressing off, where we start
1431
register uint8_t e_standby=0; // pressing on
1432
register uint8_t pins_state=0; // state of all switch pins.
1433
// register uint8_t old_pins_state=0; // detect a change (a sane one at least).
1436
while(1) { // keep going to sleep until power is on
1440
* 1:standown: Still armed for short click restart on button release, counting time.
1441
* 2:full off (neither standby nor standown). Long press time-out ocurerd,
1442
* -button release does nothing on eswitch.
1443
* -button press arms standby mode.
1444
* 3:standby: Button is pressed for turn on, restart on release. No timing presently.
1447
// enable digital input (want it off during shutdown to save power according to manual)
1448
// not sure how we ever read these pins with this not done.
1449
#if defined(USE_OTSM) && (OTSM_PIN != ESWITCH_PIN)
1450
register uint8_t e_pin_state = (lockswitch||(PINB&(1<<ESWITCH_PIN)));
1451
pins_state = e_pin_state&&(PINB&(1<<OTSM_PIN)); // if either switch is "pressed" (0) this is 0.
1453
pins_state=(PINB&(1<<ESWITCH_PIN));
1454
#if !defined(USE_OTSM) // just an alias in this case to merge code paths:
1455
register uint8_t e_pin_state=pins_state;
1459
if ( pins_state ) {// if button released and still in standown, restart
1460
break; // goto reset
1461
#if defined(USE_OTSM) && (OTSM_PIN == ESWITCH_PIN)
1462
} else if ( (wake_count>wake_count_med)) { // it's a long press
1463
e_standdown=0; // go to full off, this will stop the wake counter.
1464
_delay_loop_2(F_CPU/400); // if this was a clicky switch.. this will bring it down,
1465
// don't want to come on in off mode.
1466
sleep_time_exponent=9; // 16ms*2^9=8s, maximum watchod timeout.
1469
} else if (wake_count>wake_count_med && (!e_pin_state)) { // it's a long e-switch press
1470
e_standdown=0; // only go full off on e-switch press, count on cap to prevent counter overflow
1472
sleep_time_exponent=9; // 16ms*2^9=8s, maximum watchod timeout.
1475
continue; // still in standby, go back to sleep.
1477
if (e_standby && pins_state ) { // if button release while in standby, restart
1478
break; // goto reset //could merge this with e_standdown & pins_state above, might be smaller, might not.
1480
if (!e_standdown && !e_standby && !pins_state ) { // if button pressed while off, restart
1481
e_standby=1; // going to standby, will light when button is released
1483
wake_count+= e_standdown; // increment click time if still in standdown mode.
1484
// continue.. sleep more.
1485
#else // for simple OTSM, if power comes back, we're on:
1486
if(PINB&(1<<OTSM_PIN)) {
1487
break; // goto reset
1492
/***************** Wake on either a power-up (pin change) or a watchdog timeout************/
1493
// At every watchdog wake, increment the wake counter and go back to sleep.
1495
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
1496
// WDTCR = (1<<WDCE) |(1<<WDE);
1497
// WDTCR = (0<<WDE); // might already be in use, so we have to clear it.
1498
WDTCR = (1<<WDIE) |(!!(sleep_time_exponent&8)<<WDP3)|(sleep_time_exponent&7<<WDP0); // set the watchdog timer: 2^n *16 ms datasheet pg 46 for table.
1499
sleep_bod_disable();
1500
sei(); // yep, we're going to nest interrupts, even re-entrenty into this one!
1502
// return from wake ISR's here, both watchdog and pin change.
1504
// Now just figure out what pins are pressed and if we're coming or going, not as simple as it sounds.
1507
/*** Do a soft "reset" of sorts. **/
1509
asm volatile ("" ::: "memory"); // just in case, no i/o reordering around these. It's a noop.
1510
SPL = (RAMEND&0xff); // reset stack pointer, so if we keep going around we don't get a stack overflow.
1511
#if (ATTINY == 45 ) || ( ATTINY == 85 )
1514
SREG=0; // clear status register
1515
main(); // start over, bypassing initialization.
1519
ISR(WDT_vect, ISR_NAKED) // watchdog interrupt handler -FR
1520
{ // gcc avr stacks empty interrupts with a bunch of un-needed initialization.
1521
// do this in assembly and we get one instruction instead about 15.
1522
__asm__ volatile("reti");
1530
// initializer added by Flintrock. This goes into a "secret" code segment that gets run before main.
1531
// It cannot be called. It's cheaper than breaking main into another sub.
1532
// It initializes "cold boot" values. A "reset" instead jumps to main after a switch press
1533
// and must then bypass the wake_counter initializer.
1534
// be careful in here, local variables are not technically allowed (no stack exists), but subroutine calls are.
1535
void __attribute__ ((naked)) __attribute__ ((section (".init8"))) \
1537
initial_values(); // load defaults for eeprom config variables.
1538
// initialize register variables, since gcc stubornly won't do it for us.
1540
#if defined(USE_OTSM) || defined(USE_ESWITCH)
1541
wake_count=255; // initial value on cold reboot, represents large click time.
1545
int __attribute__((OS_task)) main() { // Jump here from a wake interrupt, skipping initialization of wake_count.
1547
// read OTC if needed, and translate it to an OTSM/E_switch wake_count value if using both:
1548
// If only OTC is used, the click decision in change modes is based directly on OTC value.
1549
// If OTSM and/or E_SWITCH is used, it's based on the OTSM/E_SWITCH wake_count.
1550
// If both E_SWITCH and OTC are used, for two switches (no OTSM),
1551
// wake_count is used, and the OTC value first gets translated to a wake_count value if we had a clicking switch press.
1552
// Could just always translate to wake_count, but it adds size.
1555
#if defined(OFFTIM3)&&defined(USE_OTC)
1556
#if !(defined(USE_OTSM)||defined(USE_ESWITCH))
1557
// check the OTC immediately before it has a chance to charge or discharge
1558
uint8_t cap_val = read_otc();
1559
#elif defined(USE_ESWITCH)&!defined(USE_OTSM)
1560
if(wake_count==255) { //255 is re-initialized value, so we had a timed-out clicky press, must use OTC
1561
// translate OTC readings to wake_count
1562
// could simplify and do this for normal OTC too (adds a few lines, but for a simple build anyway).
1563
uint8_t cap_val = read_otc();
1564
if (cap_val>CAP_MED) {
1565
wake_count=wake_count_med; // long press (>= is long)
1566
}else if (cap_val>CAP_SHORT){
1567
wake_count=wake_count_short; // med press
1569
wake_count=0; // short press
1572
#elif defined(USE_OTSM)
1573
#error You cannot define USE_OTSM and USE_OTC at the same time.
1577
init_mcu(); // setup pins, prescalers etc, configure/enable interrupts, etc.
1584
blink_value(cap_val);
1588
restore_state(); // loads user configurations
1590
#ifdef OTSM_debug // for testing your OTSM hardware
1591
// blink out the wake count, then continue into mode as normal.
1592
if (wake_count!=255) {
1593
uint8_t temp=wake_count;
1594
wake_count=0; // this just resets wake_count while blinking so we can click off early and it still works.
1595
// use 0 for debugging but will start at 255 in real use.
1600
//_delay_s(); _delay_s(); // this will increase current for two seconds if otsm_powersave is used.
1601
//// provides a debug singal through the ameter.
1604
// wake_time=0; // use this to make every click act like a fast one for debugging.
1606
count_modes(); // build the working mode group using configured choices.
1608
#if defined(USE_OTSM) || defined(USE_ESWITCH)
1609
change_mode(); // advance, reverse, stay put?
1610
wake_count=0; // reset the wake counter.
1611
#elif !defined(USE_OTC) // no cap_val but no wake_count either (fast_presses method)
1612
change_mode(); // advance, reverse, stay put?
1613
#else // use the cap value, note eswitch+OTC does NOT use cap_val here, cap val is translated above to wake_count in that case.
1614
change_mode(cap_val); // advance, reverse, stay put?
1616
//blink_value(cap_val);
1617
//blink_value(mode_idx);
1625
uint8_t output; // defines the nominal mode for program control.
1626
uint8_t actual_level; // allows modifications for stepdown etc.
1627
#if defined(TEMPERATURE_MON)||defined(USE_TURBO_TIMEOUT)
1628
uint8_t overheat_count = 0;
1632
uint8_t lowbatt_cnt = 0;
1634
// handle mode overrides, like mode group selection and temperature calibration
1635
// if (mode_override) {
1636
if (mode_idx>=MINIMUM_OVERRIDE_MODE) {
1637
// do nothing; mode is already set
1638
// fast_presses = 0;
1639
// clear_presses(); // redundant, already clear on menu entry
1640
// and had to go through menu to get to an override mode.
1641
// at most fast_presses now is 1, saves 6 bytes.
1642
output = mode_idx; // not a typo. override modes don't get converted to an actual output level.
1644
output = modes[mode_idx];
1645
actual_level = output;
1648
if (fast_presses > 0x0f) { // Config mode
1649
_delay_s(); // wait for user to stop fast-pressing button
1650
// fast_presses = 0; // exit this mode after one use
1653
toggles(); // this is the main menu
1654
// The old way: (commented out at bottom of file)
1657
output = modes[mode_idx];
1658
actual_level = output;
1660
#if !defined(NO_STROBES)
1662
// Tried saving some space on these strobes, but it's not easy. gcc does ok though.
1663
// Using a switch does create different code (more jump-table-ish, kind of), but it's not shorter.
1665
else if (output == STROBE_10HZ) {
1666
// 10Hz tactical strobe
1669
#endif // ifdef STROBE_10HZ
1671
else if (output == STROBE_16HZ) {
1672
// 16.6Hz tactical strobe
1675
#endif // ifdef STROBE_16HZ
1677
else if (output == STROBE_8HZ) {
1678
// 8.3Hz Tactical strobe
1681
#endif // ifdef STROBE_8HZ
1682
#ifdef STROBE_OLD_MOVIE
1683
else if (output == STROBE_OLD_MOVIE) {
1684
// Old movie effect strobe, like you some stop motion?
1687
#endif // ifdef STROBE_OLD_MOVIE
1688
#ifdef STROBE_CREEPY
1689
else if (output == STROBE_CREEPY) {
1690
// Creepy effect strobe stop motion effect that is quite cool or quite creepy, dpends how many friends you have with you I suppose.
1693
#endif // ifdef STROBE_CREEPY
1695
#ifdef POLICE_STROBE
1696
else if (output == POLICE_STROBE) {
1698
// police-like strobe
1699
//for(i=0;i<8;i++) {
1702
//for(i=0;i<8;i++) {
1706
#endif // ifdef POLICE_STROBE
1707
#ifdef RANDOM_STROBE
1708
else if (output == RANDOM_STROBE) {
1709
// pseudo-random strobe
1710
uint8_t ms = 34 + (pgm_rand() & 0x3f);
1714
#endif // ifdef RANDOM_STROBE
1715
#ifdef BIKING_STROBE
1716
else if (output == BIKING_STROBE) {
1717
// 2-level stutter beacon for biking and such
1718
#ifdef FULL_BIKING_STROBE
1722
//set_output(255,0,0);
1725
//set_output(0,0,255);
1730
// small/minimal version
1732
//set_output(255,0,0);
1735
//set_output(0,0,255);
1739
#endif // ifdef BIKING_STROBE
1741
else if (output == SOS) { SOS_mode(); }
1744
else if (output == RAMP) {
1746
// simple ramping test
1747
for(r=1; r<=RAMP_SIZE; r++) {
1751
for(r=RAMP_SIZE; r>0; r--) {
1756
#endif // ifdef RAMP
1757
#endif // if !defined(NO_STROBES)
1758
#ifdef USE_BATTCHECK
1759
else if (output == BATTCHECK) {
1760
#ifdef BATTCHECK_VpT
1761
//blink_value(get_voltage()); // for debugging
1762
// blink out volts and tenths
1764
uint8_t result = battcheck();
1765
blink(result >> 5, BLINK_SPEED/6);
1766
_delay_ms(BLINK_SPEED);
1768
_delay_ms(BLINK_SPEED*3/2);
1769
blink(result & 0b00011111, BLINK_SPEED/6);
1770
#else // ifdef BATTCHECK_VpT
1771
// blink zero to five times to show voltage
1772
// (~0%, ~25%, ~50%, ~75%, ~100%, >100%)
1773
blink(battcheck(), BLINK_SPEED/6);
1774
#endif // ifdef BATTCHECK_VpT
1775
// wait between readouts
1776
_delay_s(); _delay_s();
1778
#endif // ifdef USE_BATTCHECK
1779
else if (output == GROUP_SELECT_MODE) {
1780
// exit this mode after one use
1782
// mode_override = 0;
1784
for(i=0; i<NUM_MODEGROUPS; i++) {
1788
blink(1, BLINK_SPEED/3);
1790
_delay_s(); _delay_s();
1792
#ifdef TEMP_CAL_MODE
1793
#ifdef TEMPERATURE_MON
1794
else if (output == TEMP_CAL_MODE) {
1795
// make sure we don't stay in this mode after button press
1797
// mode_override = 0;
1799
// Allow the user to turn off thermal regulation if they want
1802
set_mode(RAMP_SIZE/4); // start somewhat dim during turn-off-regulation mode
1803
_delay_s(); _delay_s();
1805
// run at highest output level, to generate heat
1806
set_mode(RAMP_SIZE);
1808
// measure, save, wait... repeat
1810
maxtemp = get_temperature();
1812
_delay_s(); _delay_s();
1816
#endif // TEMP_CAL_MODE
1817
else { // Regular non-hidden solid mode
1818
// moved this before temp check. Temp check result will still apply on next loop.
1819
// reason is with Vcc reads, we switch back and forth between ADC channels.
1820
// The get temperature includes a delay to stabilize ADC (maybe not needed)
1821
// That delay results in hesitation at turn on.
1822
// So turn on first.
1823
set_mode(actual_level);
1824
#ifdef TEMPERATURE_MON
1825
uint8_t temp=get_temperature();
1827
// step down? (or step back up?)
1828
if (temp >= maxtemp) {
1830
// reduce noise, and limit the lowest step-down level
1831
if ((overheat_count > 8) && (actual_level > (RAMP_SIZE/8))) {
1833
//_delay_ms(5000); // don't ramp down too fast
1834
overheat_count = 0; // don't ramp down too fast
1837
// if we're not overheated, ramp up the user-requested level
1839
if ((temp < maxtemp - 2) && (actual_level < output)) {
1843
// set_mode(actual_level); // redundant
1845
ADC_on(); // switch back to voltage mode
1849
_delay_ms(LOOP_SLEEP); // sleep then check vital signs.
1850
// do the sleep after temp check to create stabilization time after switching adc channel
1851
// this does create a slight feedback delay, but not much.
1852
#ifdef USE_TURBO_TIMEOUT
1853
// modified from BLFA6
1854
if (output == TURBO) {
1855
overheat_count++; // actually, we don't care about roll-over prevention
1856
if (overheat_count > (uint8_t)((double)(TURBO_TIMEOUT)*(double)1000/(double)LOOP_SLEEP)) {
1857
// can't use BLFA6 mode change since we don't have predictable modes.
1858
// Must change actual_level, and lockout mode advance on next click.
1859
output=TURBO_STEPDOWN;
1860
actual_level=TURBO_STEPDOWN;
1861
set_presses(DISABLE_NEXT); // next forward press will keep turbo mode.
1865
} // end regular mode
1867
//****** Now things to do in loop after every mode **************/
1869
clear_presses(); //Theory here requires that every mode/strobe takes at least some time to get here.
1870
// see note in strobe() function.
1872
//if (ADCSRA & (1 << ADIF)) { // if a voltage reading is ready
1873
// FR says good idea, but it only takes 100us at worst.
1874
// let's save a few bytes of code instead.
1875
// See if voltage is lower than what we were looking for
1876
//uint8_t temp=get_voltage();
1877
//blink_value(temp);
1878
//if (temp < ADC_LOW) {
1879
if (get_voltage() < ADC_LOW) {
1884
// See if it's been low for a while, and maybe step down
1885
if (lowbatt_cnt >= 8) {
1886
// DEBUG: blink on step-down:
1887
//set_level(0); _delay_ms(100);
1889
if (actual_level > RAMP_SIZE) { // hidden / blinky modes
1890
// step down from blinky modes to medium
1891
actual_level = RAMP_SIZE / 2;
1892
} else if (actual_level > 1) { // regular solid mode
1893
// step down from solid modes somewhat gradually
1894
// drop by 25% each time
1895
actual_level = (actual_level >> 2) + (actual_level >> 1);
1896
// drop by 50% each time
1897
//actual_level = (actual_level >> 1);
1898
} else { // Already at the lowest mode
1899
// Turn off the light
1901
// Power down as many components as possible
1902
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
1903
cli(); // make sure not to wake back up.
1905
sleep_bod_disable();// power goes from 25uA to 4uA.
1909
// set_mode(actual_level); // redundant
1910
output = actual_level;
1912
// Wait before lowering the level again
1915
// Make sure conversion is running for next time through
1916
//ADCSRA |= (1 << ADSC);
1918
#endif // ifdef VOLTAGE_MON
1919
}// end of main while loop
1920
//return 0; // Standard Return Code
1924
// The old way to do the toggles, in case we need it back:
1925
//// Enter or leave "muggle mode"?
1926
//toggle(&muggle_mode, 1);
1927
//if (muggle_mode) { continue; }; // don't offer other options in muggle mode
1929
//toggle(&memory, 2);
1931
//toggle(&enable_moon, 3);
1933
//toggle(&reverse_modes, 4);
1935
//// Enter the mode group selection mode?
1936
//mode_idx = GROUP_SELECT_MODE;
1937
//toggle(&mode_override, 5);
1941
//toggle(&offtim3, 6);
1944
//#ifdef TEMPERATURE_MON
1945
//// Enter temperature calibration mode?
1946
//mode_idx = TEMP_CAL_MODE;
1947
//toggle(&mode_override, 7);
1951
//#ifdef USE_FIRSTBOOT
1952
//toggle(&firstboot, 8);
1954
//#if defined(USE_ESWITCH) && (OTSM_PIN != ESWITCH_PIN)
1955
//toggle(&lockswitch, 9);