From e96562e36df96ca755d527e479e597ae4e4e09e1 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 18 Aug 2017 18:12:17 -0600 Subject: Some early ideas for Round Table. Nothing close to compile-able yet. --- RoundTable/momentary.c | 68 +++++++++ RoundTable/round-table.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++ RoundTable/rt-ramping.h | 26 ++++ 3 files changed, 461 insertions(+) create mode 100644 RoundTable/momentary.c create mode 100644 RoundTable/round-table.c create mode 100644 RoundTable/rt-ramping.h (limited to 'RoundTable') diff --git a/RoundTable/momentary.c b/RoundTable/momentary.c new file mode 100644 index 0000000..120406e --- /dev/null +++ b/RoundTable/momentary.c @@ -0,0 +1,68 @@ +/* + * Momentary: Very simple example UI for RoundTable. + * Is intended to be the simplest possible RT e-switch UI. + * The light is in while the button is held; off otherwise. + * + * 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 . + */ + +#define RT_EMISAR_D4_LAYOUT +#include "round-table.c" + +volatile uint8_t brightness; + +void light_on() { + PWM1_LVL = brightness; + PWM2_LVL = 0; +} + +void light_off() { + PWM1_LVL = 0; + PWM2_LVL = 0; +} + +uint8_t momentary_state(EventPtr event, uint16_t arg) { + switch(event) { + + case EV_press: + brightness = 255; + light_on(); + // reset current event queue + empty_event_sequence(); + return 0; + + case EV_release: + light_off(); + // reset current event queue + empty_event_sequence(); + return 0; + + // LVP / low-voltage protection + case EV_voltage_low: + case EV_voltage_critical: + if (brightness > 0) brightness >>= 1; + else { + light_off(); + standby_mode(); + } + return 0; + } + return 1; // event not handled +} + +void setup() { + set_state(momentary_state); +} diff --git a/RoundTable/round-table.c b/RoundTable/round-table.c new file mode 100644 index 0000000..6cd1b10 --- /dev/null +++ b/RoundTable/round-table.c @@ -0,0 +1,367 @@ +#include "tk-attiny.h" + +// +typedef uint8_t (*EventCallbackPtr)(EventPtr event, uint16_t arg); +typedef uint8_t EventCallback(EventPtr event, uint16_t arg); +// FIXME: Why does a state need a number? Why not just a function pointer? +// (I don't think it actually needs a number...) +typedef struct State { + uint8_t num; + EventCallback event_callback; +} State; +typedef struct State* StatePtr; + +volatile StatePtr current_state; +#define EV_MAX_LEN 16 +volatile uint8_t current_event[EV_MAX_LEN]; + +volatile int16_t voltage; +#ifdef USE_THERMAL_REGULATION +volatile int16_t temperature; +#endif + +#define A_ENTER_STATE 1 +#define A_LEAVE_STATE 2 +#define A_TICK 3 +#define A_PRESS 4 +#define A_HOLD_START 5 +#define A_HOLD_TICK 6 +#define A_RELEASE 7 +#define A_RELEASE_TIMEOUT 8 +// TODO: add events for over/under-heat conditions (with parameter for severity) +#define A_OVERHEATING 9 +#define A_UNDERHEATING 10 +// TODO: add events for low voltage conditions +#define A_VOLTAGE_LOW 11 +#define A_VOLTAGE_CRITICAL 12 + +// TODO: maybe compare events by number instead of pointer? +// (number = index in event types array) +// (comparison would use full event content, but send off index to callbacks) +// (saves space by using uint8_t instead of a pointer) +// (also eliminates the need to duplicate single-entry events like for voltage or timer tick) + +// Event types +typedef PROGMEM const uint8_t Event; +typedef Event* EventPtr; +Event EV_enter_state[] = { + A_ENTER_STATE, + 0 } ; +Event EV_leave_state[] = { + A_LEAVE_STATE, + 0 } ; +Event EV_tick[] = { + A_TICK, + 0 } ; +Event EV_press[] = { + A_PRESS, + 0 }; +// shouldn't normally happen, but UI might reset event while button is down +// so a release with no recorded prior hold could be possible +Event EV_release[] = { + A_RELEASE, + 0 }; +Event EV_press_release[] = { + A_PRESS, + A_RELEASE, + 0 }; +#define EV_1click EV_press_release_timeout +Event EV_press_release_timeout[] = { + A_PRESS, + A_RELEASE, + A_RELEASE_TIMEOUT, + 0 }; +#define EV_hold EV_press_hold +// FIXME: Should holds use "start+tick" or just "tick" with a tick number? +// Or "start+tick" with a tick number? +Event EV_press_hold[] = { + A_PRESS, + A_HOLD_TIMEOUT, + 0 }; +Event EV_press_hold_release[] = { + A_PRESS, + A_HOLD_TIMEOUT, + A_RELEASE, + 0 }; +Event EV_press_release_press[] = { + A_PRESS, + A_RELEASE, + A_PRESS, + 0 }; +Event EV_press_release_press_release[] = { + A_PRESS, + A_RELEASE, + A_PRESS, + A_RELEASE, + 0 }; +#define EV_2clicks EV_press_release_press_release_timeout +Event EV_press_release_press_release_timeout[] = { + A_PRESS, + A_RELEASE, + A_PRESS, + A_RELEASE, + A_RELEASE_TIMEOUT, + 0 }; +// ... and so on + +// A list of event types for easy iteration +EventPtr event_sequences[] = { + EV_press, + EV_press_release, + EV_press_release_timeout, + EV_press_release_press, + EV_press_release_press_release, + EV_press_release_press_release_timeout, + // ... +}; + +// TODO: move this to a separate UI-specific file +/* +State states[] = { + +}; +*/ + +// TODO? add events to a queue when inside an interrupt +// instead of calling the event functions directly? +// (then empty the queue in main loop?) + +// TODO? new delay() functions which handle queue consumption? +// TODO? new interruptible delay() functions? + +//static uint8_t ticks_since_last_event = 0; // TODO: 16 bits? + +void WDT_tick() { + timer ++; + + //static uint8_t hold_ticks = 0; // TODO: 16 bits? + + // callback on each timer tick + emit(EV_tick, timer); + + // if time since last event exceeds timeout, + // append timeout to current event sequence, then + // send event to current state callback + // //hold_event(ticks) + // //emit(EV_press_hold, hold_ticks); + // emit_current(hold_ticks); + // or + // //release_timeout() + // //emit(EV_press_release_timeout, 0); + // emit_current(0); + + // add 4-step voltage / temperature thing? + // with averaged values, + // once every N ticks? +} + +void button_change_interrupt() { + // TODO: debounce a little + + //ticks_since_last_event = 0; // something happened + + // TODO: add event to current sequence + + // check if sequence matches any defined sequences + // if so, send event to current state callback + emit_current(0); +} + +uint8_t emit_current(uint16_t arg) { + uint8_t err = 1; + for (uint8_t i=0; i. + */ + +// TODO: ramp tables +// TODO: RAMP_SIZE / MAX_LVL +// TODO: actual_lvl +// TODO: target_lvl +// TODO: set_lvl +// TODO: set_lvl_smooth -- cgit v1.2.3