diff options
Diffstat (limited to '')
| -rw-r--r-- | hw/hank/emisar-d3aa/simple.h | 34 | ||||
| -rw-r--r-- | ui/simple/simple.c | 210 |
2 files changed, 244 insertions, 0 deletions
diff --git a/hw/hank/emisar-d3aa/simple.h b/hw/hank/emisar-d3aa/simple.h new file mode 100644 index 0000000..8ef36d4 --- /dev/null +++ b/hw/hank/emisar-d3aa/simple.h @@ -0,0 +1,34 @@ +/* + * simple.h: Emisar D3AA config for Simple UI + * Copyright (C) 2023, 2026 git@apexo.de, thefreeman, Selene ToyKeeper + * SPDX-License-Identifier: GPL-3.0-or-later + */ +#pragma once + +#include "hank/emisar-d3aa/anduril.h" + +#define USE_RAMPING + +#define USE_SET_LEVEL_GRADUALLY + +/* + * avr32dd20.c compiles mcu_wdt_standby() unconditionally and references this. + * so we need to define it, even if we don't use TICK_DURING_STANDBY. + */ +#ifndef STANDBY_TICK_SPEED +#define STANDBY_TICK_SPEED 3 +#endif + +#define USE_DELAY_ZERO + +#define USE_LVP + +#define USE_THERMAL_REGULATION +#define DEFAULT_THERM_CEIL 45 + +/* + * EEPROM stores 1 byte: + * - brightness index + */ +#define USE_EEPROM +#define EEPROM_BYTES 1 diff --git a/ui/simple/simple.c b/ui/simple/simple.c new file mode 100644 index 0000000..885f8a8 --- /dev/null +++ b/ui/simple/simple.c @@ -0,0 +1,210 @@ +/* + * simple.c: Yet another UI for the Emisar D3AA + * Copyright (C) 2026 git@apexo.de + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +/* + * States: + * - Off : all lights off, standby + * - Aux : aux RGB shows color-coded battery voltage + * - On : main LED on (one of 4 different brightness levels), + * aux RGB shows color-coded battery voltage + * + * Transitions: + * - Off + Click -> Aux + * - Aux + Click -> On + * - Aux + 5s -> Off + * - On + Click -> Aux + * - On + Hold -> cycle brightness levels, store on release + */ + +#include "arch/mcu.h" + +#include incfile(CFG_H) + +#ifdef HWDEF_H +#include incfile(HWDEF_H) +#endif + +#include "fsm/spaghetti-monster.h" + +#ifdef HWDEF_C +#include incfile(HWDEF_C) +#endif + +#define NUM_LEVELS 4 +#define CEIL SIMPLE_UI_CEIL + +static const uint8_t brightness_levels[NUM_LEVELS] = { + 1, + 1 * CEIL / 10, + 3 * CEIL / 10, + CEIL, +}; + +#define HOLD_TICKS_PER_LEVEL 47 // cycle time ca 0.75s (47/62 Hz) +#define AUX_TIMEOUT_TICKS 310 // ca. 5s + +uint8_t off_state(Event event, uint16_t arg); +uint8_t aux_state(Event event, uint16_t arg); +uint8_t on_state(Event event, uint16_t arg); + +uint8_t current_level_idx = 0; +uint8_t current_level = 0; +uint8_t thermal_limit = SIMPLE_UI_CEIL; + +static const uint8_t voltage_levels[] = { + 0, 0, // black + #ifdef DUAL_VOLTAGE_FLOOR + // NiMH + 9*dV, 0x01, // R + 10*dV, 0x05, // R+G + 11*dV, 0x04, // G + 12*dV, 0x14, // G+B + 13*dV, 0x10, // B + 14*dV, 0x11, // R + B + 16*dV, 0x15, // R+G+B + 20*dV, 0, // black + #endif + // li-ion + 29*dV, 0x01, // R + 33*dV, 0x05, // R+G + 35*dV, 0x04, // G + 37*dV, 0x14, // G+B + 39*dV, 0x10, // B + 41*dV, 0x11, // R + B + 44*dV, 0x15, // R+G+B + 255, 0x15, // R+G+B +}; + +static uint8_t voltage_color(void) { + uint8_t v = voltage; + if (v == 0) return 0; + v -= 1; + uint8_t i; + for (i = 0; v > voltage_levels[i]; i += 2) {} + return voltage_levels[i - 1]; +} + +void set_level_therm(uint8_t value, uint16_t thermal_headroom, uint16_t thermal_overshoot) { + if (current_level == thermal_limit && thermal_headroom > 0) { + if (thermal_headroom >= CEIL - thermal_limit) { + thermal_limit = CEIL; + } else { + thermal_limit += thermal_headroom; + } + } + + if (thermal_overshoot > 0) { + if (thermal_overshoot >= current_level) { + thermal_limit = 1; + } else { + thermal_limit = current_level - thermal_overshoot; + } + } + + current_level = value <= thermal_limit ? value : thermal_limit; + set_level(current_level); +} + +uint8_t off_state(Event event, uint16_t arg) { + if (event == EV_enter_state) { + set_level(0); + rgb_led_set(0); + button_led_set(0); + go_to_standby = 1; + return EVENT_HANDLED; + } + + if (event == EV_1click) { + set_state(aux_state, 0); + return EVENT_HANDLED; + } + + return EVENT_NOT_HANDLED; +} + +uint8_t aux_state(Event event, uint16_t arg) { + if (event == EV_enter_state) { + set_level(0); + rgb_led_set(voltage_color() << 1); + button_led_set(1); + return EVENT_HANDLED; + } + + if (event == EV_1click) { + set_state(on_state, 0); + return EVENT_HANDLED; + } + + if (event == EV_tick) { + if (arg >= AUX_TIMEOUT_TICKS) { + set_state(off_state, 0); + } + return EVENT_HANDLED; + } + + return EVENT_NOT_HANDLED; +} + +uint8_t on_state(Event event, uint16_t arg) { + if (event == EV_enter_state) { + set_level_therm(brightness_levels[current_level_idx], 0, 0); + rgb_led_set(voltage_color() << 1); + button_led_set(2); + return EVENT_HANDLED; + } + + if (event == EV_tick) { + if ((arg & 63) == 0) { + rgb_led_set(voltage_color() << 1); + } + return EVENT_HANDLED; + } + + if (event == EV_temperature_high) { + set_level_therm(brightness_levels[current_level_idx], 0, arg); + return EVENT_HANDLED; + } + + if (event == EV_temperature_low) { + set_level_therm(brightness_levels[current_level_idx], arg, 0); + return EVENT_HANDLED; + } + + if (event == EV_1click) { + set_state(aux_state, 0); + return EVENT_HANDLED; + } + + if (event == EV_click1_hold) { + if (arg % HOLD_TICKS_PER_LEVEL == 0) { + current_level_idx = (current_level_idx + 1) % NUM_LEVELS; + set_level_therm(brightness_levels[current_level_idx], 0, 0); + } + return EVENT_HANDLED; + } + + if (event == EV_click1_hold_release) { + eeprom[0] = current_level_idx; + save_eeprom(); + return EVENT_HANDLED; + } + + return EVENT_NOT_HANDLED; +} + +void low_voltage(void) { + set_state(off_state, 0); +} + +void setup(void) { + if (load_eeprom()) { + if (eeprom[0] < NUM_LEVELS) + current_level_idx = eeprom[0]; + } + push_state(off_state, 0); +} + +void loop(void) { } |
