~toykeeper/flashlight-firmware/fsm

« back to all changes in this revision

Viewing changes to ToyKeeper/spaghetti-monster/anduril/aux-leds.c

  • Committer: Selene ToyKeeper
  • Date: 2023-11-04 15:09:10 UTC
  • mfrom: (483.1.175 anduril2)
  • Revision ID: bzr@toykeeper.net-20231104150910-ddd3afw4nhfvof2l
merged anduril2 branch -> fsm, with *years* of changes
(this also means this code is now Anduril 2 instead of Anduril 1)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
4
#pragma once
 
5
 
 
6
#include "aux-leds.h"
 
7
 
 
8
 
 
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)) {
 
16
    #else
 
17
    if (voltage < VOLTAGE_LOW) {
 
18
    #endif
 
19
        indicator_led(0);
 
20
    }
 
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));
 
26
    }
 
27
    #endif
 
28
    //#endif
 
29
    // normal steady output, 0/1/2 = off / low / high
 
30
    else if ((mode & 0b00001111) < 3) {
 
31
        indicator_led(mode);
 
32
    }
 
33
    // beacon-like blinky mode
 
34
    else {
 
35
        #ifdef USE_OLD_BLINKING_INDICATOR
 
36
 
 
37
        // basic blink, 1/8th duty cycle
 
38
        if (! (tick & 7)) {
 
39
            indicator_led(2);
 
40
        }
 
41
        else {
 
42
            indicator_led(0);
 
43
        }
 
44
 
 
45
        #else
 
46
 
 
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]);
 
51
 
 
52
        #endif  // ifdef USE_OLD_BLINKING_INDICATOR
 
53
    }
 
54
}
 
55
#endif
 
56
 
 
57
#if defined(USE_AUX_RGB_LEDS) && defined(TICK_DURING_STANDBY)
 
58
uint8_t voltage_to_rgb() {
 
59
    static const uint8_t levels[] = {
 
60
    // voltage, color
 
61
          0, 0, // black
 
62
        #ifdef DUAL_VOLTAGE_FLOOR
 
63
        // AA / NiMH voltages
 
64
          9, 1, // R
 
65
         10, 2, // R+G
 
66
         11, 3, //   G
 
67
         12, 4, //   G+B
 
68
         13, 5, //     B
 
69
         14, 6, // R + B
 
70
         15, 7, // R+G+B
 
71
         20, 0, // black
 
72
        #endif
 
73
        // li-ion voltages
 
74
         29, 1, // R
 
75
         33, 2, // R+G
 
76
         35, 3, //   G
 
77
         37, 4, //   G+B
 
78
         39, 5, //     B
 
79
         41, 6, // R + B
 
80
         44, 7, // R+G+B  // skip; looks too similar to G+B
 
81
        255, 7, // R+G+B
 
82
    };
 
83
    uint8_t volts = voltage;
 
84
    //if (volts < VOLTAGE_LOW) return 0;
 
85
 
 
86
    uint8_t i;
 
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);
 
90
}
 
91
 
 
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
 
98
 
 
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))) {
 
104
    #else
 
105
    if ((volts) && (volts < VOLTAGE_LOW)) {
 
106
    #endif
 
107
        rgb_led_set(0);
 
108
        #ifdef USE_BUTTON_LED
 
109
        button_led_set(0);
 
110
        #endif
 
111
        return;
 
112
    }
 
113
 
 
114
    uint8_t pattern = (mode>>4);  // off, low, high, blinking, ... more?
 
115
    uint8_t color = mode & 0x0f;
 
116
 
 
117
    // always preview in high mode
 
118
    if (setting_rgb_mode_now) { pattern = 2; }
 
119
 
 
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
 
126
        ) {
 
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));
 
129
        // voltage mode
 
130
        color = RGB_LED_NUM_COLORS - 1;
 
131
    }
 
132
    #endif
 
133
 
 
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);
 
138
    }
 
139
    else if (color == 7) {  // disco
 
140
        rainbow = (rainbow + 1 + pseudo_rand() % 5) % 6;
 
141
        actual_color = pgm_read_byte(colors + rainbow);
 
142
    }
 
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;
 
148
        }
 
149
        actual_color = pgm_read_byte(colors + rainbow);
 
150
    }
 
151
    else {  // voltage
 
152
        // show actual voltage while asleep...
 
153
        if (go_to_standby) {
 
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);
 
159
        }
 
160
        // ... but during preview, cycle colors quickly
 
161
        else {
 
162
            actual_color = pgm_read_byte(colors + (((arg>>1) % 3) << 1));
 
163
        }
 
164
    }
 
165
 
 
166
    // pick a brightness from the animation sequence
 
167
    if (pattern == 3) {
 
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];
 
173
    }
 
174
    uint8_t result;
 
175
    #ifdef USE_BUTTON_LED
 
176
    uint8_t button_led_result;
 
177
    #endif
 
178
    switch (pattern) {
 
179
        case 0:  // off
 
180
            result = 0;
 
181
            #ifdef USE_BUTTON_LED
 
182
            button_led_result = 0;
 
183
            #endif
 
184
            break;
 
185
        case 1:  // low
 
186
            result = actual_color;
 
187
            #ifdef USE_BUTTON_LED
 
188
            button_led_result = 1;
 
189
            #endif
 
190
            break;
 
191
        default:  // high
 
192
            result = (actual_color << 1);
 
193
            #ifdef USE_BUTTON_LED
 
194
            button_led_result = 2;
 
195
            #endif
 
196
            break;
 
197
    }
 
198
    rgb_led_set(result);
 
199
    #ifdef USE_BUTTON_LED
 
200
    button_led_set(button_led_result);
 
201
    #endif
 
202
}
 
203
 
 
204
void rgb_led_voltage_readout(uint8_t bright) {
 
205
    uint8_t color = voltage_to_rgb();
 
206
    if (bright) color = color << 1;
 
207
    rgb_led_set(color);
 
208
}
 
209
#endif
 
210