diff options
Diffstat (limited to 'firmware/e300/battery/led.c')
-rw-r--r-- | firmware/e300/battery/led.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/firmware/e300/battery/led.c b/firmware/e300/battery/led.c new file mode 100644 index 000000000..0e7e992ba --- /dev/null +++ b/firmware/e300/battery/led.c @@ -0,0 +1,153 @@ +#include "led.h" +#include "io.h" + +/* hardware io */ +static io_pin_t POWER_LED = IO_PC(7); +static io_pin_t CHARGE = IO_PD(1); + +enum led_color { + LED_C_RED, + LED_C_GREEN, + LED_C_OFF +}; + +static enum led_color led_color; + +static inline void led_set(enum led_color color) +{ + switch (color) { + case LED_C_RED: + io_clear_pin(POWER_LED); + io_set_pin(CHARGE); + break; + case LED_C_GREEN: + io_clear_pin(CHARGE); + io_set_pin(POWER_LED); + break; + case LED_C_OFF: + default: + io_clear_pin(CHARGE); + io_clear_pin(POWER_LED); + break; + } + led_color = color; +} + +/* blinken lights */ +static uint8_t blink_cnt; +static uint8_t orange_cnt; + +/* state for sequence */ +static enum led_state state; +static enum led_state state_next; +static uint8_t seq_max; +static uint8_t seq_cnt; +static const uint8_t T_SEQ = 196; +static const uint8_t T_ON = 98; + +static bool counting; + +void led_set_blink_seq(uint8_t n_blinks, enum led_state color) +{ + if (color == state) + return; + + blink_cnt = 0; + seq_cnt = 0; + seq_max = 2 * n_blinks + 1; + + state = color; +} + +void led_set_solid(enum led_state color) +{ + if (state != LED_BLINK_RED_FAST) + state = color; + state_next = color; +} + +void led_set_blink(enum led_state color) +{ + if (state != LED_BLINK_RED_FAST) + state = color; + state_next = color; +} + +irqreturn_t led_wdt_handler(void) +{ + counting = false; + switch (state) { + case LED_BLINK_GREEN_SLOW: + if (blink_cnt < T_ON) + led_set(LED_C_GREEN); + else + led_set(LED_C_OFF); + blink_cnt += 1; + break; + + case LED_BLINK_GREEN_FAST: + if (blink_cnt < T_ON) + led_set(LED_C_GREEN); + else + led_set(LED_C_OFF); + blink_cnt += 4; + break; + + case LED_BLINK_RED_FAST: + counting = true; + if (!seq_cnt) { + led_set(LED_C_OFF); + } else if (blink_cnt < T_ON) + led_set(seq_cnt % 2 ? LED_C_OFF : LED_C_RED); + else + led_set(LED_C_OFF); + blink_cnt += 16; + break; + + case LED_BLINK_ORANGE: + if (blink_cnt < T_ON) + led_set(orange_cnt % 2 ? LED_C_GREEN : LED_C_RED); + else + led_set(LED_C_OFF); + + orange_cnt++; + blink_cnt += 4; + break; + + case LED_ORANGE: + led_set(orange_cnt % 2 ? LED_C_GREEN : LED_C_RED); + orange_cnt++; + blink_cnt+=4; + break; + + case LED_GREEN: + led_set(LED_C_GREEN); + break; + + case LED_RED: + led_set(LED_C_RED); + break; + + case LED_OFF: + default: + led_set(LED_C_OFF); + break; + } + + if (blink_cnt >= T_SEQ - 1) { + blink_cnt = 0; + if (counting) { + if (seq_cnt < seq_max) { + seq_cnt++; + } else { + state = state_next; + seq_cnt = 0; + counting = false; + } + } else { + state = state_next; + } + } + + return IRQ_HANDLED; +} |