aboutsummaryrefslogtreecommitdiff
path: root/spaghetti-monster/anduril/aux-leds.c
diff options
context:
space:
mode:
Diffstat (limited to 'spaghetti-monster/anduril/aux-leds.c')
-rw-r--r--spaghetti-monster/anduril/aux-leds.c174
1 files changed, 174 insertions, 0 deletions
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
+