Skip to content

Commit f2fd960

Browse files
committed
big refactor to use states instead of whatever chaos was before
1 parent 41f836c commit f2fd960

4 files changed

Lines changed: 160 additions & 72 deletions

File tree

‎kitchen-timer.ino‎

Lines changed: 148 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
// how long to sound the alarm, after this, we just give up and go back to sleep
2929
#define ALARM_DURATION_SECONDS 60
3030

31+
// any remaining ticks on the rotary will be cleared after this long (ms)
32+
#define CLEAR_TICKS_AFTER_MS 750
33+
3134
// how long to wait after user input stops before starting the timer
3235
#define WAIT_AFTER_INPUT_MS 1000
3336
// ignore user inputs for a bit after turning of the alarm as to not set a new time immediately
@@ -38,7 +41,19 @@ const float SLEEP_AFTER_MS = 5000;
3841
const float FADE_AFTER_MS = 3000;
3942
const float FADE_DURATION_MS = SLEEP_AFTER_MS - FADE_AFTER_MS;
4043

41-
#define CLEAR_TICKS_AFTER_MS 750
44+
45+
enum State {
46+
IDLE,
47+
SET_TIMER,
48+
TIMER,
49+
ALARM,
50+
ALARM_OFF_COOLDOWN,
51+
VIEW_TOTAL,
52+
MUSIC,
53+
};
54+
55+
State state = IDLE;
56+
elapsedMillis timeInState;
4257

4358
Adafruit_IS31FL3731 matrix = Adafruit_IS31FL3731();
4459
Encoder rotaryEncoder = Encoder(PIN_ENCODER_A, PIN_ENCODER_B);
@@ -49,17 +64,16 @@ bool buttonDown = false;
4964
elapsedMillis timerSeconds;
5065
elapsedMillis timeSinceInput;
5166
elapsedMillis timeSinceTick;
52-
elapsedMillis timeSinceAlarmOff;
5367
elapsedMillis timeSinceButtonDown;
5468

5569
// the main time keeping variable
5670
int time = 0;
71+
// this stores the total time counted for this "session"
72+
int timeTotal = 0;
73+
5774
// this is used for the double buffering of the display, swaps between 0/1 each update
5875
bool bufferSwapper = true;
5976

60-
// is the alarm active? is set to the number of seconds the alarm will sound and decrements until zero
61-
int alarmActive = 0;
62-
6377
// keep track of where the encoder was last update
6478
long encoderPosition = 0;
6579

@@ -105,7 +119,7 @@ void wakeUp(){
105119
swapBuffers();
106120

107121
timeSinceInput = 0;
108-
timeSinceAlarmOff = IGNORE_TIMER_SET_AFTER_ALARM_MS;
122+
setState(ALARM_OFF_COOLDOWN);
109123
refreshScreen();
110124
}
111125

@@ -160,41 +174,49 @@ void onRotary(int delta, int position){
160174
timeSinceInput = 0;
161175

162176
// if the alarm is going off, the knob won't change anything
163-
if (alarmActive){
177+
if (state == ALARM){
164178
dismissAlarm();
165179
return;
166180
}
167181

168182
// if we recently turned off the alarm, ignore inputs for a bit
169-
if (alarmRecentlyOff()) return;
183+
if (state == ALARM_OFF_COOLDOWN) return;
184+
185+
setState(SET_TIMER);
170186

171187
const int volume = 5;
172188
const int duration = 5;
173189
const bool background = true;
174190
if (delta > 0) toneAC(position % 2 == 0 ? NOTE_C7 : NOTE_D7, volume, duration, background);
175191
else if (time > 0) toneAC(position % 2 == 0 ? NOTE_C7 : NOTE_B6, volume, duration, background);
176192

193+
// if the counter is at zero, we also reset the timeTotal counter to make this a new "session"
194+
if (time == 0) timeTotal = 0;
195+
177196
// 30 second steps up to 5 minutes, then 1 minute steps
178197
if (time < 5 * 60) {
179198
time += delta * 30;
199+
timeTotal += delta * 30;
180200
} else {
181-
time += delta * 60;
201+
time += delta * 60;
202+
timeTotal += delta * 60;
182203
}
183204

184205
// don't go below zero
185206
if (time < 0) time = 0;
207+
if (timeTotal < 0) timeTotal = 0;
186208

187209
refreshScreen(true);
188210
}
189211

190212
void onButtonDown(){
191213
timeSinceInput = 0;
192214

193-
if (alarmActive){
215+
if (state == ALARM){
194216
dismissAlarm();
195217
return;
196218
}
197-
timeSinceButtonDown = 0;
219+
198220
buttonDown = true;
199221
}
200222

@@ -204,31 +226,21 @@ void onButtonUp(){
204226
}
205227

206228
void dismissAlarm(){
207-
alarmActive = 0;
208-
timeSinceAlarmOff = 0;
229+
setState(ALARM_OFF_COOLDOWN);
209230
time = 0;
210231
playMelody(melody_timer_dismiss);
211232
refreshScreen();
212233
}
213234

214-
bool waitOnLastFrame = false;
215-
void onTick(){
216-
if (alarmActive) onAlarm(false);
235+
void onSecond(){
236+
if (state == ALARM) onAlarm(false);
217237
if (time == 0) {
218238
refreshScreen();
219239
return;
220240
}
221241

222-
// don't count time when the user is inputting
223-
if (timeSinceInput < WAIT_AFTER_INPUT_MS){
224-
waitOnLastFrame = true;
225-
return;
226-
} else if (waitOnLastFrame){
227-
onStartTimer();
228-
waitOnLastFrame = false;
229-
return;
230-
}
231-
242+
if (state != TIMER) return;
243+
232244
time -= 1;
233245
if (time < 0) time = 0;
234246

@@ -238,17 +250,11 @@ void onTick(){
238250
}
239251

240252
void onAlarm(bool setActive){
241-
if (setActive) alarmActive = ALARM_DURATION_SECONDS;
242-
else alarmActive--;
243-
244-
if (alarmActive % 2 == 1) return;
253+
if (setActive) setState(ALARM);
254+
if ((timeInState / 1000) % 2 == 1) return;
245255
playMelody(melody_alarm);
246256
}
247257

248-
void onStartTimer(){
249-
playMelody(melody_timer_start);
250-
}
251-
252258
void refreshScreen(){
253259
refreshScreen(false);
254260
}
@@ -259,7 +265,7 @@ void refreshScreen(bool force){
259265
lastFrame = currentFrame;
260266

261267
// play alarm animation
262-
if (alarmActive){
268+
if (state == ALARM){
263269
int frameHalf = currentFrame / 2;
264270
int frameHalfOffset = currentFrame / 2 + 50;
265271

@@ -276,16 +282,15 @@ void refreshScreen(bool force){
276282
}
277283

278284
// alarm's just been turned off, show a little confirm message
279-
if (alarmRecentlyOff()) {
285+
if (state == ALARM_OFF_COOLDOWN) {
280286
matrix.setCursor(2, 7);
281287
matrix.print("off");
282288
swapBuffers();
283289
return;
284290
}
285291

286292
// we're idle, show a cute face
287-
if (time == 0) {
288-
293+
if (state == IDLE) {
289294
// do a nice fade out before going to sleep
290295
int time = timeSinceInput;
291296
float fade = (float) (time - FADE_AFTER_MS) / FADE_DURATION_MS;
@@ -304,27 +309,29 @@ void refreshScreen(bool force){
304309
}
305310

306311
// timer is active, show the timer digits
307-
if (minutes() > 0) {
308-
matrix.print(minutes());
312+
if (state == TIMER || state == SET_TIMER) {
313+
if (minutes() > 0) {
314+
matrix.print(minutes());
315+
316+
if (minutes() > 9){
317+
matrix.print("m");
318+
} else {
319+
matrix.print(":");
320+
}
321+
}
309322

310-
if (minutes() > 9){
311-
matrix.print("m");
312-
} else {
313-
matrix.print(":");
323+
if (seconds() > 0 && seconds() < 10) matrix.print(0);
324+
matrix.print(seconds());
325+
if (minutes() == 0) matrix.print("s");
326+
327+
if (seconds() > 0) {
328+
const int barY = 8;
329+
int lastBarPixelX = seconds() / 4;
330+
matrix.drawLine(0, barY, lastBarPixelX, barY, BRIGHTNESS);
331+
matrix.drawLine(lastBarPixelX + 1, barY, lastBarPixelX + 1, barY, seconds() % 2 == 0 ? BRIGHTNESS_EXTRA : BRIGHTNESS_HALF);
314332
}
315333
}
316334

317-
if (seconds() < 10) matrix.print(0);
318-
matrix.print(seconds());
319-
if (minutes() == 0) matrix.print("s");
320-
321-
if (seconds() > 0) {
322-
const int barY = 8;
323-
int lastBarPixelX = seconds() / 4;
324-
matrix.drawLine(0, barY, lastBarPixelX, barY, BRIGHTNESS);
325-
matrix.drawLine(lastBarPixelX + 1, barY, lastBarPixelX + 1, barY, seconds() % 2 == 0 ? BRIGHTNESS_EXTRA : BRIGHTNESS_HALF);
326-
}
327-
328335
swapBuffers();
329336
}
330337

@@ -336,23 +343,81 @@ void loop() {
336343
if (pushbutton.fallingEdge()) onButtonDown();
337344
if (pushbutton.risingEdge()) onButtonUp();
338345
}
346+
if (!buttonDown) timeSinceButtonDown = 0;
339347

340348
if (timerSeconds >= MS_IN_A_SECOND) {
341-
onTick();
349+
onSecond();
342350
timerSeconds -= MS_IN_A_SECOND;
343351
}
344352

353+
switch(state) {
354+
case IDLE: loopIdle();
355+
break;
356+
case SET_TIMER: loopSetTimer();
357+
break;
358+
case TIMER: loopTimer();
359+
break;
360+
case ALARM: loopAlarm();
361+
break;
362+
case ALARM_OFF_COOLDOWN: loopAlarmOffCooldown();
363+
break;
364+
case VIEW_TOTAL: loopViewTotal();
365+
break;
366+
case MUSIC: loopMusic();
367+
}
368+
369+
updateMelody();
370+
idle();
371+
}
372+
373+
void loopIdle(){
374+
refreshScreen();
375+
if (buttonDown && timeSinceButtonDown > 3000){
376+
playMelody(melody_nevergonnagive);
377+
onButtonUp();
378+
}
379+
380+
if (timeSinceInput > SLEEP_AFTER_MS) sleep();
381+
}
382+
383+
void loopSetTimer(){
384+
if (timeSinceInput < WAIT_AFTER_INPUT_MS) return;
385+
if (time > 0){
386+
playMelody(melody_timer_start);
387+
setState(TIMER);
388+
} else {
389+
playMelody(melody_timer_dismiss);
390+
setState(IDLE);
391+
}
392+
// we reset this here to make the delay until the timer ticks consistent
393+
timerSeconds = 700;
394+
}
395+
396+
void loopTimer(){
397+
398+
}
399+
400+
void loopAlarm(){
345401
// if the button is down, we instantly dismiss any alarm, if it's just the timer, we wait for one second first
346-
if (buttonDown && ((time > 0 && timeSinceButtonDown > 1000) || alarmActive)) {
402+
if (buttonDown) {
347403
dismissAlarm();
348404
onButtonUp();
349405
}
406+
refreshScreen();
407+
}
350408

351-
if (alarmActive || alarmRecentlyOff() || time == 0) refreshScreen();
352-
if (timeSinceInput > SLEEP_AFTER_MS && time == 0 && alarmActive == 0) sleep();
409+
void loopAlarmOffCooldown(){
410+
refreshScreen();
411+
if (timeInState < IGNORE_TIMER_SET_AFTER_ALARM_MS) return;
412+
setState(IDLE);
413+
}
353414

354-
updateMelody();
355-
idle();
415+
void loopViewTotal(){
416+
417+
}
418+
419+
void loopMusic(){
420+
356421
}
357422

358423
void idle() {
@@ -365,6 +430,8 @@ void idle() {
365430
}
366431

367432
void sleep() {
433+
return;
434+
368435
#ifdef USE_SLEEP_LED
369436
digitalWrite(PIN_SLEEP_LED, HIGH); // set the LED on
370437
#endif
@@ -393,7 +460,6 @@ void sleep() {
393460
sleep_disable(); // this is where we come back in again after sleeping
394461
}
395462

396-
397463
// this function gets called by the encoder class, i couln't make the interrupts play nice together
398464
// so i hacked it in there, this sets a flag that is then read by the loop() which brings everything back
399465
void wakeUpInterrupt(){
@@ -411,9 +477,26 @@ int minutes(){
411477
}
412478

413479
long frame() {
414-
return millis() / 100;
480+
return millis() / (long) 100;
415481
}
416482

417-
bool alarmRecentlyOff(){
418-
return timeSinceAlarmOff < IGNORE_TIMER_SET_AFTER_ALARM_MS;
483+
void setState(State newState){
484+
if (state == newState) return;
485+
state = newState;
486+
timeInState = 0;
487+
switch(state) {
488+
case IDLE: Serial.println("IDLE");
489+
break;
490+
case SET_TIMER: Serial.println("SET_TIMER");
491+
break;
492+
case TIMER: Serial.println("TIMER");
493+
break;
494+
case ALARM: Serial.println("ALARM");
495+
break;
496+
case ALARM_OFF_COOLDOWN: Serial.println("ALARM_OFF_COOLDOWN");
497+
break;
498+
case VIEW_TOTAL: Serial.println("VIEW_TOTAL");
499+
break;
500+
case MUSIC: Serial.println("MUSIC");
501+
}
419502
}

0 commit comments

Comments
 (0)