Advertisement
gchart

Babka V2 fast_presses redundancy test

Mar 11th, 2017
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.84 KB | None | 0 0
  1. /*
  2.  
  3.  * ====================================================================
  4.  *  "Babka" firmware by gChart (Gabriel Hart)
  5.  *  Last updated: 2016-11-10
  6.  *
  7.  *  This firmware is based on "Biscotti" by ToyKeeper and is intended
  8.  *  for single-channel attiny13a drivers such as Qlite and nanjc105d.
  9.  * ====================================================================
  10.  *
  11.  * 12 or more fast presses > Configuration mode
  12.  *
  13.  * Short tap on first config option goes to Group Mode selection
  14.  * Short tap on second config option goes to Turbo Mode selection
  15.  *
  16.  * If hidden modes are enabled, perform a triple-click to enter the hidden modes.
  17.  * Tap once to advance through the hidden modes.  Once you advance past the last
  18.  * hidden mode, you will return to the first non-hidden mode.
  19.  *
  20.  * Battery Check will blink out between 0 and 8 blinks.  0 blinks means your battery
  21.  * is dead.  1 blink is 1-12% battery remaining.  2 blinks is 13-24% remaining...
  22.  * 8 blinks is 88-100% remaining.  Essentially, the number of blinks is how many
  23.  * eighths of the battery remain: 1/8, 2/8, 3/8... 8/8.  After blinking, it will
  24.  * pause for two seconds and then repeat itself.
  25.  *
  26.  * Configuration Menu
  27.  *   1: Mode Groups:
  28.  *     1: 100
  29.  *     2: 20, 100
  30.  *     3: 5, 35, 100
  31.  *     4: 1, 10, 35, 100
  32.  *     5: 100, 35, 10, 1
  33.  *     6: 100, 35, 5
  34.  *     7: 100, 20
  35.  *     8: 100, Strobe
  36.  *     9: 100, 20, Strobe
  37.  *     10: 100, 35, 5, Strobe
  38.  *     11: 5, 35, 100, Strobe
  39.  *     12: 20, 100, Strobe
  40.  *   2: Memory Toggle
  41.  *   3: Hidden Strobe Modes Toggle (Strobe, Beacon, SOS)
  42.  *   4: Hidden Batt Check Toggle (if strobes are enabled, Batt Check appears at the end of them)
  43.  *   5: Turbo Timer Toggle (turbo steps down to 50%)
  44.  *   6: Reset to default configuration
  45.  *  
  46.  * ====================================================================
  47.  *
  48.  * "Biscotti" firmware (attiny13a version of "Bistro")
  49.  * This code runs on a single-channel driver with attiny13a MCU.
  50.  * It is intended specifically for nanjg 105d drivers from Convoy.
  51.  *
  52.  * Copyright (C) 2015 Selene Scriven
  53.  *
  54.  * This program is free software: you can redistribute it and/or modify
  55.  * it under the terms of the GNU General Public License as published by
  56.  * the Free Software Foundation, either version 3 of the License, or
  57.  * (at your option) any later version.
  58.  *
  59.  * This program is distributed in the hope that it will be useful,
  60.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  61.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  62.  * GNU General Public License for more details.
  63.  *
  64.  * You should have received a copy of the GNU General Public License
  65.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  66.  *
  67.  *
  68.  * ATTINY13 Diagram
  69.  *         ----
  70.  *       -|1  8|- VCC
  71.  *       -|2  7|- Voltage ADC
  72.  *       -|3  6|-
  73.  *   GND -|4  5|- PWM (Nx7135)
  74.  *         ----
  75.  *
  76.  * FUSES
  77.  *    I use these fuse settings on attiny13
  78.  *    Low:  0x75
  79.  *    High: 0xff
  80.  *
  81.  * CALIBRATION
  82.  *
  83.  *   To find out what values to use, flash the driver with battcheck.hex
  84.  *   and hook the light up to each voltage you need a value for.  This is
  85.  *   much more reliable than attempting to calculate the values from a
  86.  *   theoretical formula.
  87.  *
  88.  *   Same for off-time capacitor values.  Measure, don't guess.
  89.  */
  90. // Choose your MCU here, or in the build script
  91. #define ATTINY 13
  92. #define NANJG_LAYOUT  // specify an I/O pin layout
  93. // Also, assign I/O pins in this file:
  94. #include "../tk-attiny.h"
  95.  
  96. //#define DEFAULTS 0b00010010  // 3 modes with memory, no blinkies, no battcheck, no turbo timer
  97. #define DEFAULTS 0b10010010  // 3 modes with memory, no blinkies, no battcheck, with turbo timer
  98.  
  99. #define FAST  0xA3        // fast PWM both channels
  100. #define PHASE 0xA1        // phase-correct PWM both channels
  101. #define VOLTAGE_MON      // Comment out to disable LVP
  102. #define USE_BATTCHECK      // Enable battery check mode
  103. //#define BATTCHECK_4bars    // up to 4 blinks
  104. #define BATTCHECK_8bars  // up to 8 blinks
  105.  
  106. #define RAMP_SIZE  6
  107. #define RAMP_PWM   1, 13, 26, 51, 89, 255  // 1, 5, 10, 20, 35, 100%
  108.  
  109. #define BLINK_BRIGHTNESS    3 // output to use for blinks on battery check (and other modes)
  110. #define BLINK_SPEED      750 // ms per normal-speed blink
  111.  
  112. #define TURBO_MINUTES 5 // when turbo timer is enabled, how long before stepping down
  113. #define TICKS_PER_MINUTE 120 // used for Turbo Timer timing
  114. #define TURBO_LOWER 128  // the PWM level to use when stepping down
  115.  
  116. #define TURBO    RAMP_SIZE  // Convenience code for turbo mode
  117.  
  118. #define FIRST_SELECT_MODE 252
  119. #define GROUP_SELECT_MODE 252
  120.  
  121. // These need to be in sequential order, no gaps.
  122. // Make sure to update FIRST_BLINKY and LAST_BLINKY as needed.
  123. // BATT_CHECK should be the last blinky, otherwise the non-blinky
  124. // mode groups will pick up any blinkies after BATT_CHECK
  125. #define FIRST_BLINKY 240
  126. #define STROBE  240
  127. #define BEACON 241
  128. #define SOS 242
  129. #define BATT_CHECK 243
  130. #define LAST_BLINKY 243
  131.  
  132. // Calibrate voltage and OTC in this file:
  133. #include "../tk-calibration.h"
  134.  
  135. //#define VARIABLE_LENGTH // this seems to cost around 14 bytes, perhaps a bit more
  136.  
  137. /*
  138.  * =========================================================================
  139.  */
  140.  
  141. // Ignore a spurious warning, we did the cast on purpose
  142. #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
  143.  
  144. #include <avr/pgmspace.h>
  145. #include <avr/interrupt.h>
  146. #include <avr/eeprom.h>
  147. #include <avr/sleep.h>
  148. #include <string.h>
  149.  
  150. #define OWN_DELAY          // Don't use stock delay functions.
  151. #define USE_DELAY_S      // Also use _delay_s(), not just _delay_ms()
  152. #include "../tk-delay.h"
  153.  
  154. #include "../tk-voltage.h"
  155.  
  156. uint8_t modegroup = 0; // which mode group (set above in #defines)
  157. uint8_t mode_idx = 0;     // current or last-used mode number
  158. uint8_t eepos = 0;
  159.  
  160. #define fp4
  161. // (needs to be remembered while off, but only for up to half a second)
  162. uint8_t fast_presses  __attribute__ ((section (".noinit")));
  163. // use a second one for reduncancy
  164. #ifdef fp2
  165. uint8_t fast_presses2 __attribute__ ((section (".noinit")));
  166. #endif
  167. #ifdef fp3
  168. uint8_t fast_presses2 __attribute__ ((section (".noinit")));
  169. uint8_t fast_presses3 __attribute__ ((section (".noinit")));
  170. #endif
  171. #ifdef fp4
  172. uint8_t fast_presses2 __attribute__ ((section (".noinit")));
  173. uint8_t fast_presses3 __attribute__ ((section (".noinit")));
  174. uint8_t fast_presses4 __attribute__ ((section (".noinit")));
  175. #endif
  176.  
  177. // number of regular modes in current mode group
  178. uint8_t solid_modes;
  179.  
  180. // Each group *must* be 4 values long, can define up to 15 groups
  181. #ifdef VARIABLE_LENGTH
  182. #define NUM_MODEGROUPS 11
  183. PROGMEM const uint8_t modegroups[] = {
  184.     6, 0,
  185.     4, 6, 0,
  186.     2, 5, 6, 0,
  187.     1, 3, 5, 6, 0,
  188.     6, 5, 3, 1, 0,
  189.     6, 5, 2, 0,
  190.     6, 4, 0,
  191.     6, STROBE, 0,
  192.     6, 4, STROBE, 0,
  193.   6, 5, 2, STROBE, 0,
  194.     2, 5, 6, STROBE, 0,
  195.     //4, 6, STROBE, 0,
  196. };
  197. uint8_t modes[] = { 0,0,0,0 };  // make sure this is long enough...
  198. #else
  199. #define GROUP_SIZE 4
  200. #define NUM_MODEGROUPS 11
  201. PROGMEM const uint8_t modegroups[] = {
  202.     6, 0, 0, 0,
  203.     4, 6, 0, 0,
  204.     2, 5, 6, 0,
  205.     1, 3, 5, 6,
  206.     6, 5, 3, 1,
  207.     6, 5, 2, 0,
  208.     6, 4, 0, 0,
  209.     6, STROBE, 0, 0,
  210.     6, 4, STROBE, 0,
  211.   6, 5, 2, STROBE,
  212.     2, 5, 6, STROBE,
  213.     //4, 6, STROBE, 0,
  214. };
  215. uint8_t modes[] = { 0,0,0,0, };  // make sure this is long enough...
  216. #endif
  217.  
  218. // Modes (gets set when the light starts up based on saved config values)
  219. PROGMEM const uint8_t ramp_PWM[]  = { RAMP_PWM };
  220.  
  221. inline uint8_t modegroup_number()     { return (modegroup     ) & 0b00001111; }
  222. inline uint8_t memory_is_enabled()    { return (modegroup >> 4) & 0b00000001; }
  223. inline uint8_t blinkies_are_enabled() { return (modegroup >> 5) & 0b00000001; }
  224. inline uint8_t battcheck_is_enabled() { return (modegroup >> 6) & 0b00000001; }
  225. inline uint8_t ttimer_is_enabled()    { return (modegroup >> 7) & 0b00000001; }
  226.  
  227. void save_mode() {  // save the current mode index (with wear leveling)
  228.     eeprom_write_byte((uint8_t *)(eepos), 0xff);     // erase old state
  229.     eepos = (eepos+1) & ((EEPSIZE/2)-1);  // wear leveling, use next cell
  230.     eeprom_write_byte((uint8_t *)(eepos), mode_idx);  // save current state
  231. }
  232.  
  233. #define OPT_modegroup (EEPSIZE-1)
  234. void save_state() {  // central method for writing complete state
  235.     save_mode();
  236.     eeprom_write_byte((uint8_t *)OPT_modegroup, modegroup);
  237. }
  238.  
  239. inline void reset_state() {
  240.     mode_idx = 0;
  241.     modegroup = DEFAULTS;  // 3 brightness levels with memory
  242.     save_state();
  243. }
  244.  
  245. inline void restore_state() {
  246.     uint8_t eep;
  247.     uint8_t first = 1;
  248.     uint8_t i;
  249.     // find the mode index data
  250.     for(i=0; i<(EEPSIZE-6); i++) {
  251.         eep = eeprom_read_byte((const uint8_t *)i);
  252.         if (eep != 0xff) {
  253.             eepos = i;
  254.             mode_idx = eep;
  255.             first = 0;
  256.             break;
  257.         }
  258.     }
  259.     // if no mode_idx was found, assume this is the first boot
  260.     if (first) {
  261.         reset_state();
  262.         return;
  263.     }
  264.  
  265.     // load other config values
  266.     modegroup = eeprom_read_byte((uint8_t *)OPT_modegroup);
  267. }
  268.  
  269. inline void next_mode() {
  270.     mode_idx++;
  271.    
  272.     if(fast_presses == 3 && mode_idx <= solid_modes) {  // triple-tap from a solid mode
  273.         if( blinkies_are_enabled() ) mode_idx = FIRST_BLINKY; // if blinkies enabled, go to first one
  274.         else if( battcheck_is_enabled() ) mode_idx = BATT_CHECK; // else if battcheck enabled, go to it
  275.     }
  276.    
  277.     // if we hit the end of the solid modes or the blinkies (or battcheck if disabled), go to first solid mode
  278.     if ( (mode_idx == solid_modes) || (mode_idx > LAST_BLINKY) || (mode_idx == BATT_CHECK && !battcheck_is_enabled() )) {
  279.         mode_idx = 0;
  280.     }
  281.    
  282. }
  283.  
  284. #ifdef VARIABLE_LENGTH
  285. inline void count_modes() {
  286.     uint8_t i = modegroup_number();
  287.     uint8_t *dest = modes;
  288.     const uint8_t *src = modegroups;
  289.    
  290.     // Find the start of our modegroup
  291.     while(i) {
  292.         while(pgm_read_byte(src++)){}
  293.             i--;
  294.     }
  295.    
  296.     // Now count modes and store them in modes[]
  297.     i=0;
  298.     while(pgm_read_byte(src+i)){
  299.         *dest++ = pgm_read_byte(src+i);
  300.         i++;
  301.   }
  302.     solid_modes = i;
  303. }
  304. #else
  305. inline void count_modes() {
  306.     uint8_t *dest = modes;
  307.     //const uint8_t *src = modegroups + ( modegroup_number() <<3); // use this for groups of 8
  308.     const uint8_t *src = modegroups + ( modegroup_number() <<2); // use this for groups of 4
  309.     uint8_t i;
  310.     for(i=0; (i<GROUP_SIZE) && pgm_read_byte(src); i++, src++ ) {
  311.         *dest++ = pgm_read_byte(src);
  312.     }
  313.     solid_modes = i;
  314.  
  315. }
  316. #endif
  317.  
  318. inline void set_output(uint8_t pwm1) {
  319.     PWM_LVL = pwm1;
  320. }
  321.  
  322. void set_level(uint8_t level) {
  323.     if (level <= 2) {
  324.         TCCR0A = PHASE;
  325.         if (level == 1) { TCCR0B = 0x02; }
  326.     }
  327.     set_output(pgm_read_byte(ramp_PWM  + level - 1));
  328. }
  329.  
  330. void blink(uint8_t val, uint16_t speed)
  331. {
  332.     for (; val>0; val--)
  333.     {
  334.         set_level(BLINK_BRIGHTNESS);
  335.         _delay_ms(speed);
  336.         set_output(0);
  337.         _delay_ms(speed);
  338.         _delay_ms(speed);
  339.     }
  340. }
  341.  
  342. void toggle(uint8_t *var, uint8_t value, uint8_t num) {
  343.     blink(num, BLINK_SPEED/4);  // indicate which option number this is
  344.     uint8_t temp = *var;
  345.     *var = value;
  346.     save_state();
  347.     blink(32, 500/32); // "buzz" for a while to indicate the active toggle window
  348.    
  349.     // if the user didn't click, reset the value and return
  350.     *var = temp;
  351.     save_state();
  352.     _delay_s();
  353. }
  354.  
  355. #ifdef fp1
  356. inline uint8_t we_did_a_fast_press() {
  357.     return (fast_presses <= 15);
  358. }
  359. inline void increment_fast_presses() {
  360.     if(fast_presses < 15) fast_presses++;
  361. }
  362. void reset_fast_presses() {
  363.     fast_presses  = 0;
  364. }
  365. #endif
  366. #ifdef fp2
  367. inline uint8_t we_did_a_fast_press() {
  368.     return (fast_presses == fast_presses2) && (fast_presses <= 15);
  369. }
  370. inline void increment_fast_presses() {
  371.     if(fast_presses < 15) fast_presses++;
  372.     fast_presses2 = fast_presses;
  373. }
  374. void reset_fast_presses() {
  375.     fast_presses  = 0;
  376.     fast_presses2 = 0;
  377. }
  378. #endif
  379. #ifdef fp3
  380. inline uint8_t we_did_a_fast_press() {
  381.     return (fast_presses == fast_presses2) && (fast_presses2 == fast_presses3) && (fast_presses <= 15);
  382. }
  383. inline void increment_fast_presses() {
  384.     if(fast_presses < 15) fast_presses++;
  385.     fast_presses2 = fast_presses;
  386.     fast_presses3 = fast_presses;
  387. }
  388. void reset_fast_presses() {
  389.     fast_presses  = 0;
  390.     fast_presses2 = 0;
  391.     fast_presses3 = 0;
  392. }
  393. #endif
  394. #ifdef fp4
  395. inline uint8_t we_did_a_fast_press() {
  396.     return (fast_presses == fast_presses2) && (fast_presses2 == fast_presses3) && (fast_presses3 == fast_presses4) && (fast_presses <= 15);
  397. }
  398. inline void increment_fast_presses() {
  399.     if(fast_presses < 15) fast_presses++;
  400.     fast_presses2 = fast_presses;
  401.     fast_presses3 = fast_presses;
  402.     fast_presses4 = fast_presses;
  403. }
  404. void reset_fast_presses() {
  405.     fast_presses  = 0;
  406.     fast_presses2 = 0;
  407.     fast_presses3 = 0;
  408.     fast_presses4 = 0;
  409. }
  410. #endif
  411.  
  412. int main(void)
  413. {
  414.  
  415.     DDRB |= (1 << PWM_PIN);  // Set PWM pin to output, enable main channel
  416.     TCCR0A = FAST; // Set timer to do PWM for correct output pin and set prescaler timing
  417.     TCCR0B = 0x01; // Set timer to do PWM for correct output pin and set prescaler timing
  418.  
  419.     restore_state(); // Read config values and saved state
  420.  
  421.     count_modes(); // Enable the current mode group
  422.      // check button press time, unless we're in a selection mode (mode group or turbo timer selection)
  423.     if (mode_idx < FIRST_SELECT_MODE) {
  424.         if ( we_did_a_fast_press() ) { // sram hasn't decayed yet, must have been a short press
  425.             increment_fast_presses();
  426.             next_mode(); // Will handle wrap arounds
  427.         } else { // Long press, keep the same mode
  428.             reset_fast_presses();
  429.             if( !memory_is_enabled() ) {mode_idx = 0;}  // if memory is turned off, set mode_idx to 0
  430.         }
  431.     }
  432.     save_mode();
  433.  
  434.     // Turn features on or off as needed
  435.     #ifdef VOLTAGE_MON
  436.     ADC_on();
  437.     #else
  438.     ADC_off();
  439.     #endif
  440.  
  441.     uint8_t output;
  442.     uint8_t i = 0;
  443.     uint16_t ticks = 0;
  444.    
  445. #ifdef VOLTAGE_MON
  446.     uint8_t lowbatt_cnt = 0;
  447.     uint8_t voltage;
  448.     ADCSRA |= (1 << ADSC); // Make sure voltage reading is running for later
  449. #endif
  450.  
  451.     if(mode_idx > solid_modes) { output = mode_idx; }  // special modes, override output
  452.     else { output = modes[mode_idx]; }
  453.    
  454.     while(1) {
  455.         if (fast_presses >= 12) {  // Config mode if 12 or more fast presses
  456.             _delay_s();    // wait for user to stop fast-pressing button
  457.             reset_fast_presses(); // exit this mode after one use
  458.  
  459.             toggle(&mode_idx, GROUP_SELECT_MODE, 1); // Enter the mode group selection mode?
  460.             toggle(&modegroup, (modegroup ^ 0b00010000), 2); // memory
  461.             toggle(&modegroup, (modegroup ^ 0b00100000), 3); // hidden blinkies
  462.             toggle(&modegroup, (modegroup ^ 0b01000000), 4); // hidden battcheck
  463.             toggle(&modegroup, (modegroup ^ 0b10000000), 5); // turbo timer
  464.             toggle(&modegroup, DEFAULTS, 6); // reset to defaults
  465.         }
  466.         else if (output == STROBE) { // 10Hz tactical strobe
  467.             for(i=0;i<8;i++) {
  468.                 set_level(RAMP_SIZE);
  469.                 _delay_ms(33);
  470.                 set_output(0);
  471.                 _delay_ms(67);
  472.             }
  473.         }
  474.         else if (output == BEACON) {
  475.             set_level(RAMP_SIZE);
  476.             _delay_ms(10);
  477.             set_output(0);
  478.             _delay_s(); _delay_s();
  479.         }
  480.         else if (output == SOS) {  // dot = 1 unit, dash = 3 units, space betwen parts of a letter = 1 unit, space between letters = 3 units
  481.             #define SOS_SPEED 200  // these speeds aren't perfect, but they'll work for the [never] times they'll actually get used
  482.             blink(3, SOS_SPEED); // 200 on, 400 off, 200 on, 400 off, 200 on, 400 off
  483.             _delay_ms(SOS_SPEED);  // wait for 200
  484.             blink(3, SOS_SPEED*5/2);  // 500 on, 1000 off, 500 on, 1000 off, 500 on, 1000 off (techically too long on that last off beat, but oh well)
  485.             blink(3, SOS_SPEED);  // 200 on, 400 off, 200 on, 400 off, 200 on, 400 off
  486.             _delay_s(); _delay_s();
  487.         }
  488.         else if (output == BATT_CHECK) {
  489.              blink(battcheck(), BLINK_SPEED/4);
  490.              _delay_s(); _delay_s();
  491.         }
  492.         else if (output == GROUP_SELECT_MODE) {
  493.             mode_idx = 0; // exit this mode after one use
  494.  
  495.             for(i=0; i<NUM_MODEGROUPS; i++) {
  496.                 toggle(&modegroup, ((modegroup & 0b11110000) | i), i+1);
  497.             }
  498.             _delay_s();
  499.         }
  500.         else {
  501.             set_level(output);
  502.  
  503.             ticks ++; // count ticks for turbo timer
  504.             if ((output == TURBO) && ( ttimer_is_enabled() ) && (ticks > (TURBO_MINUTES * TICKS_PER_MINUTE))) set_output(TURBO_LOWER);
  505.  
  506.             _delay_ms(500);  // Otherwise, just sleep.
  507.  
  508.         }
  509.         reset_fast_presses();
  510. #ifdef VOLTAGE_MON
  511.         if (ADCSRA & (1 << ADIF)) {  // if a voltage reading is ready
  512.             voltage = ADCH;  // get the waiting value
  513.    
  514.             if (voltage < ADC_LOW) { // See if voltage is lower than what we were looking for
  515.                 lowbatt_cnt ++;
  516.             } else {
  517.                 lowbatt_cnt = 0;
  518.             }
  519.            
  520.             if (lowbatt_cnt >= 8) {  // See if it's been low for a while, and maybe step down
  521.                 //set_output(0);  _delay_ms(100); // blink on step-down:
  522.  
  523.                 if (output > RAMP_SIZE) {  // blinky modes
  524.                     output = RAMP_SIZE / 2; // step down from blinky modes to medium
  525.                 } else if (output > 1) {  // regular solid mode
  526.                     output = output - 1; // step down from solid modes somewhat gradually
  527.                 } else { // Already at the lowest mode
  528.                     set_output(0); // Turn off the light
  529.                     set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Power down as many components as possible
  530.                     sleep_mode();
  531.                 }
  532.                 set_level(output);
  533.                 lowbatt_cnt = 0;
  534.                 _delay_s(); // Wait before lowering the level again
  535.             }
  536.  
  537.             ADCSRA |= (1 << ADSC); // Make sure conversion is running for next time through
  538.         }
  539. #endif  // ifdef VOLTAGE_MON
  540.     }
  541. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement