3
* ====================================================================
4
* Ramping UI for nanjg105c and a clicky switch by gChart (Gabriel Hart)
6
* This firmware has its roots loosely based on "Biscotti" by ToyKeeper
8
* ====================================================================
10
* 12 or more fast presses > Configuration mode
14
* 2: Stop-at-the-top toggle (without any user interaction, stops itself at turbo)
15
* 3: Turbo Timer Toggle (turbo steps down to 50%)
16
* 4: Reset to default configuration
18
* ====================================================================
20
* "Biscotti" firmware (attiny13a version of "Bistro")
21
* This code runs on a single-channel driver with attiny13a MCU.
22
* It is intended specifically for nanjg 105d drivers from Convoy.
24
* Copyright (C) 2015 Selene Scriven
26
* This program is free software: you can redistribute it and/or modify
27
* it under the terms of the GNU General Public License as published by
28
* the Free Software Foundation, either version 3 of the License, or
29
* (at your option) any later version.
31
* This program is distributed in the hope that it will be useful,
32
* but WITHOUT ANY WARRANTY; without even the implied warranty of
33
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
* GNU General Public License for more details.
36
* You should have received a copy of the GNU General Public License
37
* along with this program. If not, see <http://www.gnu.org/licenses/>.
45
* GND -|4 5|- PWM (Nx7135)
49
* I use these fuse settings on attiny13
55
* To find out what values to use, flash the driver with battcheck.hex
56
* and hook the light up to each voltage you need a value for. This is
57
* much more reliable than attempting to calculate the values from a
58
* theoretical formula.
60
* Same for off-time capacitor values. Measure, don't guess.
62
// Choose your MCU here, or in the build script
64
#define NANJG_LAYOUT // specify an I/O pin layout
65
// Also, assign I/O pins in this file:
66
#include "../tk-attiny.h"
68
#define DEFAULTS 0b00000100 // No memory, doesn't stop at the top, turbo timer is enabled
70
#define FAST 0xA3 // fast PWM both channels
71
#define PHASE 0xA1 // phase-correct PWM both channels
72
#define VOLTAGE_MON // Comment out to disable LVP
74
#define BLINK_BRIGHTNESS 40 // output to use for blinks in config mode
75
#define BLINK_SPEED 750 // ms per normal-speed blink
77
#define USE_BATTCHECK // Enable battery check mode
78
#define BATTCHECK_8bars // up to 8 blinks
80
#define TURBO_MINUTES 5 // when turbo timer is enabled, how long before stepping down
81
#define TICKS_PER_MINUTE 120 // used for Turbo Timer timing
82
#define TURBO_LOWER 128 // the PWM level to use when stepping down
83
#define TURBO_THRESHOLD sizeof(ramp_values)-5 // Min output level that we consider to be turbo?
85
#define RAMP_TIME 5 // number of seconds to go from min brightness to max brightness
87
#define RAMP_SIZE sizeof(ramp_values)
88
//#define RAMP_VALUES 1,1,1,1,1,2,2,2,2,3,3,4,5,5,6,7,8,9,10,11,13,14,16,18,20,22,24,26,29,32,34,38,41,44,48,51,55,60,64,68,73,78,84,89,95,101,107,113,120,127,134,142,150,158,166,175,184,193,202,212,222,233,244,255
89
#define RAMP_VALUES 5,5,5,5,5,6,6,6,6,7,7,8,8,9,10,11,12,13,14,15,17,18,20,22,23,25,28,30,32,35,38,41,44,47,51,55,59,63,67,71,76,81,86,92,97,103,109,116,122,129,136,144,151,159,167,176,185,194,203,213,223,233,244,255
91
// Calibrate voltage and OTC in this file:
92
#include "../tk-calibration.h"
95
* =========================================================================
98
// Ignore a spurious warning, we did the cast on purpose
99
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
101
#include <avr/pgmspace.h>
102
#include <avr/interrupt.h>
103
#include <avr/eeprom.h>
104
#include <avr/sleep.h>
107
#define OWN_DELAY // Don't use stock delay functions.
108
#define USE_DELAY_MS // use _delay_ms()
109
#define USE_DELAY_S // Also use _delay_s(), not just _delay_ms()
110
#include "../tk-delay.h"
112
#include "../tk-voltage.h"
114
register uint8_t options asm("r6");
115
register uint8_t eepos asm("r7");
117
#define NUM_FP_BYTES 3
118
uint8_t fast_presses[NUM_FP_BYTES] __attribute__ ((section (".noinit")));
121
#define RAMPING_DOWN 1
122
uint8_t ramp_direction __attribute__ ((section (".noinit")));
123
uint8_t ramp_stopped __attribute__ ((section (".noinit")));
124
uint8_t output __attribute__ ((section (".noinit")));
125
uint8_t output_in_eeprom;
127
PROGMEM const uint8_t ramp_values[] = { RAMP_VALUES };
129
inline uint8_t memory_is_enabled() { return (options ) & 0b00000001; }
130
inline uint8_t stop_at_the_top() { return (options >> 1) & 0b00000001; }
131
inline uint8_t ttimer_is_enabled() { return (options >> 2) & 0b00000001; }
133
void save_output() { // save the current output level (with wear leveling)
134
uint8_t oldpos=eepos;
135
eepos = (eepos+1) & ((EEPSIZE/2)-1); // wear leveling, use next cell
136
eeprom_write_byte((uint8_t *)(eepos), output); // save current state
137
eeprom_write_byte((uint8_t *)(oldpos), 0xff); // erase old state
140
#define OPT_options (EEPSIZE-1)
141
void save_state() { // central method for writing complete state
143
eeprom_write_byte((uint8_t *)OPT_options, options);
146
inline void reset_state() {
147
output_in_eeprom = 1;
148
options = DEFAULTS; // 3 brightness levels with memory
152
inline void restore_state() {
156
// find the output level data
157
for(i=0; i<(EEPSIZE-6); i++) {
158
eep = eeprom_read_byte((const uint8_t *)i);
161
output_in_eeprom = eep;
166
// if no output level was found, assume this is the first boot
172
// load other config values
173
options = eeprom_read_byte((uint8_t *)OPT_options);
176
void set_pwm(uint8_t pwm) {
182
void set_level(uint8_t level) {
183
if (level == 0) { set_pwm(0); }
184
else { set_pwm( pgm_read_byte(ramp_values + level - 1) ); }
187
void blink(uint8_t val, uint16_t speed)
191
set_pwm(BLINK_BRIGHTNESS);
199
void toggle_options(uint8_t value, uint8_t num) {
200
blink(num, BLINK_SPEED/4); // indicate which option number this is
201
uint8_t temp = options;
204
blink(32, 500/32); // "buzz" for a while to indicate the active toggle window
206
// if the user didn't click, reset the value and return
212
inline uint8_t we_did_a_fast_press() {
213
uint8_t i = NUM_FP_BYTES-1;
214
while (i && (fast_presses[i] == fast_presses[i-1] )){ --i; }
217
inline void increment_fast_presses() {
219
for(i=0; i<NUM_FP_BYTES; i++) { fast_presses[i]++; }
222
void reset_fast_presses() {
224
for(i=0; i<NUM_FP_BYTES; i++) { fast_presses[i] = 0; }
230
DDRB |= (1 << PWM_PIN); // Set PWM pin to output, enable main channel
232
restore_state(); // Read config values and saved state
234
if ( we_did_a_fast_press() ) {
235
increment_fast_presses();
236
ramp_stopped = !ramp_stopped;
238
if(fast_presses[0] == 2) { // jump to turbo on a double-tap from anywhere
243
if(ramp_stopped) { save_output(); }
245
} else { // Long press
246
reset_fast_presses();
247
ramp_direction = RAMPING_UP;
248
if( memory_is_enabled() ) {
249
output = output_in_eeprom;
267
uint8_t lowbatt_cnt = 0;
269
ADCSRA |= (1 << ADSC); // Make sure voltage reading is running for later
273
if (fast_presses[0] >= 12) { // Config mode if 12 or more fast presses
274
_delay_s(); // wait for user to stop fast-pressing button
275
reset_fast_presses(); // exit this mode after one use
277
toggle_options((options ^ 0b00000001), 1); // memory
278
toggle_options((options ^ 0b00000010), 2); // stop at the top
279
toggle_options((options ^ 0b00000100), 3); // turbo timer
280
toggle_options(DEFAULTS, 4); // reset to defaults
282
else if (fast_presses[0] == 3) {
283
//else if (output == BATT_CHECK) {
284
blink(battcheck(), BLINK_SPEED/4);
285
_delay_s(); _delay_s();
286
// shouldn't need to worry about resetting fast_presses here, but may need to later
288
else if ( !ramp_stopped ) {
290
if(output == 1 || output == RAMP_SIZE) { _delay_s(); } // pause for a second at the lowest & highest levels
292
if( (ramp_direction == RAMPING_DOWN && output == 1) || (ramp_direction == RAMPING_UP && output == RAMP_SIZE) ) {
293
ramp_direction = !ramp_direction;
296
if( output == RAMP_SIZE && stop_at_the_top() ) {
300
if(ramp_direction == RAMPING_UP) { output++; }
303
_delay_ms(RAMP_TIME*1000/RAMP_SIZE);
305
// if we've been ramping around for more than half a second, reset the fast_presses
306
ticks = ticks + (RAMP_TIME*1000/RAMP_SIZE);
309
reset_fast_presses();
314
if ((output >= TURBO_THRESHOLD) && ( ttimer_is_enabled() ) && (ticks > (TURBO_MINUTES * TICKS_PER_MINUTE))) {
315
set_pwm(TURBO_LOWER);
318
ticks ++; // count ticks for turbo timer
322
_delay_ms(500); // Otherwise, just sleep.
323
reset_fast_presses();
326
if (ADCSRA & (1 << ADIF)) { // if a voltage reading is ready
327
voltage = ADCH; // get the waiting value
329
if (voltage < ADC_LOW) { // See if voltage is lower than what we were looking for
335
if (lowbatt_cnt >= 8) { // See if it's been low for a while, and maybe step down
336
if (output > 1) { // not yet at the lowest level
337
output = (output>>1); // divide output in half using bitwise operators
338
} else { // Can't go any lower
339
set_pwm(0); // Turn off the light
340
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Power down as many components as possible
345
_delay_s(); // Wait before lowering the level again
348
ADCSRA |= (1 << ADSC); // Make sure conversion is running for next time through
350
#endif // ifdef VOLTAGE_MON