From 7cb4fe0944b839f28dfd96a88a772cd6a8b58019 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 2 Nov 2023 17:16:25 -0600 Subject: reorganized project files (part 1) (just moved files, didn't change the contents yet, and nothing will work without updating #includes and build scripts and stuff) --- ui/baton/baton.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ui/baton/baton.txt | 21 ++++++ 2 files changed, 209 insertions(+) create mode 100644 ui/baton/baton.c create mode 100644 ui/baton/baton.txt (limited to 'ui/baton') diff --git a/ui/baton/baton.c b/ui/baton/baton.c new file mode 100644 index 0000000..e672755 --- /dev/null +++ b/ui/baton/baton.c @@ -0,0 +1,188 @@ +/* + * Baton: Olight Baton-like UI for SpaghettiMonster. + * + * Copyright (C) 2017 Selene ToyKeeper + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "hwdef-Emisar_D4.h" +#define USE_LVP +#define USE_THERMAL_REGULATION +#define USE_DELAY_MS +#include "spaghetti-monster.h" + +// FSM states +uint8_t off_state(Event event, uint16_t arg); +uint8_t steady_state(Event event, uint16_t arg); +uint8_t lockout_state(Event event, uint16_t arg); + +// brightness control +uint8_t memorized_level = 1; +uint8_t actual_level = 0; +#ifdef USE_THERMAL_REGULATION +uint8_t target_level = 0; +#endif + +// moon + ../../bin/level_calc.py 2 6 7135 18 10 150 FET 1 10 1500 +uint8_t pwm1_levels[] = { 3, 18, 110, 255, 255, 255, 0, }; +uint8_t pwm2_levels[] = { 0, 0, 0, 9, 58, 138, 255, }; +#define MAX_LEVEL (sizeof(pwm1_levels)-1) + +// set LED brightness +void set_level(uint8_t lvl) { + actual_level = lvl; + PWM1_LVL = pwm1_levels[lvl]; + PWM2_LVL = pwm2_levels[lvl]; +} + +uint8_t off_state(Event event, uint16_t arg) { + // turn emitter off when entering state + if (event == EV_enter_state) { + go_to_standby = 1; // sleep while off (lower power use) + return EVENT_HANDLED; + } + // hold (initially): go to lowest level, but allow abort for regular click + else if (event == EV_click1_press) { + set_level(0); + return EVENT_HANDLED; + } + // hold (longer): go to lowest level + else if (event == EV_click1_hold) { + set_state(steady_state, 0); + return EVENT_HANDLED; + } + // 1 click (before timeout): go to memorized level, but allow abort for double click + else if (event == EV_click1_release) { + set_level(memorized_level); + return EVENT_HANDLED; + } + // 1 click: regular mode + else if (event == EV_1click) { + set_state(steady_state, memorized_level); + return EVENT_HANDLED; + } + // 2 clicks: highest mode + else if (event == EV_2clicks) { + set_state(steady_state, MAX_LEVEL); + return EVENT_HANDLED; + } + // 4 clicks: soft lockout + else if (event == EV_4clicks) { + set_state(lockout_state, 0); + return EVENT_HANDLED; + } + return EVENT_NOT_HANDLED; +} + +uint8_t steady_state(Event event, uint16_t arg) { + // turn LED on when we first enter the mode + if (event == EV_enter_state) { + // remember this level, unless it's moon or turbo + if ((arg > 0) && (arg < MAX_LEVEL)) memorized_level = arg; + // use the requested level even if not memorized + #ifdef USE_THERMAL_REGULATION + target_level = arg; + #endif + set_level(arg); + return EVENT_HANDLED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return EVENT_HANDLED; + } + // 2 clicks: go to/from highest level + else if (event == EV_2clicks) { + if (actual_level < MAX_LEVEL) { // go to turbo + memorized_level = actual_level; // in case we're on moon + #ifdef USE_THERMAL_REGULATION + target_level = MAX_LEVEL; + #endif + set_level(MAX_LEVEL); + } + else { // return from turbo + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + set_level(memorized_level); + } + return EVENT_HANDLED; + } + // hold: change brightness + else if (event == EV_click1_hold) { + if ((arg % HOLD_TIMEOUT) == 0) { + memorized_level = (actual_level+1) % (MAX_LEVEL+1); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + set_level(memorized_level); + } + return EVENT_HANDLED; + } + #ifdef USE_THERMAL_REGULATION + // overheating: drop by 1 level + else if (event == EV_temperature_high) { + if (actual_level > 1) { set_level(actual_level - 1); } + return EVENT_HANDLED; + } + // underheating: increase by 1 level if we're lower than the target + else if (event == EV_temperature_low) { + if (actual_level < target_level) { set_level(actual_level + 1); } + return EVENT_HANDLED; + } + #endif + return EVENT_NOT_HANDLED; +} + +uint8_t lockout_state(Event event, uint16_t arg) { + // stay asleep while locked + if (event == EV_tick) { + PWM1_LVL = 0; PWM2_LVL = 0; // make sure emitters are off + // sleep 1 second after user stops pressing buttons + if (arg > TICKS_PER_SECOND) { go_to_standby = 1; } + return EVENT_HANDLED; + } + // 4 clicks: exit, and turn on at "low" level + else if (event == EV_4clicks) { + set_state(steady_state, 1); + return EVENT_HANDLED; + } + return EVENT_NOT_HANDLED; +} + +void low_voltage() { + // step down by one level or turn off + if (actual_level > 0) { + set_level(actual_level - 1); + #ifdef USE_THERMAL_REGULATION + target_level = actual_level; // don't let low temperature override LVP + #endif + } + else { + set_state(off_state, 0); + } +} + +void setup() { + // blink when power is connected + set_level(MAX_LEVEL/2); + delay_ms(10); + set_level(0); + + push_state(off_state, 0); +} + +void loop() { +} diff --git a/ui/baton/baton.txt b/ui/baton/baton.txt new file mode 100644 index 0000000..2f0c22f --- /dev/null +++ b/ui/baton/baton.txt @@ -0,0 +1,21 @@ +This is a very simple clone of the Olight Baton interface. It is not +exact, but it has the basics. Mostly, it exists for the purposes of +demonstrating how to create interfaces in FSM. + +While off: + + - 1 click: Turn on (at memorized level). + - Hold: Turn on (at moon level). + - 2 clicks: Turn on (at highest level). + - 4 clicks: Soft lockout mode. + +While on: + + - 1 click: Turn off. + - Hold: Change the brightness. Goes up in steps, then wraps around. + - 2 clicks: Go to/from highest level. + +While locked: + + - 4 clicks: Exit lockout mode. + -- cgit v1.2.3