From d0a99d5636e9e597a44d872b5350c3588b032439 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Sat, 14 Nov 2020 12:24:28 +0000 Subject: [PATCH] manager: Implement alarm callbacks for applications to use Create a simple time queue where actions (functions or bound methods) can be queued against the real time clock. Signed-off-by: Daniel Thompson --- micropython | 2 +- wasp/boards/simulator/watch.py | 3 ++ wasp/drivers/nrf_rtc.py | 4 +++ wasp/wasp.py | 53 ++++++++++++++++++++++++++++++---- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/micropython b/micropython index b442d82..d198d29 160000 --- a/micropython +++ b/micropython @@ -1 +1 @@ -Subproject commit b442d82b8ca4e7062bfcafedbd6ea2788400ae69 +Subproject commit d198d2907a0837cb82f4d38984bb2ba068cacf77 diff --git a/wasp/boards/simulator/watch.py b/wasp/boards/simulator/watch.py index de1b584..e19e728 100644 --- a/wasp/boards/simulator/watch.py +++ b/wasp/boards/simulator/watch.py @@ -117,6 +117,9 @@ class RTC(object): now = self.get_localtime() return (now[3], now[4], now[5]) + def time(self): + return time.time() + @property def uptime(self): return time.time() - self._epoch diff --git a/wasp/drivers/nrf_rtc.py b/wasp/drivers/nrf_rtc.py index 222be32..100bacd 100644 --- a/wasp/drivers/nrf_rtc.py +++ b/wasp/drivers/nrf_rtc.py @@ -103,6 +103,10 @@ class RTC(object): localtime = self.get_localtime() return localtime[3:6] + def time(self): + """Get time in the same format as time.time""" + return self.offset + (self._uptime >> 3) + @property def uptime(self): """Provide the current uptime in seconds.""" diff --git a/wasp/wasp.py b/wasp/wasp.py index 0b99c0d..a415666 100644 --- a/wasp/wasp.py +++ b/wasp/wasp.py @@ -86,6 +86,14 @@ class PinHandler(): self._value = new_value return new_value +def _key_app(d): + """Get a sort key for apps.""" + return d.NAME + +def _key_alarm(d): + """Get a sort key for alarms.""" + return d[0] + class Manager(): """Wasp-os system manager @@ -112,6 +120,7 @@ class Manager(): self.blank_after = 15 + self._alarms = [] self._brightness = 2 self._button = PinHandler(watch.button) self._charging = True @@ -142,7 +151,7 @@ class Manager(): self.quick_ring.append(app) else: self.launcher_ring.append(app) - self.launcher_ring.sort(key = lambda x: x.NAME) + self.launcher_ring.sort(key = _key_app) @property def brightness(self): @@ -159,7 +168,16 @@ class Manager(): """ if self.app: if 'background' in dir(self.app): - self.app.background() + try: + self.app.background() + except: + # Clear out the old app to ensure we don't recurse when + # we switch to to the CrashApp. It's a bit freaky but + # True has an empty directory this is better than + # None because it won't re-runt he system start up + # code. + self.app = True + raise else: # System start up... watch.display.poweron() @@ -242,6 +260,23 @@ class Manager(): def set_music_info(self, info): self.musicinfo = info + def set_alarm(self, time, action): + """Queue an alarm. + + :param int time: Time to trigger the alarm (use time.mktime) + :param function action: Action to perform when the alarm expires. + """ + self._alarms.append((time, action)) + self._alarms.sort(key = _key_alarm) + + def cancel_alarm(self, time, action): + """Unqueue an alarm.""" + try: + self._alarms.remove((time, action)) + except: + return False + return True + def request_event(self, event_mask): """Subscribe to events. @@ -338,9 +373,19 @@ class Manager(): expiry point. """ rtc = watch.rtc + update = rtc.update() + + alarms = self._alarms + if update and alarms: + now = rtc.time() + head = alarms[0] + + if head[0] <= now: + alarms.remove(head) + head[1]() if self.sleep_at: - if rtc.update() and self.tick_expiry: + if update and self.tick_expiry: now = rtc.get_uptime_ms() if self.tick_expiry <= now: @@ -363,8 +408,6 @@ class Manager(): gc.collect() else: - watch.rtc.update() - if 1 == self._button.get_event() or \ self._charging != watch.battery.charging(): self.wake()