1
// aux-leds.c: Aux LED functions for Anduril.
2
// Copyright (C) 2017-2023 Selene ToyKeeper
3
// SPDX-License-Identifier: GPL-3.0-or-later
9
#if defined(USE_INDICATOR_LED)
10
void indicator_led_update(uint8_t mode, uint8_t tick) {
11
//uint8_t volts = voltage; // save a few bytes by caching volatile value
12
// turn off when battery is too low
13
#ifdef DUAL_VOLTAGE_FLOOR
14
if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR))
15
|| (voltage < DUAL_VOLTAGE_LOW_LOW)) {
17
if (voltage < VOLTAGE_LOW) {
21
//#ifdef USE_INDICATOR_LOW_BAT_WARNING
22
#ifndef DUAL_VOLTAGE_FLOOR // this isn't set up for dual-voltage lights like the Sofirn SP10 Pro
23
// fast blink a warning when battery is low but not critical
24
else if (voltage < VOLTAGE_RED) {
25
indicator_led(mode & (((tick & 0b0010)>>1) - 3));
29
// normal steady output, 0/1/2 = off / low / high
30
else if ((mode & 0b00001111) < 3) {
33
// beacon-like blinky mode
35
#ifdef USE_OLD_BLINKING_INDICATOR
37
// basic blink, 1/8th duty cycle
47
// fancy blink, set off/low/high levels here:
48
static const uint8_t seq[] = {0, 1, 2, 1, 0, 0, 0, 0,
49
0, 0, 1, 0, 0, 0, 0, 0};
50
indicator_led(seq[tick & 15]);
52
#endif // ifdef USE_OLD_BLINKING_INDICATOR
57
#if defined(USE_AUX_RGB_LEDS) && defined(TICK_DURING_STANDBY)
58
uint8_t voltage_to_rgb() {
59
static const uint8_t levels[] = {
62
#ifdef DUAL_VOLTAGE_FLOOR
80
44, 7, // R+G+B // skip; looks too similar to G+B
83
uint8_t volts = voltage;
84
//if (volts < VOLTAGE_LOW) return 0;
87
for (i = 0; volts >= levels[i]; i += 2) {}
88
uint8_t color_num = levels[(i - 2) + 1];
89
return pgm_read_byte(rgb_led_colors + color_num);
92
// do fancy stuff with the RGB aux LEDs
93
// mode: 0bPPPPCCCC where PPPP is the pattern and CCCC is the color
94
// arg: time slice number
95
void rgb_led_update(uint8_t mode, uint16_t arg) {
96
static uint8_t rainbow = 0; // track state of rainbow mode
97
static uint8_t frame = 0; // track state of animation mode
99
// turn off aux LEDs when battery is empty
100
// (but if voltage==0, that means we just booted and don't know yet)
101
uint8_t volts = voltage; // save a few bytes by caching volatile value
102
#ifdef DUAL_VOLTAGE_FLOOR
103
if ((volts) && (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW))) {
105
if ((volts) && (volts < VOLTAGE_LOW)) {
108
#ifdef USE_BUTTON_LED
114
uint8_t pattern = (mode>>4); // off, low, high, blinking, ... more?
115
uint8_t color = mode & 0x0f;
117
// always preview in high mode
118
if (setting_rgb_mode_now) { pattern = 2; }
120
#ifdef USE_POST_OFF_VOLTAGE
121
// use voltage high mode for a few seconds after initial poweroff
122
// (but not after changing aux LED settings and other similar actions)
123
else if ((arg < (cfg.post_off_voltage * SLEEP_TICKS_PER_SECOND))
124
&& (ticks_since_on < (cfg.post_off_voltage * SLEEP_TICKS_PER_SECOND))
125
&& (ticks_since_on > 0) // don't blink red on 1st frame
127
// use high mode if regular aux level is high or prev level was high
128
pattern = 1 + ((2 == pattern) | (prev_level >= POST_OFF_VOLTAGE_BRIGHTNESS));
130
color = RGB_LED_NUM_COLORS - 1;
134
const uint8_t *colors = rgb_led_colors + 1;
135
uint8_t actual_color = 0;
136
if (color < 7) { // normal color
137
actual_color = pgm_read_byte(colors + color);
139
else if (color == 7) { // disco
140
rainbow = (rainbow + 1 + pseudo_rand() % 5) % 6;
141
actual_color = pgm_read_byte(colors + rainbow);
143
else if (color == 8) { // rainbow
144
uint8_t speed = 0x03; // awake speed
145
if (go_to_standby) speed = RGB_RAINBOW_SPEED; // asleep speed
146
if (0 == (arg & speed)) {
147
rainbow = (rainbow + 1) % 6;
149
actual_color = pgm_read_byte(colors + rainbow);
152
// show actual voltage while asleep...
154
actual_color = voltage_to_rgb();
155
// choose a color based on battery voltage
156
//if (volts >= 38) actual_color = pgm_read_byte(colors + 4);
157
//else if (volts >= 33) actual_color = pgm_read_byte(colors + 2);
158
//else actual_color = pgm_read_byte(colors + 0);
160
// ... but during preview, cycle colors quickly
162
actual_color = pgm_read_byte(colors + (((arg>>1) % 3) << 1));
166
// pick a brightness from the animation sequence
168
// uses an odd length to avoid lining up with rainbow loop
169
static const uint8_t animation[] = {2, 1, 0, 0, 0, 0, 0, 0, 0,
170
1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
171
frame = (frame + 1) % sizeof(animation);
172
pattern = animation[frame];
175
#ifdef USE_BUTTON_LED
176
uint8_t button_led_result;
181
#ifdef USE_BUTTON_LED
182
button_led_result = 0;
186
result = actual_color;
187
#ifdef USE_BUTTON_LED
188
button_led_result = 1;
192
result = (actual_color << 1);
193
#ifdef USE_BUTTON_LED
194
button_led_result = 2;
199
#ifdef USE_BUTTON_LED
200
button_led_set(button_led_result);
204
void rgb_led_voltage_readout(uint8_t bright) {
205
uint8_t color = voltage_to_rgb();
206
if (bright) color = color << 1;