diff --git a/wasp/boards/pinetime/manifest.py b/wasp/boards/pinetime/manifest.py index 9243d77..cb2d788 100644 --- a/wasp/boards/pinetime/manifest.py +++ b/wasp/boards/pinetime/manifest.py @@ -22,6 +22,7 @@ freeze('../..', manifest_240x240.manifest + 'gadgetbridge.py', 'ppg.py', 'shell.py', + 'motion.py', 'wasp.py', ), opt=3 diff --git a/wasp/boards/pinetime/watch.py.in b/wasp/boards/pinetime/watch.py.in index 91c59c3..8bd4a85 100644 --- a/wasp/boards/pinetime/watch.py.in +++ b/wasp/boards/pinetime/watch.py.in @@ -90,7 +90,7 @@ try: Signal(Pin('CHARGING', Pin.IN), invert=True), Signal(Pin('USB_PWR', Pin.IN), invert=True)) i2c = I2C(1, scl='I2C_SCL', sda='I2C_SDA') - accel = BMA421(i2c) + accel = BMA421(i2c, Pin('ACCEL_INT', Pin.IN)) hrs = HRS3300(i2c) touch = CST816S(i2c, Pin('TP_INT', Pin.IN), Pin('TP_RST', Pin.OUT, value=0), diff --git a/wasp/drivers/bma421.py b/wasp/drivers/bma421.py index 14562d4..6dbfe82 100644 --- a/wasp/drivers/bma421.py +++ b/wasp/drivers/bma421.py @@ -7,6 +7,8 @@ import bma42x import time +import motion +from machine import Pin # Sensor orientation definition. # The 6 most significant bits define the indexes of the x, y, and z values @@ -17,7 +19,7 @@ import time # Y index ───────────────┐ │ # X index ─────────────┐ │ │ # ├┐├┐├┐ -_DEFAULT_ORIENTATION = const(0b010010101) +_DEFAULT_ORIENTATION = const(0b010010000) # 1 = keep, 0 = negate │││ # X sign ───────────────────┘││ # Y sign ────────────────────┘│ @@ -28,13 +30,19 @@ class BMA421: .. automethod:: __init__ """ - def __init__(self, i2c, orientation=_DEFAULT_ORIENTATION): + def __init__(self, i2c, intr=None, orientation=_DEFAULT_ORIENTATION): """Configure the driver. :param machine.I2C i2c: I2C bus used to access the sensor. """ self._dev = bma42x.BMA42X(i2c) self._orientation = orientation + self._gesture_int = intr + self._gesture_event = motion.AccelGestureEvent.NONE + self.hardware_gesture_available = False + + if self._gesture_int != None: + self._gesture_int.irq(trigger=Pin.IRQ_FALLING, handler=self.handle_interrupt) def reset(self): """Reset and reinitialize the sensor.""" @@ -55,6 +63,36 @@ class BMA421: perf_mode=bma42x.CIC_AVG_MODE) dev.feature_enable(bma42x.STEP_CNTR, True) + # Set axes remapping + # This works only for hardware-based intelligence. + # Software readout is remapped manually in accel_xyz(). + dev.set_remap_axes(self._orientation) + + self.hardware_gesture_available = dev.get_chip_id() == bma42x.BMA425_CHIP_ID + + # Enable gesture interrupts + if self.hardware_gesture_available: + dev.set_int_pin_config(int_line=bma42x.INTR1_MAP, + edge_ctrl=bma42x.LEVEL_TRIGGER, + lvl=bma42x.ACTIVE_LOW, + od=bma42x.PUSH_PULL, + output_en=True, input_en=False) + dev.feature_enable(bma42x.WRIST_WEAR, True) + dev.map_interrupt(bma42x.INTR1_MAP, bma42x.WRIST_WEAR_INT, True) + + def handle_interrupt(self, pin_obj): + """Interrupt handler for gesture events originating from the sensor""" + self._dev.read_int_status() # TODO: Actually read status from the register + self._gesture_event = motion.AccelGestureEvent.WRIST_TILT + + def get_gesture_event(self): + """Receive the latest gesture event if any""" + return self._gesture_event + + def reset_gesture_event(self): + """Call after processing the gesture event""" + self._gesture_event = motion.AccelGestureEvent.NONE + @property def steps(self): """Report the number of steps counted.""" diff --git a/wasp/modules/bma42x-upy b/wasp/modules/bma42x-upy index b968b25..30b19fe 160000 --- a/wasp/modules/bma42x-upy +++ b/wasp/modules/bma42x-upy @@ -1 +1 @@ -Subproject commit b968b2530440afae8b555613e89b1240afcf4da2 +Subproject commit 30b19fec7c1d05abd533ce46dcbe2d1a38f56a0c diff --git a/wasp/motion.py b/wasp/motion.py new file mode 100644 index 0000000..f8cb0ee --- /dev/null +++ b/wasp/motion.py @@ -0,0 +1,7 @@ +from micropython import const + +class AccelGestureEvent(): + """Enumerated ids for accelerometer-based gesture events + """ + NONE = const(0) + WRIST_TILT = const(1) diff --git a/wasp/wasp.py b/wasp/wasp.py index fbb2f4f..fcebdc7 100644 --- a/wasp/wasp.py +++ b/wasp/wasp.py @@ -20,6 +20,7 @@ import micropython import sys import watch import widgets +import motion from apps.launcher import LauncherApp from apps.pager import PagerApp, CrashApp, NotificationApp @@ -157,6 +158,8 @@ class Manager(): def secondary_init(self): global free + watch.accel.reset() + if not self.app: # Register default apps if main hasn't put anything on the quick ring if not self.quick_ring: @@ -496,11 +499,16 @@ class Manager(): self.wake() if self.raise_wake: - now = rtc.get_uptime_ms() - if now >= self.accel_poll_expiry: - self.accel_poll_expiry = (now + self.accel_poll_ms) - if self._do_raise_wake(): + if watch.accel.hardware_gesture_available: + if watch.accel.get_gesture_event() == motion.AccelGestureEvent.WRIST_TILT: + watch.accel.reset_gesture_event() self.wake() + else: + now = rtc.get_uptime_ms() + if now >= self.accel_poll_expiry: + self.accel_poll_expiry = (now + self.accel_poll_ms) + if self._do_raise_wake(): + self.wake() def _do_raise_wake(self):