aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/e300/battery/led.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/e300/battery/led.c')
-rw-r--r--firmware/e300/battery/led.c153
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;
+}