joeycastillo / Sensor-Watch

A board replacement for the classic Casio F-91W wristwatch
Other
1.21k stars 244 forks source link

Movement: more granular timing of background tasks #28

Closed tahnok closed 2 years ago

tahnok commented 2 years ago

I've been thinking on and off how to implement some kind of countdown timer and I wanted to start a discussion around it.

From what I understand, the SAM L22 only has the one RTC. The alarm is being used to fire the once a minute wake up in low power mode. Movement apps can hook into background task callbacks if they want, but the 'granularity' is limited to once a minute.

Given the above, I don't see a way to make a timer that runs in the background that can fire at a granularity of more than a minute. I think that could be fine for some use cases (I'm thinking a pomodoro app would be neat) but I like to make tea using a 3 minute timer.

The best I can come up with at the moment is to have 2 kinds of timers, a short accurate one that must run in the foreground so it can receive 1Hz updates and a long / low power one that is limited to firing on the minute

joeycastillo commented 2 years ago

The granularity thing is a problem with movement as implemented, but I think with some changes we can get there. The main thing isn't necessarily that the watch face needs to be in the foreground, just that as long as a countdown is running, someone needs to be checking for a match every second. I think we can have Movement do this, and notify the watch face when there is a match. It would mean the watch can't enter low energy mode while a timer is running, but I sense we only need second-level granularity for minutes to hours at a time; a daily alarm or weeks-long countdown can work fine on the minute boundary.

I'm going to play with this today; my instinct is to add a function like:

void movement_schedule_background_task(watch_date_time date_time)

Each watch face can schedule one background task, and as long as a background task is scheduled, the watch won't enter low energy mode. Each tick, Movement will compare the current timestamp to the scheduled task's timestamp, and on a match, call the watch face's loop function with an EVENT_BACKGROUND_TASK. The watch face can then use the background task event to play a sound.

I would like for there to be some way for the watch face to request a move to the foreground (i.e. to play an alarm and display a message), but for now I think allowing a more granular background task will be enough to implement a countdown timer.

joeycastillo commented 2 years ago

I think this code should do what we need; let me know what you think?

The one big limitation is, you can only schedule a background task while active and in the foreground. This is probably fine for a countdown timer since the task will be scheduled in response to the wearer pressing a button, but it may be a challenge for something like a pomodoro app that would want to start a new timer as soon as a previous timer fires. We'd likely need to implement forced foregrounding to allow for that use case, or add an index parameter to this API (which is a challenge since currently watch faces don't know their index in the list of watch faces).

tahnok commented 2 years ago

Code looks good, I don't see anything that would stop a countdown face from being written. From the background, can watch face play a tone?

I agree that having a face be able to bring itself to the foreground would be really handy though. Maybe when the faces are initialized they can be handed their index which they can store if they want? Or when processing background tasks maybe the face can return true/false if it wants to be brought to the foreground?

joeycastillo commented 2 years ago

A watch face can play a short two-beep signal (movement_play_signal) from the background; alas the longer alarm sound (movement_play_alarm) wouldn't work. You could play a longer signal by using a series of watch_buzzer_play_note calls, but these block the UI while playing a note or a rest.

Anyway! I merged in changes that address two items in this thread:

I also added an option in simple_clock_face to turn on an hourly signal, just like the F-91W's hourly signal, that can trigger both in the normal and low energy modes. This can be a template for folks who want to implement alarms in response to a background task.