diff options
| author | Daniel Thompson <daniel@redfelineninja.org.uk> | 2020-03-08 10:18:08 (GMT) |
|---|---|---|
| committer | Daniel Thompson <daniel@redfelineninja.org.uk> | 2020-03-08 10:18:08 (GMT) |
| commit | b5b96bd7760f76d9bb476eb835f49b3c9586ca5c (patch) | |
| tree | 2c9f5e9d4682a1efc870754d2e37d680f33925a2 /wasp | |
| parent | 753a1e68f114772cd0fce765c7ec4770c8e34036 (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.py | 2 | ||||
| -rw-r--r-- | wasp/boards/simulator/display.py | 6 | ||||
| -rw-r--r-- | wasp/clock.py | 6 | ||||
| -rw-r--r-- | wasp/drivers/cst816s.py | 51 | ||||
| -rw-r--r-- | wasp/flashlight.py | 34 | ||||
| -rw-r--r-- | wasp/manager.py | 74 | ||||
| -rw-r--r-- | wasp/testapp.py | 35 |
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) |
