Guest User

Untitled

a guest
May 30th, 2015
26
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * BLF EE A6 firmware (special-edition group buy light)
  3.  * This light uses a FET+1 style driver, with a FET on the main PWM channel
  4.  * for the brightest high modes and a single 7135 chip on the secondary PWM
  5.  * channel so we can get stable, efficient low / medium modes.  It also
  6.  * includes a capacitor for measuring off time.
  7.  *
  8.  * Copyright (C) 2015 Selene Scriven
  9.  *
  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.
  14.  *
  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.
  19.  *
  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/>.
  22.  *
  23.  *
  24.  * NANJG 105C Diagram
  25.  *           ---
  26.  *         -|   |- VCC
  27.  *     OTC -|   |- Voltage ADC
  28.  *  Star 3 -|   |- PWM (FET)
  29.  *     GND -|   |- PWM (1x7135)
  30.  *           ---
  31.  *
  32.  * FUSES
  33.  *      I use these fuse settings
  34.  *      Low:  0x75  (4.8MHz CPU without 8x divider, 9.4kHz phase-correct PWM or 18.75kHz fast-PWM)
  35.  *      High: 0xff
  36.  *
  37.  *      For more details on these settings, visit http://github.com/JCapSolutions/blf-firmware/wiki/PWM-Frequency
  38.  *
  39.  * STARS
  40.  *      Star 2 = second PWM output channel
  41.  *      Star 3 = mode memory if soldered, no memory by default
  42.  *      Star 4 = Capacitor for off-time
  43.  *
  44.  * VOLTAGE
  45.  *      Resistor values for voltage divider (reference BLF-VLD README for more info)
  46.  *      Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
  47.  *
  48.  *           VCC
  49.  *            |
  50.  *           Vd (~.25 v drop from protection diode)
  51.  *            |
  52.  *          1912 (R1 19,100 ohms)
  53.  *            |
  54.  *            |---- PB2 from MCU
  55.  *            |
  56.  *          4701 (R2 4,700 ohms)
  57.  *            |
  58.  *           GND
  59.  *
  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.
  64.  *
  65.  *   Same for off-time capacitor values.  Measure, don't guess.
  66.  */
  67. #define F_CPU 4800000UL
  68.  
  69. /*
  70.  * =========================================================================
  71.  * Settings to modify per driver
  72.  */
  73.  
  74. //#define FAST 0x23           // fast PWM channel 1 only
  75. //#define PHASE 0x21          // phase-correct PWM channel 1 only
  76. #define FAST 0xA3           // fast PWM both channels
  77. #define PHASE 0xA1          // phase-correct PWM both channels
  78.  
  79. #define VOLTAGE_MON         // Comment out to disable LVP
  80. #define OWN_DELAY           // Should we use the built-in delay or our own?
  81. // Adjust the timing per-driver, since the hardware has high variance
  82. // Higher values will run slower, lower values run faster.
  83. #define DELAY_TWEAK         950
  84.  
  85. #define OFFTIM3             // Use short/med/long off-time presses
  86.                             // instead of just short/long
  87.  
  88. // comment out to use extended config mode instead of a solderable star
  89. // (controls whether mode memory is on the star or if it's a setting in config mode)
  90. //#define CONFIG_STARS
  91.  
  92. // Mode group 1
  93. #define NUM_MODES1          4
  94. // PWM levels for the big circuit (FET or Nx7135)
  95. #define MODESNx1            0,22,100,255
  96. // PWM levels for the small circuit (1x7135)
  97. #define MODES1x1            8,22,100,255
  98. // PWM speed for each mode
  99. #define MODES_PWM1          PHASE,FAST,FAST,FAST
  100. // Mode group 2
  101. #define NUM_MODES2          5
  102. #define MODESNx2            0,25,102,255,0
  103. #define MODES1x2            7,0,0,0,255
  104. #define MODES_PWM2          PHASE,FAST,FAST,FAST,FAST
  105. // Hidden modes are *before* the lowest (moon) mode, and should be specified
  106. // in reverse order.  So, to go backward from moon to turbo to strobe to
  107. // battcheck, use BATTCHECK,STROBE,TURBO .
  108. #define NUM_HIDDEN          0
  109. #define HIDDENMODES        
  110. #define HIDDENMODES_PWM    
  111.  
  112. // Uncomment to use a 2-level stutter beacon instead of a tactical strobe
  113. //#define BIKING_STROBE
  114.  
  115. #define NON_WDT_TURBO            // enable turbo step-down without WDT
  116. // How many timer ticks before before dropping down.
  117. // Each timer tick is 500ms, so "60" would be a 30-second stepdown.
  118. // Max value of 255 unless you change "ticks"
  119. #define TURBO_TIMEOUT       120
  120.  
  121. // These values were measured using wight's "A17HYBRID-S" driver built by DBCstm.
  122. // Your mileage may vary.
  123. #define ADC_42          174 // the ADC value we expect for 4.20 volts
  124. #define ADC_100         174 // the ADC value for 100% full (4.2V resting)
  125. #define ADC_75          165 // the ADC value for 75% full (4.0V resting)
  126. #define ADC_50          155 // the ADC value for 50% full (3.8V resting)
  127. #define ADC_25          141 // the ADC value for 25% full (3.5V resting)
  128. #define ADC_0           118 // the ADC value for 0% full (3.0V resting)
  129. #define ADC_LOW         120 // When do we start ramping down (2.8V)
  130. #define ADC_CRIT        111 // When do we shut the light off (2.7V)
  131. // These values were copied from s7.c.
  132. // Your mileage may vary.
  133. //#define ADC_42          185 // the ADC value we expect for 4.20 volts
  134. //#define ADC_100         185 // the ADC value for 100% full (4.2V resting)
  135. //#define ADC_75          175 // the ADC value for 75% full (4.0V resting)
  136. //#define ADC_50          164 // the ADC value for 50% full (3.8V resting)
  137. //#define ADC_25          154 // the ADC value for 25% full (3.5V resting)
  138. //#define ADC_0           139 // the ADC value for 0% full (3.0V resting)
  139. //#define ADC_LOW         123 // When do we start ramping down (2.8V)
  140. //#define ADC_CRIT        113 // When do we shut the light off (2.7V)
  141. // Values for testing only:
  142. //#define ADC_LOW         125 // When do we start ramping down (2.8V)
  143. //#define ADC_CRIT        124 // When do we shut the light off (2.7V)
  144.  
  145. // the BLF EE A6 driver may have different offtime cap values than most other drivers
  146. #ifdef OFFTIM3
  147. #define CAP_SHORT           245  // Value between 1 and 255 corresponding with cap voltage (0 - 1.1v) where we consider it a short press to move to the next mode
  148. #define CAP_MED             170  // Value between 1 and 255 corresponding with cap voltage (0 - 1.1v) where we consider it a short press to move to the next mode
  149. #else
  150. #define CAP_SHORT           200  // Value between 1 and 255 corresponding with cap voltage (0 - 1.1v) where we consider it a short press to move to the next mode
  151.                                  // Not sure the lowest you can go before getting bad readings, but with a value of 70 and a 1uF cap, it seemed to switch sometimes
  152.                                  // even when waiting 10 seconds between presses.
  153. #endif
  154.  
  155. #define TURBO     255       // Convenience code for turbo mode
  156. #define STROBE    254       // Convenience code for strobe mode
  157. #define BATTCHECK 253       // Convenience code for battery check mode
  158.  
  159. /*
  160.  * =========================================================================
  161.  */
  162.  
  163. #ifdef OWN_DELAY
  164. #include <util/delay_basic.h>
  165. // Having own _delay_ms() saves some bytes AND adds possibility to use variables as input
  166. void _delay_ms(uint16_t n)
  167. {
  168.     // TODO: make this take tenths of a ms instead of ms,
  169.     // for more precise timing?
  170.     while(n-- > 0) _delay_loop_2(DELAY_TWEAK);
  171. }
  172. void _delay_s()  // because it saves a bit of ROM space to do it this way
  173. {
  174.     _delay_ms(1000);
  175. }
  176. #else
  177. #include <util/delay.h>
  178. #endif
  179.  
  180. #include <avr/pgmspace.h>
  181. //#include <avr/io.h>
  182. //#include <avr/interrupt.h>
  183. #include <avr/eeprom.h>
  184. #include <avr/sleep.h>
  185. //#include <avr/power.h>
  186.  
  187. #define STAR2_PIN   PB0     // But note that there is no star 2.
  188. #define STAR3_PIN   PB4
  189. #define CAP_PIN     PB3
  190. #define CAP_CHANNEL 0x03    // MUX 03 corresponds with PB3 (Star 4)
  191. #define CAP_DIDR    ADC3D   // Digital input disable bit corresponding with PB3
  192. #define PWM_PIN     PB1
  193. #define ALT_PWM_PIN PB0
  194. #define VOLTAGE_PIN PB2
  195. #define ADC_CHANNEL 0x01    // MUX 01 corresponds with PB2
  196. #define ADC_DIDR    ADC1D   // Digital input disable bit corresponding with PB2
  197. #define ADC_PRSCL   0x06    // clk/64
  198.  
  199. #define PWM_LVL     OCR0B   // OCR0B is the output compare register for PB1
  200. #define ALT_PWM_LVL OCR0A   // OCR0A is the output compare register for PB0
  201.  
  202. /*
  203.  * global variables
  204.  */
  205.  
  206. // Config / state variables
  207. uint8_t eepos = 0;
  208. uint8_t memory = 0;        // mode memory, or not (set via soldered star)
  209. uint8_t modegroup = 0;     // which mode group (set above in #defines)
  210. uint8_t mode_idx = 0;      // current or last-used mode number
  211. uint8_t fast_presses = 0;  // counter for entering config mode
  212.  
  213. // NOTE: Only '1' is known to work; -1 will probably break and is untested.
  214. // In other words, short press goes to the next (higher) mode,
  215. // medium press goes to the previous (lower) mode.
  216. #define mode_dir 1
  217. // total length of current mode group's array
  218. uint8_t mode_cnt;
  219. // number of regular non-hidden modes in current mode group
  220. uint8_t solid_modes;
  221. // number of hidden modes in the current mode group
  222. // (hardcoded because both groups have the same hidden modes)
  223. //uint8_t hidden_modes = NUM_HIDDEN;  // this is never used
  224.  
  225.  
  226. // Modes (gets set when the light starts up based on saved config values)
  227. PROGMEM const uint8_t modesNx1[] = { MODESNx1, HIDDENMODES };
  228. PROGMEM const uint8_t modesNx2[] = { MODESNx2, HIDDENMODES };
  229. const uint8_t *modesNx;  // gets pointed at whatever group is current
  230.  
  231. PROGMEM const uint8_t modes1x1[] = { MODES1x1, HIDDENMODES };
  232. PROGMEM const uint8_t modes1x2[] = { MODES1x2, HIDDENMODES };
  233. const uint8_t *modes1x;
  234.  
  235. PROGMEM const uint8_t modes_pwm1[] = { MODES_PWM1, HIDDENMODES_PWM };
  236. PROGMEM const uint8_t modes_pwm2[] = { MODES_PWM2, HIDDENMODES_PWM };
  237. const uint8_t *modes_pwm;
  238.  
  239. PROGMEM const uint8_t voltage_blinks[] = {
  240.     ADC_0,    // 1 blink  for 0%-25%
  241.     ADC_25,   // 2 blinks for 25%-50%
  242.     ADC_50,   // 3 blinks for 50%-75%
  243.     ADC_75,   // 4 blinks for 75%-100%
  244.     ADC_100,  // 5 blinks for >100%
  245. };
  246.  
  247. void save_state() {  // central method for writing (with wear leveling)
  248.     uint8_t oldpos=eepos;
  249.     // a single 16-bit write uses less ROM space than two 8-bit writes
  250.     uint16_t eep;
  251.  
  252.     eepos=(eepos+2)&31;  // wear leveling, use next cell
  253.  
  254. #ifdef CONFIG_STARS
  255.     eep = mode_idx | (fast_presses << 12) | (modegroup << 8);
  256. #else
  257.     eep = mode_idx | (fast_presses << 12) | (modegroup << 8) | (memory << 9);
  258. #endif
  259.     eeprom_write_word((uint16_t *)(eepos), eep);      // save current state
  260.     eeprom_write_word((uint16_t *)(oldpos), 0xffff);  // erase old state
  261. }
  262.  
  263. void restore_state() {
  264.     // two 8-bit reads use less ROM space than a single 16-bit write
  265.     uint8_t eep1;
  266.     uint8_t eep2;
  267.     // find the config data
  268.     for(eepos=0; eepos<32; eepos+=2) {
  269.         eep1 = eeprom_read_byte((const uint8_t *)eepos);
  270.         eep2 = eeprom_read_byte((const uint8_t *)eepos+1);
  271.         if (eep1 != 0xff) break;
  272.     }
  273.     // unpack the config data
  274.     if (eepos < 32) {
  275.         mode_idx = eep1;
  276.         fast_presses = (eep2 >> 4);
  277.         modegroup = eep2 & 1;
  278. #ifndef CONFIG_STARS
  279.         memory = (eep2 >> 1) & 1;
  280. #endif
  281.     }
  282.     //else eepos=0;  // unnecessary, save_state handles wrap-around
  283. }
  284.  
  285. inline void next_mode() {
  286.     mode_idx += 1;
  287.     if (mode_idx >= solid_modes) {
  288.         // Wrap around, skipping the hidden modes
  289.         // (note: this also applies when going "forward" from any hidden mode)
  290.         mode_idx = 0;
  291.     }
  292. }
  293.  
  294. #ifdef OFFTIM3
  295. inline void prev_mode() {
  296.     if (mode_idx == solid_modes) {
  297.         // If we hit the end of the hidden modes, go back to moon
  298.         mode_idx = 0;
  299.     } else if (mode_idx > 0) {
  300.         // Regular mode: is between 1 and TOTAL_MODES
  301.         mode_idx -= 1;
  302.     } else {
  303.         // Otherwise, wrap around (this allows entering hidden modes)
  304.         mode_idx = mode_cnt - 1;
  305.     }
  306. }
  307. #endif
  308.  
  309. #ifdef CONFIG_STARS
  310. inline void check_stars() {
  311.     // Configure options based on stars
  312.     // 0 being low for soldered, 1 for pulled-up for not soldered
  313. #if 0  // not implemented, STAR2_PIN is used for second PWM channel
  314.     // Moon
  315.     // enable moon mode?
  316.     if ((PINB & (1 << STAR2_PIN)) == 0) {
  317.         modes[mode_cnt++] = MODE_MOON;
  318.     }
  319. #endif
  320. #if 0  // Mode order not as important as mem/no-mem
  321.     // Mode order
  322.     if ((PINB & (1 << STAR3_PIN)) == 0) {
  323.         // High to Low
  324.         mode_dir = -1;
  325.     } else {
  326.         mode_dir = 1;
  327.     }
  328. #endif
  329.     // Memory
  330.     if ((PINB & (1 << STAR3_PIN)) == 0) {
  331.         memory = 1;  // solder to enable memory
  332.     } else {
  333.         memory = 0;  // unsolder to disable memory
  334.     }
  335. }
  336. #endif  // ifdef CONFIG_STARS
  337.  
  338. void count_modes() {
  339.     /*
  340.      * Determine how many solid and hidden modes we have.
  341.      * The modes_pwm array should have several values for regular modes
  342.      * then some values for hidden modes.
  343.      *
  344.      * (this matters because we have more than one set of modes to choose
  345.      *  from, so we need to count at runtime)
  346.      */
  347.     if (modegroup == 0) {
  348.         solid_modes = NUM_MODES1;
  349.         modesNx = modesNx1;
  350.         modes1x = modes1x1;
  351.         modes_pwm = modes_pwm1;
  352.     } else {
  353.         solid_modes = NUM_MODES2;
  354.         modesNx = modesNx2;
  355.         modes1x = modes1x2;
  356.         modes_pwm = modes_pwm2;
  357.     }
  358.     mode_cnt = solid_modes + NUM_HIDDEN;
  359. }
  360.  
  361. #ifdef VOLTAGE_MON
  362. inline void ADC_on() {
  363.     DIDR0 |= (1 << ADC_DIDR);                           // disable digital input on ADC pin to reduce power consumption
  364.     ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
  365.     ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
  366. }
  367. #else
  368. inline void ADC_off() {
  369.     ADCSRA &= ~(1<<7); //ADC off
  370. }
  371. #endif
  372.  
  373. void set_output(uint8_t pwm1, uint8_t pwm2) {
  374.     // Need PHASE to properly turn off the light
  375.     if ((pwm1==0) && (pwm2==0)) {
  376.         TCCR0A = PHASE;
  377.     }
  378.     PWM_LVL = pwm1;
  379.     ALT_PWM_LVL = pwm2;
  380. }
  381.  
  382. void set_mode(mode) {
  383.     TCCR0A = pgm_read_byte(modes_pwm + mode);
  384.     set_output(pgm_read_byte(modesNx + mode), pgm_read_byte(modes1x + mode));
  385.     /*
  386.     // Only set output for solid modes
  387.     uint8_t out = pgm_read_byte(modesNx + mode);
  388.     if ((out < 250) || (out == 255)) {
  389.         set_output(pgm_read_byte(modesNx + mode), pgm_read_byte(modes1x + mode));
  390.     }
  391.     */
  392. }
  393.  
  394. #ifdef VOLTAGE_MON
  395. uint8_t get_voltage() {
  396.     // Start conversion
  397.     ADCSRA |= (1 << ADSC);
  398.     // Wait for completion
  399.     while (ADCSRA & (1 << ADSC));
  400.     // See if voltage is lower than what we were looking for
  401.     return ADCH;
  402. }
  403. #endif
  404.  
  405. void blink(uint8_t val)
  406. {
  407.     for (; val>0; val--)
  408.     {
  409.         set_output(0,20);
  410.         _delay_ms(100);
  411.         set_output(0,0);
  412.         _delay_ms(400);
  413.     }
  414. }
  415.  
  416. int main(void)
  417. {
  418.     uint8_t cap_val;
  419.  
  420.     // Read the off-time cap *first* to get the most accurate reading
  421.     // Start up ADC for capacitor pin
  422.     DIDR0 |= (1 << CAP_DIDR);                           // disable digital input on ADC pin to reduce power consumption
  423.     ADMUX  = (1 << REFS0) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3
  424.     ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
  425.  
  426.     // Wait for completion
  427.     while (ADCSRA & (1 << ADSC));
  428.     // Start again as datasheet says first result is unreliable
  429.     ADCSRA |= (1 << ADSC);
  430.     // Wait for completion
  431.     while (ADCSRA & (1 << ADSC));
  432.     cap_val = ADCH; // save this for later
  433.  
  434.     // All ports default to input, but turn pull-up resistors on for the stars (not the ADC input!  Made that mistake already)
  435.     // only one star, because one is used for PWM channel 2
  436.     // and the other is used for the off-time capacitor
  437.     PORTB = (1 << STAR3_PIN);
  438.  
  439.     // Set PWM pin to output
  440.     DDRB |= (1 << PWM_PIN);     // enable main channel
  441.     DDRB |= (1 << ALT_PWM_PIN); // enable second channel
  442.  
  443.     // Set timer to do PWM for correct output pin and set prescaler timing
  444.     //TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
  445.     //TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  446.     TCCR0A = PHASE;
  447.     // Set timer to do PWM for correct output pin and set prescaler timing
  448.     TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  449.  
  450.     // Read config values and saved state
  451. #ifdef CONFIG_STARS
  452.     check_stars();
  453. #endif
  454.     restore_state();
  455.     // Enable the current mode group
  456.     count_modes();
  457.  
  458.  
  459.     if (cap_val > CAP_SHORT) {
  460.         // Indicates they did a short press, go to the next mode
  461.         next_mode(); // Will handle wrap arounds
  462.         if (fast_presses < 15) fast_presses ++;
  463. #ifdef OFFTIM3
  464.     } else if (cap_val > CAP_MED) {
  465.         // User did a medium press, go back one mode
  466.         prev_mode(); // Will handle "negative" modes and wrap-arounds
  467.         fast_presses = 0;
  468. #endif
  469.     } else {
  470.         // Long press, keep the same mode
  471.         // ... or reset to the first mode
  472.         fast_presses = 0;
  473.         if (! memory) {
  474.             // Reset to the first mode
  475.             mode_idx = 0;
  476.         }
  477.     }
  478.     save_state();
  479.  
  480.     // Turn off ADC
  481.     //ADC_off();
  482.  
  483.     // Charge up the capacitor by setting CAP_PIN to output
  484.     DDRB  |= (1 << CAP_PIN);    // Output
  485.     PORTB |= (1 << CAP_PIN);    // High
  486.  
  487.     // Turn features on or off as needed
  488.     #ifdef VOLTAGE_MON
  489.     ADC_on();
  490.     #else
  491.     ADC_off();
  492.     #endif
  493.     //ACSR   |=  (1<<7); //AC off
  494.  
  495.     // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
  496.     // Will allow us to go idle between WDT interrupts
  497.     //set_sleep_mode(SLEEP_MODE_IDLE);  // not used due to blinky modes
  498.  
  499.     uint8_t output;
  500. #ifdef NON_WDT_TURBO
  501.     uint8_t ticks = 0;
  502. #endif
  503. #ifdef VOLTAGE_MON
  504.     uint8_t lowbatt_cnt = 0;
  505.     uint8_t i = 0;
  506.     uint8_t voltage;
  507.     // Make sure voltage reading is running for later
  508.     ADCSRA |= (1 << ADSC);
  509. #endif
  510.     while(1) {
  511.         output = pgm_read_byte(modesNx + mode_idx);
  512.         if (fast_presses == 0x0f) {  // Config mode
  513.             _delay_s();       // wait for user to stop fast-pressing button
  514.             fast_presses = 0; // exit this mode after one use
  515.             mode_idx = 0;
  516.  
  517. #ifdef CONFIG_STARS
  518.             // Short/small version of the config mode
  519.             // Toggle the mode group, blink, then exit
  520.             modegroup ^= 1;
  521.             save_state();
  522.             count_modes();  // reconfigure without a power cycle
  523.             blink(1);
  524. #else
  525.             // Longer/larger version of the config mode
  526.             // Toggle the mode group, blink, un-toggle, continue
  527.             modegroup ^= 1;
  528.             save_state();
  529.             blink(2);
  530.             modegroup ^= 1;
  531.  
  532.             _delay_s();
  533.  
  534.             // Toggle memory, blink, untoggle, exit
  535.             memory ^= 1;
  536.             save_state();
  537.             blink(2);
  538.             memory ^= 1;
  539.  
  540.             save_state();
  541. #endif  // ifdef CONFIG_STARS
  542.         }
  543.         else if (output == STROBE) {
  544. // ifdef BIKING_STROBE
  545.         }
  546.         else if (output == BATTCHECK) {
  547.             uint8_t blinks = 0;
  548.             // turn off and wait one second before showing the value
  549.             // (also, ensure voltage is measured while not under load)
  550.             set_output(0,0);
  551.             _delay_s();
  552.             voltage = get_voltage();
  553.             voltage = get_voltage(); // the first one is unreliable
  554.             // division takes too much flash space
  555.             //voltage = (voltage-ADC_LOW) / (((ADC_42 - 15) - ADC_LOW) >> 2);
  556.             // a table uses less space than 5 logic clauses
  557.             for (i=0; i<sizeof(voltage_blinks); i++) {
  558.                 if (voltage > pgm_read_byte(voltage_blinks + i)) {
  559.                     blinks ++;
  560.                 }
  561.             }
  562.  
  563.             // blink up to five times to show voltage
  564.             // (~0%, ~25%, ~50%, ~75%, ~100%, >100%)
  565.             blink(blinks);
  566.             _delay_s();  // wait at least 1 second between readouts
  567.         }
  568.         else {  // Regular non-hidden solid mode
  569.             set_mode(mode_idx);
  570.             // This part of the code will mostly replace the WDT tick code.
  571. #ifdef NON_WDT_TURBO
  572.             // Do some magic here to handle turbo step-down
  573.             if (ticks < 255) ticks++;
  574.             if ((ticks > TURBO_TIMEOUT)
  575.                     && (output == TURBO)) {
  576.                 mode_idx = solid_modes - 2; // step down to second-highest mode
  577.                 set_mode(mode_idx);
  578.                 save_state();
  579.             }
  580. #endif
  581.             // Otherwise, just sleep.
  582.             _delay_ms(500);
  583.  
  584.             // If we got this far, the user has stopped fast-pressing.
  585.             // So, don't enter config mode.
  586.             fast_presses = 0;
  587.             save_state();
  588.         }
  589. #ifdef VOLTAGE_MON
  590. #if 1
  591.         if (ADCSRA & (1 << ADIF)) {  // if a voltage reading is ready
  592.             voltage = ADCH; // get_voltage();
  593.             // See if voltage is lower than what we were looking for
  594.             //if (voltage < ((mode_idx <= 1) ? ADC_CRIT : ADC_LOW)) {
  595.             if (voltage < ADC_LOW) {
  596.                 lowbatt_cnt ++;
  597.             } else {
  598.                 lowbatt_cnt = 0;
  599.             }
  600.             // See if it's been low for a while, and maybe step down
  601.             if (lowbatt_cnt >= 8) {
  602.                 // DEBUG: blink on step-down:
  603.                 //set_output(0,0);  _delay_ms(100);
  604.                 i = mode_idx; // save space by not accessing mode_idx more than necessary
  605.                 // properly track hidden vs normal modes
  606.                 if (i >= solid_modes) {
  607.                     // step down from blinky modes to medium
  608.                     i = 2;
  609.                 } else if (i > 0) {
  610.                     // step down from solid modes one at a time
  611.                     i -= 1;
  612.                 } else { // Already at the lowest mode
  613.                     i = 0;
  614.                     // Turn off the light
  615.                     set_output(0,0);
  616.                     // Power down as many components as possible
  617.                     set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  618.                     sleep_mode();
  619.                 }
  620.                 set_mode(i);
  621.                 mode_idx = i;
  622.                 save_state();
  623.                 lowbatt_cnt = 0;
  624.                 // Wait at least 2 seconds before lowering the level again
  625.                 _delay_ms(250);  // this will interrupt blinky modes
  626.             }
  627.  
  628.             // Make sure conversion is running for next time through
  629.             ADCSRA |= (1 << ADSC);
  630.         }
  631. #endif
  632. #endif  // ifdef VOLTAGE_MON
  633.         //sleep_mode();  // incompatible with blinky modes
  634.     }
  635.  
  636.     //return 0; // Standard Return Code
  637. }
RAW Paste Data