Rename manager.py and expose its interfaces to all applications

This is a big change that break compatiblity with existing applications
*and* with existing installed versions of main.py.

When upgrading it is import to update main.py:

    ./tools/wasptool --upload wasp/main.py
This commit is contained in:
Daniel Thompson 2020-03-22 12:37:19 +00:00
parent 5a234c16ad
commit f8bd1a7461
8 changed files with 75 additions and 62 deletions

View file

@ -4,7 +4,7 @@ WASP Internals
System management System management
----------------- -----------------
.. automodule:: manager .. automodule:: wasp
:members: :members:
:undoc-members: :undoc-members:

View file

@ -14,6 +14,11 @@ import string
import sys import sys
def sync(c): def sync(c):
"""Stop the watch and synchronize with the command prompt.
Sending a random print ensure the final export (of the prompt)
does not accidentally match a previously issued prompt.
"""
tag = ''.join([random.choice(string.ascii_uppercase) for i in range(6)]) tag = ''.join([random.choice(string.ascii_uppercase) for i in range(6)])
c.send('\x03') c.send('\x03')
@ -23,8 +28,14 @@ def sync(c):
c.expect('>>> ') c.expect('>>> ')
def unsync(c): def unsync(c):
# Set the watch running again """Set the watch running again.
c.sendline('wasp.run()')
There must be an expect (or a sleep) since if we kill the subordinate
process too early then the sendline will not have completed.
"""
c.sendline('wasp.system.run()')
c.expect('Watch is running, use Ctrl-C to stop')
c.send('\x18')
def paste(c, f, verbose=False): def paste(c, f, verbose=False):
docstring = False docstring = False

View file

@ -1,7 +1,6 @@
import wasp
import fonts.clock as digits import fonts.clock as digits
import watch
import widgets
import manager
DIGITS = ( DIGITS = (
digits.clock_0, digits.clock_0,
@ -18,28 +17,28 @@ DIGITS = (
MONTH = 'JanFebMarAprMayJunJulAugSepOctNovDec' MONTH = 'JanFebMarAprMayJunJulAugSepOctNovDec'
class ClockApp(object): class ClockApp():
"""Simple digital clock application. """Simple digital clock application.
Shows a time (as HH:MM) together with a battery meter and the date. Shows a time (as HH:MM) together with a battery meter and the date.
""" """
def __init__(self): def __init__(self):
self.meter = widgets.BatteryMeter() self.meter = wasp.widgets.BatteryMeter()
def handle_event(self, event_view): def handle_event(self, event_view):
"""Process events that the app is subscribed to.""" """Process events that the app is subscribed to."""
if event_view[0] == manager.EVENT_TICK: if event_view[0] == wasp.EVENT_TICK:
self.update() self.update()
else: else:
# TODO: Raise an unexpected event exception # TODO: Raise an unexpected event exception
pass pass
def foreground(self, manager, effect=None): def foreground(self, effect=None):
"""Activate the application.""" """Activate the application."""
self.on_screen = ( -1, -1, -1, -1, -1, -1 ) self.on_screen = ( -1, -1, -1, -1, -1, -1 )
self.draw(effect) self.draw(effect)
manager.request_tick(1000) wasp.system.request_tick(1000)
def tick(self, ticks): def tick(self, ticks):
self.update() self.update()
@ -56,7 +55,7 @@ class ClockApp(object):
def draw(self, effect=None): def draw(self, effect=None):
"""Redraw the display from scratch.""" """Redraw the display from scratch."""
draw = watch.drawable draw = wasp.watch.drawable
draw.fill() draw.fill()
draw.rleblit(digits.clock_colon, pos=(2*48, 80), fg=0xb5b6) draw.rleblit(digits.clock_colon, pos=(2*48, 80), fg=0xb5b6)
@ -70,14 +69,14 @@ class ClockApp(object):
The updates are a lazy as possible and rely on an prior call to The updates are a lazy as possible and rely on an prior call to
draw() to ensure the screen is suitably prepared. draw() to ensure the screen is suitably prepared.
""" """
now = watch.rtc.get_localtime() now = wasp.watch.rtc.get_localtime()
if now[3] == self.on_screen[3] and now[4] == self.on_screen[4]: if now[3] == self.on_screen[3] and now[4] == self.on_screen[4]:
if now[5] != self.on_screen[5]: if now[5] != self.on_screen[5]:
self.meter.update() self.meter.update()
self.on_screen = now self.on_screen = now
return False return False
draw = watch.drawable draw = wasp.watch.drawable
draw.rleblit(DIGITS[now[4] % 10], pos=(4*48, 80)) draw.rleblit(DIGITS[now[4] % 10], pos=(4*48, 80))
draw.rleblit(DIGITS[now[4] // 10], pos=(3*48, 80), fg=0xbdb6) draw.rleblit(DIGITS[now[4] // 10], pos=(3*48, 80), fg=0xbdb6)
draw.rleblit(DIGITS[now[3] % 10], pos=(1*48, 80)) draw.rleblit(DIGITS[now[3] % 10], pos=(1*48, 80))

View file

@ -1,5 +1,4 @@
import watch import wasp
import manager
class FlashlightApp(object): class FlashlightApp(object):
"""Trivial flashlight application. """Trivial flashlight application.
@ -10,11 +9,11 @@ class FlashlightApp(object):
def __init__(self): def __init__(self):
self.backlight = None self.backlight = None
def foreground(self, manager, effect=None): def foreground(self, effect=None):
"""Activate the application.""" """Activate the application."""
self.on_screen = ( -1, -1, -1, -1, -1, -1 ) self.on_screen = ( -1, -1, -1, -1, -1, -1 )
self.draw(effect) self.draw(effect)
manager.request_tick(1000) wasp.system.request_tick(1000)
def background(self): def background(self):
"""De-activate the application (without losing state).""" """De-activate the application (without losing state)."""
@ -28,5 +27,5 @@ class FlashlightApp(object):
def draw(self, effect=None): def draw(self, effect=None):
"""Redraw the display from scratch.""" """Redraw the display from scratch."""
display = watch.display display = wasp.watch.display
display.fill(0xffff) display.fill(0xffff)

View file

@ -1,7 +1,5 @@
import watch
import widgets
import manager
import machine import machine
import wasp
class TestApp(): class TestApp():
"""Simple test application. """Simple test application.
@ -11,11 +9,11 @@ class TestApp():
self.tests = ('Touch', 'String') self.tests = ('Touch', 'String')
self.test = self.tests[0] self.test = self.tests[0]
def foreground(self, system, effect=None): def foreground(self, effect=None):
"""Activate the application.""" """Activate the application."""
self.on_screen = ( -1, -1, -1, -1, -1, -1 ) self.on_screen = ( -1, -1, -1, -1, -1, -1 )
self.draw(effect) self.draw(effect)
system.request_event(manager.EVENT_TOUCH | manager.EVENT_SWIPE_UPDOWN) wasp.system.request_event(wasp.EVENT_TOUCH | wasp.EVENT_SWIPE_UPDOWN)
def background(self): def background(self):
"""De-activate the application (without losing state).""" """De-activate the application (without losing state)."""
@ -33,7 +31,7 @@ class TestApp():
self.draw() self.draw()
def touch(self, event): def touch(self, event):
draw = watch.drawable draw = wasp.watch.drawable
if self.test == 'Touch': if self.test == 'Touch':
draw.string('({}, {})'.format(event[1], event[2]), draw.string('({}, {})'.format(event[1], event[2]),
0, 108, width=240) 0, 108, width=240)
@ -55,8 +53,8 @@ class TestApp():
def draw(self, effect=None): def draw(self, effect=None):
"""Redraw the display from scratch.""" """Redraw the display from scratch."""
watch.display.mute(True) wasp.watch.display.mute(True)
watch.drawable.fill() wasp.watch.drawable.fill()
watch.drawable.string('{} test'.format(self.test), wasp.watch.drawable.string('{} test'.format(self.test),
0, 6, width=240) 0, 6, width=240)
watch.display.mute(False) wasp.watch.display.mute(False)

View file

@ -17,8 +17,8 @@ freeze('../..',
'fonts/sans24.py', 'fonts/sans24.py',
'icons.py', 'icons.py',
'logo.py', 'logo.py',
'manager.py',
'shell.py', 'shell.py',
'wasp.py',
'widgets.py', 'widgets.py',
), ),
opt=3 opt=3

View file

@ -1,3 +1,2 @@
import manager, watch import wasp
wasp = manager.Manager(watch) wasp.system.run()
wasp.run()

View file

@ -1,5 +1,7 @@
import gc import gc
import machine import machine
import watch
import widgets
from apps.clock import ClockApp from apps.clock import ClockApp
from apps.flashlight import FlashlightApp from apps.flashlight import FlashlightApp
@ -16,9 +18,7 @@ EVENT_SWIPE_UPDOWN = 0x0004
EVENT_BUTTON = 0x0008 EVENT_BUTTON = 0x0008
class Manager(object): class Manager(object):
def __init__(self, watch): def __init__(self):
self.watch = watch
self.app = None self.app = None
self.applications = [ self.applications = [
@ -26,17 +26,17 @@ class Manager(object):
FlashlightApp(), FlashlightApp(),
TestApp() TestApp()
] ]
self.watch.display.poweron()
self.switch(self.applications[0])
self.watch.backlight.set(2)
self.sleep_at = watch.rtc.uptime + 90
self.charging = True self.charging = True
def switch(self, app): def switch(self, app):
if self.app: if self.app:
self.app.background() self.app.background()
else:
# System start up...
watch.display.poweron()
watch.display.mute(True)
watch.backlight.set(2)
self.sleep_at = watch.rtc.uptime + 90
# Clear out any configuration from the old application # Clear out any configuration from the old application
self.event_mask = 0 self.event_mask = 0
@ -44,9 +44,9 @@ class Manager(object):
self.tick_expiry = None self.tick_expiry = None
self.app = app self.app = app
self.watch.display.mute(True) watch.display.mute(True)
app.foreground(self) app.foreground()
self.watch.display.mute(False) watch.display.mute(False)
def navigate(self, direction=None): def navigate(self, direction=None):
"""Navigate between different applications. """Navigate between different applications.
@ -76,10 +76,10 @@ class Manager(object):
tick intervals are not possible. tick intervals are not possible.
""" """
self.tick_period_ms = period_ms self.tick_period_ms = period_ms
self.tick_expiry = self.watch.rtc.get_uptime_ms() + period_ms self.tick_expiry = watch.rtc.get_uptime_ms() + period_ms
def handle_event(self, event): def handle_event(self, event):
self.sleep_at = self.watch.rtc.uptime + 15 self.sleep_at = watch.rtc.uptime + 15
event_mask = self.event_mask event_mask = self.event_mask
if event[0] < 5: if event[0] < 5:
@ -94,7 +94,7 @@ class Manager(object):
self.app.touch(event) self.app.touch(event)
def tick(self): def tick(self):
rtc = self.watch.rtc rtc = watch.rtc
if self.sleep_at: if self.sleep_at:
if rtc.update() and self.tick_expiry: if rtc.update() and self.tick_expiry:
@ -107,36 +107,36 @@ class Manager(object):
ticks += 1 ticks += 1
self.app.tick(ticks) self.app.tick(ticks)
if self.watch.button.value(): if watch.button.value():
self.sleep_at = self.watch.rtc.uptime + 15 self.sleep_at = watch.rtc.uptime + 15
event = self.watch.touch.get_event() event = watch.touch.get_event()
if event: if event:
self.handle_event(event) self.handle_event(event)
if self.watch.rtc.uptime > self.sleep_at: if watch.rtc.uptime > self.sleep_at:
self.watch.backlight.set(0) watch.backlight.set(0)
if not self.app.sleep(): if not self.app.sleep():
self.switch(self.applications[0]) self.switch(self.applications[0])
self.app.sleep() self.app.sleep()
self.watch.display.poweroff() watch.display.poweroff()
self.charging = self.watch.battery.charging() self.charging = watch.battery.charging()
self.sleep_at = None self.sleep_at = None
gc.collect() gc.collect()
else: else:
self.watch.rtc.update() watch.rtc.update()
charging = self.watch.battery.charging() charging = watch.battery.charging()
if self.watch.button.value() or self.charging != charging: if watch.button.value() or self.charging != charging:
self.watch.display.poweron() watch.display.poweron()
self.app.wake() self.app.wake()
self.watch.backlight.set(2) watch.backlight.set(2)
# Discard any pending touch events # Discard any pending touch events
_ = self.watch.touch.get_event() _ = watch.touch.get_event()
self.sleep_at = self.watch.rtc.uptime + 15 self.sleep_at = watch.rtc.uptime + 15
def run(self): def run(self):
"""Run the system manager synchronously. """Run the system manager synchronously.
@ -145,6 +145,13 @@ class Manager(object):
normal execution context meaning any exceptions and other problems normal execution context meaning any exceptions and other problems
can be observed interactively via the console. can be observed interactively via the console.
""" """
if not self.app:
self.switch(self.applications[0])
print('Watch is running, use Ctrl-C to stop')
while True: while True:
self.tick() self.tick()
machine.deepsleep() machine.deepsleep()
system = Manager()