Guest User

PD68 TripleDown FW - Test Version

a guest
Jan 17th, 2016
383
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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×