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;
3841const float FADE_AFTER_MS = 3000 ;
3942const 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
4358Adafruit_IS31FL3731 matrix = Adafruit_IS31FL3731();
4459Encoder rotaryEncoder = Encoder(PIN_ENCODER_A , PIN_ENCODER_B );
@@ -49,17 +64,16 @@ bool buttonDown = false;
4964elapsedMillis timerSeconds;
5065elapsedMillis timeSinceInput;
5166elapsedMillis timeSinceTick;
52- elapsedMillis timeSinceAlarmOff;
5367elapsedMillis timeSinceButtonDown;
5468
5569// the main time keeping variable
5670int 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
5875bool 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
6478long 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
190212void 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
206228void 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
240252void 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-
252258void 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
358423void idle () {
@@ -365,6 +430,8 @@ void idle() {
365430}
366431
367432void 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
399465void wakeUpInterrupt (){
@@ -411,9 +477,26 @@ int minutes(){
411477}
412478
413479long 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