Compare commits

...

5 commits

Author SHA1 Message Date
c816d1db35 Re-introduce software-based gesture fallback
The algorithm still has to be adjusted for the new mapping.
2022-06-18 11:19:15 -04:00
a15cc6697d bma421: Flip all axes
This is what the hardware requires for gesture detection to work (all
clockwise directions should be positive, and counterclockwise directions
are negative).

TODO: Correct all software logic to match
2022-06-18 10:41:42 -04:00
6332f11502 Initial implementation of interrupt-based wrist tilt detection on BMA425 2022-06-18 10:41:33 -04:00
c08eb7c350 bma42x: Set hardware-based axes remapping 2022-06-17 16:44:57 -04:00
3cb60d7705 Initialize accelerometer during system init
It was originally only initialized in the step counter, but this won't
work when the step counter app is disabled.
2022-06-17 16:27:13 -04:00
6 changed files with 62 additions and 8 deletions

View file

@ -22,6 +22,7 @@ freeze('../..', manifest_240x240.manifest +
'gadgetbridge.py',
'ppg.py',
'shell.py',
'motion.py',
'wasp.py',
),
opt=3

View file

@ -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),

View file

@ -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."""

@ -1 +1 @@
Subproject commit b968b2530440afae8b555613e89b1240afcf4da2
Subproject commit 30b19fec7c1d05abd533ce46dcbe2d1a38f56a0c

7
wasp/motion.py Normal file
View file

@ -0,0 +1,7 @@
from micropython import const
class AccelGestureEvent():
"""Enumerated ids for accelerometer-based gesture events
"""
NONE = const(0)
WRIST_TILT = const(1)

View file

@ -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):