diff options
| -rw-r--r-- | spaghetti-monster/anduril/anduril.c | 271 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/aux-leds.c | 174 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/aux-leds.h | 83 |
3 files changed, 290 insertions, 238 deletions
diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 6ef7954..b479552 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -2,7 +2,7 @@ * Anduril: Narsil-inspired UI for SpaghettiMonster. * (Anduril is Aragorn's sword, the blade Narsil reforged) * - * Copyright (C) 2017-2019 Selene ToyKeeper + * Copyright (C) 2017-2020 Selene ToyKeeper * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,34 +18,36 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -// Usually a program would be structured like this... -// - Library headers -// - App headers -// - App code -// -// ... in each source file. -// ... and each library and part of the program would be linked together. -// -// But this doesn't follow that pattern, because it's using the -// -fwhole-program -// flag to reduce the compiled size. It lets us fit more features -// in a tiny MCU chip's ROM. -// -// So the structure is like this instead... -// - App-level configuration headers -// - Default config -// - Per build target config -// - Library-level configuration headers -// - Library code (FSM itself) -// - App headers -// - App code (all of it, inline) -// -// Don't do this in regular programs. It's weird and kind of gross. -// But in this case it gives us a bunch of much-needed space, so... woot. -// -// Also, there are a ton of compile-time flags because it needs to build -// a bunch of different versions and each one needs to be trimmed as small -// as possible. These are mostly "USE" flags. +/* + * Usually a program would be structured like this... + * - Library headers + * - App headers + * - App code + * + * ... in each source file. + * ... and each library and part of the program would be linked together. + * + * But this doesn't follow that pattern, because it's using the + * -fwhole-program + * flag to reduce the compiled size. It lets us fit more features + * in a tiny MCU chip's ROM. + * + * So the structure is like this instead... + * - App-level configuration headers + * - Default config + * - Per build target config + * - Library-level configuration headers + * - Library code (FSM itself) + * - App headers + * - App code (all of it, inline) + * + * Don't do this in regular programs. It's weird and kind of gross. + * But in this case it gives us a bunch of much-needed space, so... woot. + * + * Also, there are a ton of compile-time flags because it needs to build + * a bunch of different versions and each one needs to be trimmed as small + * as possible. These are mostly "USE" flags. + */ /********* User-configurable options *********/ #include "config-default.h" @@ -92,6 +94,7 @@ #include "ramp-mode.h" #include "load-save-config.h" #include "config-mode.h" +#include "aux-leds.h" #include "misc.h" #ifdef USE_VERSION_CHECK @@ -137,68 +140,6 @@ #include "sos-mode.h" #endif -// FSM states - -#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) -void indicator_blink(uint8_t arg); -#endif -#if defined(USE_AUX_RGB_LEDS) && defined(TICK_DURING_STANDBY) -uint8_t setting_rgb_mode_now = 0; -void rgb_led_update(uint8_t mode, uint8_t arg); -void rgb_led_voltage_readout(uint8_t bright); -/* - * 0: R - * 1: RG - * 2: G - * 3: GB - * 4: B - * 5: R B - * 6: RGB - * 7: rainbow - * 8: voltage - */ -const PROGMEM uint8_t rgb_led_colors[] = { - 0b00000001, // 0: red - 0b00000101, // 1: yellow - 0b00000100, // 2: green - 0b00010100, // 3: cyan - 0b00010000, // 4: blue - 0b00010001, // 5: purple - 0b00010101, // 6: white -}; -#define RGB_LED_NUM_COLORS 10 -#define RGB_LED_NUM_PATTERNS 4 -#ifndef RGB_LED_OFF_DEFAULT -//#define RGB_LED_OFF_DEFAULT 0x18 // low, voltage -#define RGB_LED_OFF_DEFAULT 0x17 // low, rainbow -#endif -#ifndef RGB_LED_LOCKOUT_DEFAULT -#define RGB_LED_LOCKOUT_DEFAULT 0x37 // blinking, rainbow -#endif -#ifndef RGB_RAINBOW_SPEED -#define RGB_RAINBOW_SPEED 0x0f // change color every 16 frames -#endif -uint8_t rgb_led_off_mode = RGB_LED_OFF_DEFAULT; -uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; -#endif - - -#ifdef USE_INDICATOR_LED - // bits 2-3 control lockout mode - // bits 0-1 control "off" mode - // modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) - #ifdef INDICATOR_LED_DEFAULT_MODE - uint8_t indicator_led_mode = INDICATOR_LED_DEFAULT_MODE; - #else - #ifdef USE_INDICATOR_LED_WHILE_RAMPING - //uint8_t indicator_led_mode = (1<<2) + 2; - uint8_t indicator_led_mode = (2<<2) + 1; - #else - uint8_t indicator_led_mode = (3<<2) + 1; - #endif - #endif -#endif - /********* Include all the app logic source files *********/ // (is a bit weird to do things this way, @@ -208,6 +149,7 @@ uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; #include "ramp-mode.c" #include "load-save-config.c" #include "config-mode.c" +#include "aux-leds.c" #include "misc.c" #ifdef USE_VERSION_CHECK @@ -255,153 +197,6 @@ uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; #endif -#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) -// beacon-like mode for the indicator LED -void indicator_blink(uint8_t arg) { - // turn off aux LEDs when battery is empty - if (voltage < VOLTAGE_LOW) { indicator_led(0); return; } - - #ifdef USE_FANCIER_BLINKING_INDICATOR - - // fancy blink, set off/low/high levels here: - uint8_t seq[] = {0, 1, 2, 1, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0}; - indicator_led(seq[arg & 15]); - - #else // basic blink, 1/8th duty cycle - - if (! (arg & 7)) { - indicator_led(2); - } - else { - indicator_led(0); - } - - #endif -} -#endif - -#if defined(USE_AUX_RGB_LEDS) && defined(TICK_DURING_STANDBY) -uint8_t voltage_to_rgb() { - uint8_t levels[] = { - // voltage, color - 0, 0, // 0, R - 33, 1, // 1, R+G - 35, 2, // 2, G - 37, 3, // 3, G+B - 39, 4, // 4, B - 41, 5, // 5, R + B - 44, 6, // 6, R+G+B // skip; looks too similar to G+B - 255, 6, // 7, R+G+B - }; - uint8_t volts = voltage; - if (volts < 29) return 0; - - uint8_t i; - for (i = 0; volts >= levels[i]; i += 2) {} - uint8_t color_num = levels[(i - 2) + 1]; - return pgm_read_byte(rgb_led_colors + color_num); -} - -// do fancy stuff with the RGB aux LEDs -// mode: 0bPPPPCCCC where PPPP is the pattern and CCCC is the color -// arg: time slice number -void rgb_led_update(uint8_t mode, uint8_t arg) { - static uint8_t rainbow = 0; // track state of rainbow mode - static uint8_t frame = 0; // track state of animation mode - - // turn off aux LEDs when battery is empty - // (but if voltage==0, that means we just booted and don't know yet) - uint8_t volts = voltage; // save a few bytes by caching volatile value - if ((volts) && (volts < VOLTAGE_LOW)) { - rgb_led_set(0); - #ifdef USE_BUTTON_LED - button_led_set(0); - #endif - return; - } - - uint8_t pattern = (mode>>4); // off, low, high, blinking, ... more? - uint8_t color = mode & 0x0f; - - // preview in blinking mode is awkward... use high instead - if ((! go_to_standby) && (pattern > 2)) { pattern = 2; } - - - const uint8_t *colors = rgb_led_colors; - uint8_t actual_color = 0; - if (color < 7) { // normal color - actual_color = pgm_read_byte(colors + color); - } - else if (color == 7) { // rainbow - uint8_t speed = 0x03; // awake speed - if (go_to_standby) speed = RGB_RAINBOW_SPEED; // asleep speed - if (0 == (arg & speed)) { - rainbow = (rainbow + 1) % 6; - } - actual_color = pgm_read_byte(colors + rainbow); - } - else { // voltage - // show actual voltage while asleep... - if (go_to_standby) { - actual_color = voltage_to_rgb(); - // choose a color based on battery voltage - //if (volts >= 38) actual_color = pgm_read_byte(colors + 4); - //else if (volts >= 33) actual_color = pgm_read_byte(colors + 2); - //else actual_color = pgm_read_byte(colors + 0); - } - // ... but during preview, cycle colors quickly - else { - actual_color = pgm_read_byte(colors + (((arg>>1) % 3) << 1)); - } - } - - // pick a brightness from the animation sequence - if (pattern == 3) { - // uses an odd length to avoid lining up with rainbow loop - uint8_t animation[] = {2, 1, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 1}; - frame = (frame + 1) % sizeof(animation); - pattern = animation[frame]; - } - uint8_t result; - #ifdef USE_BUTTON_LED - uint8_t button_led_result; - #endif - switch (pattern) { - case 0: // off - result = 0; - #ifdef USE_BUTTON_LED - button_led_result = 0; - #endif - break; - case 1: // low - result = actual_color; - #ifdef USE_BUTTON_LED - button_led_result = 1; - #endif - break; - default: // high - result = (actual_color << 1); - #ifdef USE_BUTTON_LED - button_led_result = 2; - #endif - break; - } - rgb_led_set(result); - #ifdef USE_BUTTON_LED - button_led_set(button_led_result); - #endif -} - -void rgb_led_voltage_readout(uint8_t bright) { - uint8_t color = voltage_to_rgb(); - if (bright) color = color << 1; - rgb_led_set(color); -} -#endif - - void low_voltage() { StatePtr state = current_state; diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c new file mode 100644 index 0000000..d783797 --- /dev/null +++ b/spaghetti-monster/anduril/aux-leds.c @@ -0,0 +1,174 @@ +/* + * aux-leds.c: Aux LED functions for Anduril. + * + * Copyright (C) 2017 Selene ToyKeeper + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef AUX_LEDS_C +#define AUX_LEDS_C + +#include "aux-leds.h" + + +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +// beacon-like mode for the indicator LED +void indicator_blink(uint8_t arg) { + // turn off aux LEDs when battery is empty + if (voltage < VOLTAGE_LOW) { indicator_led(0); return; } + + #ifdef USE_FANCIER_BLINKING_INDICATOR + + // fancy blink, set off/low/high levels here: + uint8_t seq[] = {0, 1, 2, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0}; + indicator_led(seq[arg & 15]); + + #else // basic blink, 1/8th duty cycle + + if (! (arg & 7)) { + indicator_led(2); + } + else { + indicator_led(0); + } + + #endif +} +#endif + +#if defined(USE_AUX_RGB_LEDS) && defined(TICK_DURING_STANDBY) +uint8_t voltage_to_rgb() { + uint8_t levels[] = { + // voltage, color + 0, 0, // 0, R + 33, 1, // 1, R+G + 35, 2, // 2, G + 37, 3, // 3, G+B + 39, 4, // 4, B + 41, 5, // 5, R + B + 44, 6, // 6, R+G+B // skip; looks too similar to G+B + 255, 6, // 7, R+G+B + }; + uint8_t volts = voltage; + if (volts < 29) return 0; + + uint8_t i; + for (i = 0; volts >= levels[i]; i += 2) {} + uint8_t color_num = levels[(i - 2) + 1]; + return pgm_read_byte(rgb_led_colors + color_num); +} + +// do fancy stuff with the RGB aux LEDs +// mode: 0bPPPPCCCC where PPPP is the pattern and CCCC is the color +// arg: time slice number +void rgb_led_update(uint8_t mode, uint8_t arg) { + static uint8_t rainbow = 0; // track state of rainbow mode + static uint8_t frame = 0; // track state of animation mode + + // turn off aux LEDs when battery is empty + // (but if voltage==0, that means we just booted and don't know yet) + uint8_t volts = voltage; // save a few bytes by caching volatile value + if ((volts) && (volts < VOLTAGE_LOW)) { + rgb_led_set(0); + #ifdef USE_BUTTON_LED + button_led_set(0); + #endif + return; + } + + uint8_t pattern = (mode>>4); // off, low, high, blinking, ... more? + uint8_t color = mode & 0x0f; + + // preview in blinking mode is awkward... use high instead + if ((! go_to_standby) && (pattern > 2)) { pattern = 2; } + + + const uint8_t *colors = rgb_led_colors; + uint8_t actual_color = 0; + if (color < 7) { // normal color + actual_color = pgm_read_byte(colors + color); + } + else if (color == 7) { // rainbow + uint8_t speed = 0x03; // awake speed + if (go_to_standby) speed = RGB_RAINBOW_SPEED; // asleep speed + if (0 == (arg & speed)) { + rainbow = (rainbow + 1) % 6; + } + actual_color = pgm_read_byte(colors + rainbow); + } + else { // voltage + // show actual voltage while asleep... + if (go_to_standby) { + actual_color = voltage_to_rgb(); + // choose a color based on battery voltage + //if (volts >= 38) actual_color = pgm_read_byte(colors + 4); + //else if (volts >= 33) actual_color = pgm_read_byte(colors + 2); + //else actual_color = pgm_read_byte(colors + 0); + } + // ... but during preview, cycle colors quickly + else { + actual_color = pgm_read_byte(colors + (((arg>>1) % 3) << 1)); + } + } + + // pick a brightness from the animation sequence + if (pattern == 3) { + // uses an odd length to avoid lining up with rainbow loop + uint8_t animation[] = {2, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + frame = (frame + 1) % sizeof(animation); + pattern = animation[frame]; + } + uint8_t result; + #ifdef USE_BUTTON_LED + uint8_t button_led_result; + #endif + switch (pattern) { + case 0: // off + result = 0; + #ifdef USE_BUTTON_LED + button_led_result = 0; + #endif + break; + case 1: // low + result = actual_color; + #ifdef USE_BUTTON_LED + button_led_result = 1; + #endif + break; + default: // high + result = (actual_color << 1); + #ifdef USE_BUTTON_LED + button_led_result = 2; + #endif + break; + } + rgb_led_set(result); + #ifdef USE_BUTTON_LED + button_led_set(button_led_result); + #endif +} + +void rgb_led_voltage_readout(uint8_t bright) { + uint8_t color = voltage_to_rgb(); + if (bright) color = color << 1; + rgb_led_set(color); +} +#endif + + +#endif + diff --git a/spaghetti-monster/anduril/aux-leds.h b/spaghetti-monster/anduril/aux-leds.h new file mode 100644 index 0000000..cb3975e --- /dev/null +++ b/spaghetti-monster/anduril/aux-leds.h @@ -0,0 +1,83 @@ +/* + * aux-leds.h: Aux LED functions for Anduril. + * + * Copyright (C) 2017 Selene ToyKeeper + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef AUX_LEDS_H +#define AUX_LEDS_H + +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +void indicator_blink(uint8_t arg); +#endif +#if defined(USE_AUX_RGB_LEDS) && defined(TICK_DURING_STANDBY) +uint8_t setting_rgb_mode_now = 0; +void rgb_led_update(uint8_t mode, uint8_t arg); +void rgb_led_voltage_readout(uint8_t bright); +/* + * 0: R + * 1: RG + * 2: G + * 3: GB + * 4: B + * 5: R B + * 6: RGB + * 7: rainbow + * 8: voltage + */ +const PROGMEM uint8_t rgb_led_colors[] = { + 0b00000001, // 0: red + 0b00000101, // 1: yellow + 0b00000100, // 2: green + 0b00010100, // 3: cyan + 0b00010000, // 4: blue + 0b00010001, // 5: purple + 0b00010101, // 6: white +}; +#define RGB_LED_NUM_COLORS 10 +#define RGB_LED_NUM_PATTERNS 4 +#ifndef RGB_LED_OFF_DEFAULT +#define RGB_LED_OFF_DEFAULT 0x18 // low, voltage +//#define RGB_LED_OFF_DEFAULT 0x17 // low, rainbow +#endif +#ifndef RGB_LED_LOCKOUT_DEFAULT +#define RGB_LED_LOCKOUT_DEFAULT 0x37 // blinking, rainbow +#endif +#ifndef RGB_RAINBOW_SPEED +#define RGB_RAINBOW_SPEED 0x0f // change color every 16 frames +#endif +uint8_t rgb_led_off_mode = RGB_LED_OFF_DEFAULT; +uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; +#endif + +#ifdef USE_INDICATOR_LED + // bits 2-3 control lockout mode + // bits 0-1 control "off" mode + // modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) + #ifdef INDICATOR_LED_DEFAULT_MODE + uint8_t indicator_led_mode = INDICATOR_LED_DEFAULT_MODE; + #else + #ifdef USE_INDICATOR_LED_WHILE_RAMPING + //uint8_t indicator_led_mode = (1<<2) + 2; + uint8_t indicator_led_mode = (2<<2) + 1; + #else + uint8_t indicator_led_mode = (3<<2) + 1; + #endif + #endif +#endif + + +#endif |
