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 ++++
tk-attiny.h | 82 ++++++++++-
4 files changed, 542 insertions(+), 1 deletion(-)
create mode 100644 RoundTable/momentary.c
create mode 100644 RoundTable/round-table.c
create mode 100644 RoundTable/rt-ramping.h
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
diff --git a/tk-attiny.h b/tk-attiny.h
index 72ed2f0..ebd997f 100644
--- a/tk-attiny.h
+++ b/tk-attiny.h
@@ -4,7 +4,7 @@
* Attiny portability header.
* This helps abstract away the differences between various attiny MCUs.
*
- * Copyright (C) 2015 Selene ToyKeeper
+ * 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
@@ -31,12 +31,25 @@
#define EEPSIZE 64
#define V_REF REFS0
#define BOGOMIPS 950
+ #define ADMUX_VCC 0b00001100
#elif (ATTINY == 25)
// TODO: Use 6.4 MHz instead of 8 MHz?
#define F_CPU 8000000UL
#define EEPSIZE 128
#define V_REF REFS1
#define BOGOMIPS (F_CPU/4000)
+ #define ADMUX_VCC 0b00001100
+ #define ADMUX_THERM 0b10001111
+#elif (ATTINY == 85)
+ // TODO: Use 6.4 MHz instead of 8 MHz?
+ #define F_CPU 8000000UL
+ #define EEPSIZE 512
+ #define V_REF REFS1
+ #define BOGOMIPS (F_CPU/4000)
+ // (1 << V_REF) | (0 << ADLAR) | (VCC_CHANNEL)
+ #define ADMUX_VCC 0b00001100
+ // (1 << V_REF) | (0 << ADLAR) | (THERM_CHANNEL)
+ #define ADMUX_THERM 0b10001111
#else
Hey, you need to define ATTINY.
#endif
@@ -145,6 +158,73 @@
#endif // NANJG_LAYOUT
+
+#ifdef RT_EMISAR_D4_LAYOUT
+/*
+ * ----
+ * Reset -|1 8|- VCC
+ * eswitch -|2 7|-
+ * AUX LED -|3 6|- PWM (FET)
+ * GND -|4 5|- PWM (1x7135)
+ * ----
+ */
+
+#define AUXLED_PIN PB4 // pin 3
+
+#define SWITCH_PIN PB3 // pin 2, OTC
+#define CAP_CHANNEL 0x03 // MUX 03 corresponds with PB3 (Star 4)
+#define CAP_DIDR ADC3D // Digital input disable bit corresponding with PB3
+
+#define PWM2_PIN PB1 // pin 6, FET PWM
+#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1
+#define PWM1_PIN PB0 // pin 5, 1x7135 PWM
+#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0
+
+#define VOLTAGE_PIN PB2 // pin 7, voltage ADC
+#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2
+#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2
+#define ADC_PRSCL 0x06 // clk/64
+
+//#define TEMP_DIDR ADC4D
+#define TEMP_CHANNEL 0b00001111
+
+#define FAST 0xA3 // fast PWM both channels
+#define PHASE 0xA1 // phase-correct PWM both channels
+
+#endif
+
+
+#ifdef RT_TKSABER_LAYOUT
+/*
+ * ----
+ * Reset -|1 8|- VCC
+ * PWM 4 (A) -|2 7|- e-switch
+ * PWM 3 (B) -|3 6|- PWM 2 (G)
+ * GND -|4 5|- PWM 1 (R)
+ * ----
+ */
+
+#define PWM1_PIN PB0 // pin 5
+#define PWM1_LVL OCR0A
+#define PWM2_PIN PB1 // pin 6
+#define PWM2_LVL OCR0B
+#define PWM3_PIN PB4 // pin 3
+#define PWM3_LVL OCR1B
+#define PWM4_PIN PB3 // pin 2
+#define PWM4_LVL OCR1A // FIXME: does this work?
+
+#define SWITCH_PIN PB2 // pin 7
+
+#define ADC_PRSCL 0x07 // clk/128 (no need to be super fast)
+// FIXME: What is the DIDR for pin 8?
+//#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2
+
+#define FAST 0xA3 // fast PWM both channels
+#define PHASE 0xA1 // phase-correct PWM both channels
+
+#endif // TKSABER_LAYOUT
+
+
#ifndef PWM_LVL
Hey, you need to define an I/O pin layout.
#endif
--
cgit v1.2.3