SHARE
TWEET

PD68 TripleDown FW - Test Version

a guest Jan 17th, 2016 171 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: 0xfd  (to enable brownout detection)
  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.  
  89. // output to use for blinks on battery check mode (primary PWM level, alt PWM level)
  90. // Use 20,0 for a single-channel driver or 0,20 for a two-channel driver
  91. #define BLINK_BRIGHTNESS    20,20
  92.  
  93. // Mode group 1
  94. #define NUM_MODES1          3
  95. // PWM levels for the big circuit (FET or Nx7135)
  96. #define MODESNx1            0,255,TURBO
  97. // PWM levels for the small circuit (1x7135)
  98. #define MODES1x1            255,0,0
  99. // PWM speed for each mode
  100. #define MODES_PWM1          PHASE,PHASE,PHASE
  101. // Mode group 2
  102. #define NUM_MODES2          5
  103. #define MODESNx2            0,0,15,255,TURBO
  104. #define MODES1x2            5,255,0,0,0
  105. #define MODES_PWM2          PHASE,FAST,FAST,FAST,FAST
  106. // Hidden modes are *before* the lowest (moon) mode, and should be specified
  107. // in reverse order.  So, to go backward from moon to turbo to strobe to
  108. // battcheck, use BATTCHECK,STROBE,TURBO .
  109. #define NUM_HIDDEN          0
  110. #define HIDDENMODES         0
  111. #define HIDDENMODES_PWM     0
  112. #define HIDDENMODES_ALT     0  // Zeroes, same length as NUM_HIDDEN
  113.  
  114. #define TURBO     245       // Convenience code for turbo mode
  115. #define BATTCHECK 254       // Convenience code for battery check mode
  116. // Uncomment to enable tactical strobe mode
  117. //#define STROBE    253       // Convenience code for strobe mode
  118. // Uncomment to unable a 2-level stutter beacon instead of a tactical strobe
  119. //#define BIKING_STROBE 252   // Convenience code for biking strobe mode
  120. // comment out to use minimal version instead (smaller)
  121. //#define FULL_BIKING_STROBE
  122.  
  123. #define NON_WDT_TURBO            // enable turbo step-down without WDT
  124. // How many timer ticks before before dropping down.
  125. // Each timer tick is 500ms, so "60" would be a 30-second stepdown.
  126. // Max value of 255 unless you change "ticks"
  127. #define TURBO_TIMEOUT       10
  128.  
  129. // These values were measured using wight's "A17HYBRID-S" driver built by DBCstm.
  130. // Your mileage may vary.
  131. #define ADC_42          174 // the ADC value we expect for 4.20 volts
  132. #define ADC_100         174 // the ADC value for 100% full (4.2V resting)
  133. #define ADC_75          166 // the ADC value for 75% full (4.0V resting)
  134. #define ADC_50          158 // the ADC value for 50% full (3.8V resting)
  135. #define ADC_25          145 // the ADC value for 25% full (3.5V resting)
  136. #define ADC_0           124 // the ADC value for 0% full (3.0V resting)
  137. #define ADC_LOW         116 // When do we start ramping down (2.8V)
  138. #define ADC_CRIT        112 // When do we shut the light off (2.7V)
  139. // These values were copied from s7.c.
  140. // Your mileage may vary.
  141. //#define ADC_42          185 // the ADC value we expect for 4.20 volts
  142. //#define ADC_100         185 // the ADC value for 100% full (4.2V resting)
  143. //#define ADC_75          175 // the ADC value for 75% full (4.0V resting)
  144. //#define ADC_50          164 // the ADC value for 50% full (3.8V resting)
  145. //#define ADC_25          154 // the ADC value for 25% full (3.5V resting)
  146. //#define ADC_0           139 // the ADC value for 0% full (3.0V resting)
  147. //#define ADC_LOW         123 // When do we start ramping down (2.8V)
  148. //#define ADC_CRIT        113 // When do we shut the light off (2.7V)
  149. // Values for testing only:
  150. //#define ADC_LOW         125 // When do we start ramping down (2.8V)
  151. //#define ADC_CRIT        124 // When do we shut the light off (2.7V)
  152.  
  153. // the BLF EE A6 driver may have different offtime cap values than most other drivers
  154. // Values are between 1 and 255, and can be measured with offtime-cap.c
  155. // These #defines are the edge boundaries, not the center of the target.
  156. #ifdef OFFTIM3
  157. #define CAP_SHORT           250  // Anything higher than this is a short press
  158. #define CAP_MED             190  // Between CAP_MED and CAP_SHORT is a medium press
  159.                                  // Below CAP_MED is a long press
  160. #else
  161. #define CAP_SHORT           190  // Anything higher than this is a short press, lower is a long press
  162. #endif
  163.  
  164. /*
  165.  * =========================================================================
  166.  */
  167.  
  168. // Ignore a spurious warning, we did the cast on purpose
  169. #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
  170.  
  171. #ifdef OWN_DELAY
  172. #include <util/delay_basic.h>
  173. // Having own _delay_ms() saves some bytes AND adds possibility to use variables as input
  174. void _delay_ms(uint16_t n)
  175. {
  176.     // TODO: make this take tenths of a ms instead of ms,
  177.     // for more precise timing?
  178.     while(n-- > 0) _delay_loop_2(DELAY_TWEAK);
  179. }
  180. void _delay_s()  // because it saves a bit of ROM space to do it this way
  181. {
  182.     _delay_ms(1000);
  183. }
  184. #else
  185. #include <util/delay.h>
  186. #endif
  187.  
  188. #include <avr/pgmspace.h>
  189. //#include <avr/io.h>
  190. //#include <avr/interrupt.h>
  191. #include <avr/eeprom.h>
  192. #include <avr/sleep.h>
  193. //#include <avr/power.h>
  194.  
  195. #define STAR2_PIN   PB0     // But note that there is no star 2.
  196. #define FET_PIN   PB4
  197. #define CAP_PIN     PB3
  198. #define CAP_CHANNEL 0x03    // MUX 03 corresponds with PB3 (Star 4)
  199. #define CAP_DIDR    ADC3D   // Digital input disable bit corresponding with PB3
  200. #define PWM_PIN     PB1
  201. #define ALT_PWM_PIN PB0
  202. #define VOLTAGE_PIN PB2
  203. #define ADC_CHANNEL 0x01    // MUX 01 corresponds with PB2
  204. #define ADC_DIDR    ADC1D   // Digital input disable bit corresponding with PB2
  205. #define ADC_PRSCL   0x06    // clk/64
  206.  
  207. #define PWM_LVL     OCR0B   // OCR0B is the output compare register for PB1
  208. #define ALT_PWM_LVL OCR0A   // OCR0A is the output compare register for PB0
  209.  
  210. /*
  211.  * global variables
  212.  */
  213.  
  214. // Config / state variables
  215. uint8_t eepos = 0;
  216. uint8_t memory = 0;        // mode memory, or not (set via soldered star)
  217. uint8_t modegroup = 0;     // which mode group (set above in #defines)
  218. uint8_t mode_idx = 0;      // current or last-used mode number
  219. // counter for entering config mode
  220. // (needs to be remembered while off, but only for up to half a second)
  221. uint8_t fast_presses __attribute__ ((section (".noinit")));
  222.  
  223. // NOTE: Only '1' is known to work; -1 will probably break and is untested.
  224. // In other words, short press goes to the next (higher) mode,
  225. // medium press goes to the previous (lower) mode.
  226. #define mode_dir 1
  227. // total length of current mode group's array
  228. uint8_t mode_cnt;
  229. // number of regular non-hidden modes in current mode group
  230. uint8_t solid_modes;
  231. // number of hidden modes in the current mode group
  232. // (hardcoded because both groups have the same hidden modes)
  233. //uint8_t hidden_modes = NUM_HIDDEN;  // this is never used
  234.  
  235.  
  236. // Modes (gets set when the light starts up based on saved config values)
  237. PROGMEM const uint8_t modesNx1[] = { MODESNx1, HIDDENMODES };
  238. PROGMEM const uint8_t modesNx2[] = { MODESNx2, HIDDENMODES };
  239. const uint8_t *modesNx;  // gets pointed at whatever group is current
  240.  
  241. PROGMEM const uint8_t modes1x1[] = { MODES1x1, HIDDENMODES_ALT };
  242. PROGMEM const uint8_t modes1x2[] = { MODES1x2, HIDDENMODES_ALT };
  243. const uint8_t *modes1x;
  244.  
  245. PROGMEM const uint8_t modes_pwm1[] = { MODES_PWM1, HIDDENMODES_PWM };
  246. PROGMEM const uint8_t modes_pwm2[] = { MODES_PWM2, HIDDENMODES_PWM };
  247. const uint8_t *modes_pwm;
  248.  
  249. PROGMEM const uint8_t voltage_blinks[] = {
  250.     ADC_0,    // 1 blink  for 0%-25%
  251.     ADC_25,   // 2 blinks for 25%-50%
  252.     ADC_50,   // 3 blinks for 50%-75%
  253.     ADC_75,   // 4 blinks for 75%-100%
  254.     ADC_100,  // 5 blinks for >100%
  255.     255,      // Ceiling, don't remove
  256. };
  257.  
  258. void save_state() {  // central method for writing (with wear leveling)
  259.     // a single 16-bit write uses less ROM space than two 8-bit writes
  260.     uint8_t eep;
  261.     uint8_t oldpos=eepos;
  262.  
  263.     eepos = (eepos+1) & 63;  // wear leveling, use next cell
  264.  
  265.  
  266.     eep = mode_idx | (modegroup << 5) | (memory << 6);
  267.     eeprom_write_byte((uint8_t *)(eepos), eep);      // save current state
  268.     eeprom_write_byte((uint8_t *)(oldpos), 0xff);    // erase old state
  269. }
  270.  
  271. void restore_state() {
  272.     uint8_t eep;
  273.     // find the config data
  274.     for(eepos=0; eepos<64; eepos++) {
  275.         eep = eeprom_read_byte((const uint8_t *)eepos);
  276.         if (eep != 0xff) break;
  277.     }
  278.     // unpack the config data
  279.     if (eepos < 64) {
  280.         mode_idx = eep & 0x0f;
  281.         modegroup = (eep >> 5) & 1;
  282.         memory = (eep >> 6) & 1;
  283.     }
  284.     // unnecessary, save_state handles wrap-around
  285.     // (and we don't really care about it skipping cell 0 once in a while)
  286.     //else eepos=0;
  287. }
  288.  
  289. inline void next_mode() {
  290.     mode_idx += 1;
  291.     if (mode_idx >= solid_modes) {
  292.         // Wrap around, skipping the hidden modes
  293.         // (note: this also applies when going "forward" from any hidden mode)
  294.         mode_idx = 0;
  295.     }
  296. }
  297.  
  298. #ifdef OFFTIM3
  299. inline void prev_mode() {
  300.     if (mode_idx == solid_modes) {
  301.         // If we hit the end of the hidden modes, go back to moon
  302.         mode_idx = 0;
  303.     } else if (mode_idx > 0) {
  304.         // Regular mode: is between 1 and TOTAL_MODES
  305.         mode_idx -= 1;
  306.     } else {
  307.         // Otherwise, wrap around (this allows entering hidden modes)
  308.         mode_idx = mode_cnt - 1;
  309.     }
  310. }
  311. #endif
  312.  
  313. #ifdef CONFIG_STARS
  314. inline void check_stars() {
  315.     // Configure options based on stars
  316.     // 0 being low for soldered, 1 for pulled-up for not soldered
  317. #if 0  // not implemented, STAR2_PIN is used for second PWM channel
  318.     // Moon
  319.     // enable moon mode?
  320.     if ((PINB & (1 << STAR2_PIN)) == 0) {
  321.         modes[mode_cnt++] = MODE_MOON;
  322.     }
  323. #endif
  324. #if 0  // Mode order not as important as mem/no-mem
  325.     // Mode order
  326.     if ((PINB & (1 << FET_PIN)) == 0) {
  327.         // High to Low
  328.         mode_dir = -1;
  329.     } else {
  330.         mode_dir = 1;
  331.     }
  332. #endif
  333.     // Memory
  334.     if ((PINB & (1 << FET_PIN)) == 0) {
  335.         memory = 1;  // solder to enable memory
  336.     } else {
  337.         memory = 0;  // unsolder to disable memory
  338.     }
  339. }
  340. #endif  // ifdef CONFIG_STARS
  341.  
  342. void count_modes() {
  343.     /*
  344.      * Determine how many solid and hidden modes we have.
  345.      * The modes_pwm array should have several values for regular modes
  346.      * then some values for hidden modes.
  347.      *
  348.      * (this matters because we have more than one set of modes to choose
  349.      *  from, so we need to count at runtime)
  350.      */
  351.     if (modegroup == 0) {
  352.         solid_modes = NUM_MODES1;
  353.         modesNx = modesNx1;
  354.         modes1x = modes1x1;
  355.         modes_pwm = modes_pwm1;
  356.     } else {
  357.         solid_modes = NUM_MODES2;
  358.         modesNx = modesNx2;
  359.         modes1x = modes1x2;
  360.         modes_pwm = modes_pwm2;
  361.     }
  362.     mode_cnt = solid_modes + NUM_HIDDEN;
  363. }
  364.  
  365. #ifdef VOLTAGE_MON
  366. inline void ADC_on() {
  367.     DIDR0 |= (1 << ADC_DIDR);                           // disable digital input on ADC pin to reduce power consumption
  368.     ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
  369.     ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
  370. }
  371. #else
  372. inline void ADC_off() {
  373.     ADCSRA &= ~(1<<7); //ADC off
  374. }
  375. #endif
  376.  
  377. void set_output(uint8_t pwm1, uint8_t pwm2) {
  378.     // Need PHASE to properly turn off the light
  379.     if ((pwm1==0) && (pwm2==0)) {
  380.         TCCR0A = PHASE;
  381.     }
  382. #ifdef TURBO
  383.     if (pwm1 == TURBO) {
  384.         PWM_LVL = 0;
  385.         ALT_PWM_LVL = 0;
  386.         DDRB |= (1 << FET_PIN);
  387.         PORTB |= (1 << FET_PIN);
  388.     } else {
  389.         PWM_LVL = pwm1;
  390.         ALT_PWM_LVL = pwm2;
  391.         PORTB &= ~(1 << FET_PIN);
  392.     }
  393. #else  
  394.     PWM_LVL = pwm1;
  395.     ALT_PWM_LVL = pwm2;
  396. #endif //ifdef TURBO
  397. }
  398.  
  399. void set_mode(uint8_t mode) {
  400.     TCCR0A = pgm_read_byte(modes_pwm + mode);
  401.     set_output(pgm_read_byte(modesNx + mode), pgm_read_byte(modes1x + mode));
  402.     /*
  403.     // Only set output for solid modes
  404.     uint8_t out = pgm_read_byte(modesNx + mode);
  405.     if ((out < 250) || (out == 255)) {
  406.         set_output(pgm_read_byte(modesNx + mode), pgm_read_byte(modes1x + mode));
  407.     }
  408.     */
  409. }
  410.  
  411. #ifdef VOLTAGE_MON
  412. uint8_t get_voltage() {
  413.     // Start conversion
  414.     ADCSRA |= (1 << ADSC);
  415.     // Wait for completion
  416.     while (ADCSRA & (1 << ADSC));
  417.     // See if voltage is lower than what we were looking for
  418.     return ADCH;
  419. }
  420. #endif
  421.  
  422. void blink(uint8_t val)
  423. {
  424.     for (; val>0; val--)
  425.     {
  426.         set_output(BLINK_BRIGHTNESS);
  427.         _delay_ms(100);
  428.         set_output(0,0);
  429.         _delay_ms(400);
  430.     }
  431. }
  432.  
  433. void toggle(uint8_t *var) {
  434.     // Used for extended config mode
  435.     // Changes the value of a config option, waits for the user to "save"
  436.     // by turning the light off, then changes the value back in case they
  437.     // didn't save.  Can be used repeatedly on different options, allowing
  438.     // the user to change and save only one at a time.
  439.     *var ^= 1;
  440.     save_state();
  441.     blink(2);
  442.     *var ^= 1;
  443.     save_state();
  444.     _delay_s();
  445. }
  446.  
  447. int main(void)
  448. {
  449.     uint8_t cap_val;
  450.  
  451.     // Read the off-time cap *first* to get the most accurate reading
  452.     // Start up ADC for capacitor pin
  453.     DIDR0 |= (1 << CAP_DIDR);                           // disable digital input on ADC pin to reduce power consumption
  454.     ADMUX  = (1 << REFS0) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3
  455.     ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
  456.  
  457.     // Wait for completion
  458.     while (ADCSRA & (1 << ADSC));
  459.     // Start again as datasheet says first result is unreliable
  460.     ADCSRA |= (1 << ADSC);
  461.     // Wait for completion
  462.     while (ADCSRA & (1 << ADSC));
  463.     cap_val = ADCH; // save this for later
  464.  
  465.     // Set PWM pin to output
  466.     DDRB |= (1 << PWM_PIN);     // enable main channel
  467.     DDRB |= (1 << ALT_PWM_PIN); // enable second channel
  468.  
  469.     // Set timer to do PWM for correct output pin and set prescaler timing
  470.     //TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
  471.     //TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  472.     TCCR0A = PHASE;
  473.     // Set timer to do PWM for correct output pin and set prescaler timing
  474.     TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  475.  
  476.     // Read config values and saved state
  477.     restore_state();
  478.     // Enable the current mode group
  479.     count_modes();
  480.  
  481.  
  482.     // memory decayed, reset it
  483.     // (should happen on med/long press instead
  484.     //  because mem decay is *much* slower when the OTC is charged
  485.     //  so let's not wait until it decays to reset it)
  486.     //if (fast_presses > 0x20) { fast_presses = 0; }
  487.  
  488.     if (cap_val > CAP_SHORT) {
  489.         // We don't care what the value is as long as it's over 15
  490.         fast_presses = (fast_presses+1) & 0x1f;
  491.         // Indicates they did a short press, go to the next mode
  492.         next_mode(); // Will handle wrap arounds
  493. #ifdef OFFTIM3
  494.     } else if (cap_val > CAP_MED) {
  495.         fast_presses = 0;
  496.         // User did a medium press, go back one mode
  497.         prev_mode(); // Will handle "negative" modes and wrap-arounds
  498. #endif
  499.     } else {
  500.         // Long press, keep the same mode
  501.         // ... or reset to the first mode
  502.         fast_presses = 0;
  503.         if (! memory) {
  504.             // Reset to the first mode
  505.             mode_idx = 0;
  506.         }
  507.     }
  508.     save_state();
  509.  
  510.     // Turn off ADC
  511.     //ADC_off();
  512.  
  513.     // Charge up the capacitor by setting CAP_PIN to output
  514.     DDRB  |= (1 << CAP_PIN);    // Output
  515.     PORTB |= (1 << CAP_PIN);    // High
  516.  
  517.     // Turn features on or off as needed
  518.     #ifdef VOLTAGE_MON
  519.     ADC_on();
  520.     #else
  521.     ADC_off();
  522.     #endif
  523.     //ACSR   |=  (1<<7); //AC off
  524.  
  525.     // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
  526.     // Will allow us to go idle between WDT interrupts
  527.     //set_sleep_mode(SLEEP_MODE_IDLE);  // not used due to blinky modes
  528.  
  529.     uint8_t output;
  530. #ifdef NON_WDT_TURBO
  531.     uint8_t ticks = 0;
  532. #endif
  533. #ifdef VOLTAGE_MON
  534.     uint8_t lowbatt_cnt = 0;
  535.     uint8_t i = 0;
  536.     uint8_t voltage;
  537.     // Make sure voltage reading is running for later
  538.     ADCSRA |= (1 << ADSC);
  539. #endif
  540.     while(1) {
  541.         output = pgm_read_byte(modesNx + mode_idx);
  542.         if (fast_presses > 0x0f) {  // Config mode
  543.             _delay_s();       // wait for user to stop fast-pressing button
  544.             fast_presses = 0; // exit this mode after one use
  545.             mode_idx = 0;
  546.  
  547.             // Longer/larger version of the config mode
  548.             // Toggle the mode group, blink, un-toggle, continue
  549.             toggle(&modegroup);
  550.  
  551.             // Toggle memory, blink, untoggle, exit
  552.             toggle(&memory);
  553.         }
  554.  
  555. #ifdef STROBE
  556.         else if (output == STROBE) {
  557.             // 10Hz tactical strobe
  558.             set_output(255,0);
  559.             _delay_ms(50);
  560.             set_output(0,0);
  561.             _delay_ms(50);
  562.         }
  563. #endif // ifdef STROBE
  564. #ifdef BIKING_STROBE
  565.         else if (output == BIKING_STROBE) {
  566.             // 2-level stutter beacon for biking and such
  567. #ifdef FULL_BIKING_STROBE
  568.             // normal version
  569.             for(i=0;i<4;i++) {
  570.                 set_output(255,0);
  571.                 _delay_ms(5);
  572.                 set_output(0,255);
  573.                 _delay_ms(65);
  574.             }
  575.             _delay_ms(720);
  576. #else
  577.             // small/minimal version
  578.             set_output(255,0);
  579.             _delay_ms(10);
  580.             set_output(0,255);
  581.             _delay_s();
  582. #endif
  583.         }
  584. #endif  // ifdef BIKING_STROBE
  585. #ifdef BATTCHECK
  586.         else if (output == BATTCHECK) {
  587.             voltage = get_voltage();
  588.             // figure out how many times to blink
  589.             for (i=0;
  590.                     voltage > pgm_read_byte(voltage_blinks + i);
  591.                     i ++) {}
  592.  
  593.             // blink zero to five times to show voltage
  594.             // (~0%, ~25%, ~50%, ~75%, ~100%, >100%)
  595.             blink(i);
  596.             // wait between readouts
  597.             _delay_s(); _delay_s();
  598.         }
  599. #endif // ifdef BATTCHECK
  600.         else {  // Regular non-hidden solid mode
  601.             set_mode(mode_idx);
  602.             // This part of the code will mostly replace the WDT tick code.
  603. #ifdef NON_WDT_TURBO
  604.             // Do some magic here to handle turbo step-down
  605.             //if (ticks < 255) ticks++;  // don't roll over
  606.             ticks ++;  // actually, we don't care about roll-over prevention
  607.             if ((ticks > TURBO_TIMEOUT)
  608.                     && (output == TURBO)) {
  609.                 mode_idx = solid_modes - 2; // step down to second-highest mode
  610.                 set_mode(mode_idx);
  611.                 save_state();
  612.             }
  613. #endif
  614.             // Otherwise, just sleep.
  615.             _delay_ms(500);
  616.  
  617.             // If we got this far, the user has stopped fast-pressing.
  618.             // So, don't enter config mode.
  619.             fast_presses = 0;
  620.         }
  621. #ifdef VOLTAGE_MON
  622. #if 1
  623.         if (ADCSRA & (1 << ADIF)) {  // if a voltage reading is ready
  624.             voltage = ADCH; // get_voltage();
  625.             // See if voltage is lower than what we were looking for
  626.             //if (voltage < ((mode_idx <= 1) ? ADC_CRIT : ADC_LOW)) {
  627.             if (voltage < ADC_LOW) {
  628.                 lowbatt_cnt ++;
  629.             } else {
  630.                 lowbatt_cnt = 0;
  631.             }
  632.             // See if it's been low for a while, and maybe step down
  633.             if (lowbatt_cnt >= 8) {
  634.                 // DEBUG: blink on step-down:
  635.                 //set_output(0,0);  _delay_ms(100);
  636.                 i = mode_idx; // save space by not accessing mode_idx more than necessary
  637.                 // properly track hidden vs normal modes
  638.                 if (i >= solid_modes) {
  639.                     // step down from blinky modes to medium
  640.                     i = 2;
  641.                 } else if (i > 0) {
  642.                     // step down from solid modes one at a time
  643.                     i -= 1;
  644.                 } else { // Already at the lowest mode
  645.                     i = 0;
  646.                     // Turn off the light
  647.                     set_output(0,0);
  648.                     // Power down as many components as possible
  649.                     set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  650.                     sleep_mode();
  651.                 }
  652.                 set_mode(i);
  653.                 mode_idx = i;
  654.                 save_state();
  655.                 lowbatt_cnt = 0;
  656.                 // Wait at least 2 seconds before lowering the level again
  657.                 _delay_ms(250);  // this will interrupt blinky modes
  658.             }
  659.  
  660.             // Make sure conversion is running for next time through
  661.             ADCSRA |= (1 << ADSC);
  662.         }
  663. #endif
  664. #endif  // ifdef VOLTAGE_MON
  665.         //sleep_mode();  // incompatible with blinky modes
  666.  
  667.         // If we got this far, the user has stopped fast-pressing.
  668.         // So, don't enter config mode.
  669.         //fast_presses = 0;  // doesn't interact well with strobe, too fast
  670.     }
  671.  
  672.     //return 0; // Standard Return Code
  673. }
RAW Paste Data
Top