summaryrefslogtreecommitdiff
path: root/wasp
diff options
context:
space:
mode:
authorDaniel Thompson <daniel@redfelineninja.org.uk>2020-03-08 10:18:08 (GMT)
committerDaniel Thompson <daniel@redfelineninja.org.uk>2020-03-08 10:18:08 (GMT)
commitb5b96bd7760f76d9bb476eb835f49b3c9586ca5c (patch)
tree2c9f5e9d4682a1efc870754d2e37d680f33925a2 /wasp
parent753a1e68f114772cd0fce765c7ec4770c8e34036 (diff)
wasp: Integrate the touch driver
At this point we are starting to bring an event model for applications but there's still a long way to go!
Diffstat (limited to 'wasp')
-rw-r--r--wasp/boards/pinetime/manifest.py2
-rw-r--r--wasp/boards/simulator/display.py6
-rw-r--r--wasp/clock.py6
-rw-r--r--wasp/drivers/cst816s.py51
-rw-r--r--wasp/flashlight.py34
-rw-r--r--wasp/manager.py74
-rw-r--r--wasp/testapp.py35
7 files changed, 193 insertions, 15 deletions
diff --git a/wasp/boards/pinetime/manifest.py b/wasp/boards/pinetime/manifest.py
index 4787520..b3e2e17 100644
--- a/wasp/boards/pinetime/manifest.py
+++ b/wasp/boards/pinetime/manifest.py
@@ -11,12 +11,14 @@ freeze('../..',
'drivers/signal.py',
'drivers/st7789.py',
'drivers/vibrator.py',
+ 'flashlight.py',
'fonts/clock.py',
'fonts/sans24.py',
'icons.py',
'logo.py',
'manager.py',
'shell.py',
+ 'testapp.py',
'widgets.py',
),
opt=3
diff --git a/wasp/boards/simulator/display.py b/wasp/boards/simulator/display.py
index 93ac8ae..41d9512 100644
--- a/wasp/boards/simulator/display.py
+++ b/wasp/boards/simulator/display.py
@@ -77,7 +77,10 @@ class CST816SSim():
raise OSError
dbuf[:] = self.regs[reg:len(dbuf)+reg]
- self.regs[1] = 0
+ if self.regs[3]:
+ self.regs[3] = 0
+ else:
+ self.regs[1] = 0
def handle_key(self, key):
if key.keysym.sym == sdl2.SDLK_DOWN:
@@ -88,6 +91,7 @@ class CST816SSim():
self.regs[1] = 3
elif key.keysym.sym == sdl2.SDLK_RIGHT:
self.regs[1] = 4
+ self.regs[3] = 0x80
self.raise_interrupt()
def handle_mousebutton(self, button):
diff --git a/wasp/clock.py b/wasp/clock.py
index c3b3c3a..5de6271 100644
--- a/wasp/clock.py
+++ b/wasp/clock.py
@@ -50,6 +50,12 @@ class ClockApp(object):
"""De-activate the application (without losing state)."""
pass
+ def sleep(self):
+ return True
+
+ def wake(self):
+ self.update()
+
def draw(self, effect=None):
"""Redraw the display from scratch."""
display = watch.display
diff --git a/wasp/drivers/cst816s.py b/wasp/drivers/cst816s.py
index 4a372c0..7461a5f 100644
--- a/wasp/drivers/cst816s.py
+++ b/wasp/drivers/cst816s.py
@@ -1,4 +1,14 @@
-"""Hynitron CST816S touch contoller driver for MicroPython."""
+"""Hynitron CST816S touch contoller driver for MicroPython.
+
+After modifying this file we can replace the frozen driver with the
+test driver with the following command::
+
+ ./tools/wasptool \
+ --exec wasp/drivers/cst816s.py \
+ --eval "watch.touch = CST816S(watch.i2c)"`
+"""
+
+import array
class CST816S:
"""Hynitron CST816S I2C touch controller driver."""
@@ -6,23 +16,48 @@ class CST816S:
def __init__(self, bus):
self.i2c = bus
self.dbuf = bytearray(6)
+ self.event = array.array('H', (0, 0, 0))
- def get_event(self, queue):
+ def get_event(self):
"""Receive a touch event.
Check for a pending touch event and, if an event is pending,
prepare it ready to go in the event queue.
- :return: True if an event is received, False otherwise.
+ :return: An event record if an event is received, None otherwise.
"""
dbuf = self.dbuf
+ event = self.event
+
+ # TODO: check the interrupt pin
try:
self.i2c.readfrom_mem_into(21, 1, dbuf)
except OSError:
- return False
+ return None
+
+ # Skip junk events
+ if dbuf[0] == 0:
+ return None
+
+ x = ((dbuf[2] & 0xf) << 8) + dbuf[3]
+ y = ((dbuf[4] & 0xf) << 8) + dbuf[5]
+ swipe_start = dbuf[2] & 0x80
+
+ # Skip identical events... when the I2C interface comes alive
+ # we can still get back stale events
+ if dbuf[0] == event[0] and x == event[1] and y == event[2] \
+ and not swipe_start:
+ return None
+
+ # This is a good event, lets save it
+ event[0] = dbuf[0]
+ event[1] = x
+ event[2] = y
+
+ # Do not forward swipe start events
+ if dbuf[2] & 0x80:
+ event[0] = 0
+ return None
- queue[0] = dbuf[0]
- queue[1] = ((dbuf[2] & 0xf) << 8) + dbuf[3]
- queue[2] = ((dbuf[4] & 0xf) << 8) + dbuf[5]
- return True
+ return event
diff --git a/wasp/flashlight.py b/wasp/flashlight.py
new file mode 100644
index 0000000..d71342b
--- /dev/null
+++ b/wasp/flashlight.py
@@ -0,0 +1,34 @@
+import watch
+import manager
+
+from draw565 import Draw565
+
+class FlashlightApp(object):
+ """Trivial flashlight application.
+
+ Shows a pure white screen with the backlight set to maximum.
+ """
+
+ def __init__(self):
+ self.backlight = None
+
+ def foreground(self, manager, effect=None):
+ """Activate the application."""
+ self.on_screen = ( -1, -1, -1, -1, -1, -1 )
+ self.draw(effect)
+ manager.request_tick(1000)
+
+ def background(self):
+ """De-activate the application (without losing state)."""
+ pass
+
+ def sleep(self):
+ return False
+
+ def tick(self, ticks):
+ pass
+
+ def draw(self, effect=None):
+ """Redraw the display from scratch."""
+ display = watch.display
+ display.fill(0xffff)
diff --git a/wasp/manager.py b/wasp/manager.py
index 879c3f2..6e45518 100644
--- a/wasp/manager.py
+++ b/wasp/manager.py
@@ -1,30 +1,69 @@
import clock
+import flashlight
+import testapp
import gc
import machine
-EVENT_TICK = 0x100
-EVENT_KEYMASK = 0xff
+DOWN = 1
+UP = 2
+LEFT = 3
+RIGHT = 4
+
+EVENT_TOUCH = 0x0001
+EVENT_BUTTON = 0x0002
class Manager(object):
def __init__(self, watch):
self.watch = watch
self.app = None
- self.switch(clock.ClockApp())
+
+ self.applications = [
+ clock.ClockApp(),
+ flashlight.FlashlightApp(),
+ testapp.TouchTestApp()
+ ]
+
+ self.watch.display.poweron()
+ self.switch(self.applications[0])
+ self.watch.backlight.set(2)
+
self.sleep_at = watch.rtc.uptime + 90
self.charging = True
def switch(self, app):
if self.app:
- self.app.background(self)
+ self.app.background()
# Clear out any configuration from the old application
+ self.event_mask = 0
self.tick_period_ms = 0
self.tick_expiry = None
self.app = app
app.foreground(self)
+ def navigate(self, direction=None):
+ """Navigate between different applications.
+
+ Currently the direction is ignored.
+ """
+ app_list = self.applications
+
+ if direction == DOWN:
+ i = app_list.index(self.app) + 1
+ if i >= len(app_list):
+ i = 0
+ self.switch(app_list[i])
+ elif direction == UP:
+ i = app_list.index(self.app) - 1
+ if i < 0:
+ i = len(app_list)-1
+ self.switch(app_list[i])
+
+ def request_event(self, event_mask):
+ self.event_mask |= event_mask
+
def request_tick(self, period_ms=None):
"""Request (and subscribe to) a periodic tick event.
@@ -34,6 +73,14 @@ class Manager(object):
self.tick_period_ms = period_ms
self.tick_expiry = self.watch.rtc.get_uptime_ms() + period_ms
+ def handle_event(self, event):
+ self.sleep_at = self.watch.rtc.uptime + 15
+
+ if event[0] < 5:
+ self.navigate(event[0])
+ elif event[0] == 5 and self.event_mask & EVENT_TOUCH:
+ self.app.touch(event)
+
def tick(self):
rtc = self.watch.rtc
@@ -51,8 +98,15 @@ class Manager(object):
if self.watch.button.value():
self.sleep_at = self.watch.rtc.uptime + 15
+ event = self.watch.touch.get_event()
+ if event:
+ self.handle_event(event)
+
if self.watch.rtc.uptime > self.sleep_at:
self.watch.backlight.set(0)
+ if not self.app.sleep():
+ self.switch(self.applications[0])
+ self.app.sleep()
self.watch.display.poweroff()
self.charging = self.watch.battery.charging()
self.sleep_at = None
@@ -64,13 +118,21 @@ class Manager(object):
charging = self.watch.battery.charging()
if self.watch.button.value() or self.charging != charging:
self.watch.display.poweron()
- self.app.tick(None)
+ self.app.wake()
self.watch.backlight.set(2)
- self.sleep_at = self.watch.rtc.uptime + 15
+ # Discard any pending touch events
+ _ = self.watch.touch.get_event()
+ self.sleep_at = self.watch.rtc.uptime + 15
def run(self):
+ """Run the system manager synchronously.
+
+ This allows all watch management activities to handle in the
+ normal execution context meaning any exceptions and other problems
+ can be observed interactively via the console.
+ """
while True:
self.tick()
machine.deepsleep()
diff --git a/wasp/testapp.py b/wasp/testapp.py
new file mode 100644
index 0000000..2cf3431
--- /dev/null
+++ b/wasp/testapp.py
@@ -0,0 +1,35 @@
+import watch
+import widgets
+import manager
+
+from draw565 import Draw565
+
+class TouchTestApp(object):
+ """Simple application to visualize touch events.
+ """
+
+ def __init__(self):
+ pass
+
+ def foreground(self, system, effect=None):
+ """Activate the application."""
+ self.on_screen = ( -1, -1, -1, -1, -1, -1 )
+ self.draw(effect)
+ system.request_event(manager.EVENT_TOUCH)
+
+ def background(self):
+ """De-activate the application (without losing state)."""
+ pass
+
+ def sleep(self):
+ return False
+
+ def touch(self, event):
+ draw = Draw565(watch.display)
+ draw.string('({}, {})'.format(event[1], event[2]),
+ 0, 180, width=240)
+ return True
+
+ def draw(self, effect=None):
+ """Redraw the display from scratch."""
+ watch.display.fill(0)