wasp-os/wasp/apps/heart.py
Daniel Thompson 92812e5ad2 apps: heart: Implement a debug mode to copy out raw data
Signed-off-by: Daniel Thompson <daniel@redfelineninja.org.uk>
2021-05-05 21:06:39 +01:00

128 lines
3.4 KiB
Python

# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2020 Daniel Thompson
"""Heart rate monitor
~~~~~~~~~~~~~~~~~~~~~
A graphing heart rate monitor using a PPG sensor.
.. figure:: res/HeartApp.png
:width: 179
This program also implements some (entirely optional) debug features to
store the raw heart data to the filesystem so that the samples can be used
to further refine the heart rate detection algorithm.
To enable the logging feature select the heart rate application using the
watch UI and then run the following command via wasptool:
.. code-block:: sh
./tools/wasptool --eval 'wasp.system.app.debug = True'
Once debug has been enabled then the watch will automatically log heart
rate data whenever the heart rate application is running (and only
when it is running). Setting the debug flag to False will disable the
logging when the heart rate monitor next exits.
Finally to download the logs for analysis try:
.. code-block:: sh
./tools/wasptool --pull hrs.data
"""
import wasp
import machine
import ppg
class HeartApp():
"""Heart rate monitor application."""
NAME = 'Heart'
def __init__(self):
self._debug = False
self._hrdata = None
def foreground(self):
"""Activate the application."""
wasp.watch.hrs.enable()
# There is no delay after the enable because the redraw should
# take long enough it is not needed
draw = wasp.watch.drawable
draw.fill()
draw.set_color(wasp.system.theme('bright'))
draw.string('PPG graph', 0, 6, width=240)
wasp.system.request_tick(1000 // 8)
self._hrdata = ppg.PPG(wasp.watch.hrs.read_hrs())
if self._debug:
self._hrdata.enable_debug()
self._x = 0
def background(self):
wasp.watch.hrs.disable()
self._hrdata = None
def _subtick(self, ticks):
"""Notify the application that its periodic tick is due."""
draw = wasp.watch.drawable
spl = self._hrdata.preprocess(wasp.watch.hrs.read_hrs())
if len(self._hrdata.data) >= 240:
draw.set_color(wasp.system.theme('bright'))
draw.string('{} bpm'.format(self._hrdata.get_heart_rate()),
0, 6, width=240)
# Graph is orange by default...
color = wasp.system.theme('spot1')
# If the maths goes wrong lets show it in the chart!
if spl > 100 or spl < -100:
color = 0xffff
if spl > 104 or spl < -104:
spl = 0
spl += 104
x = self._x
draw.fill(0, x, 32, 1, 208-spl)
draw.fill(color, x, 239-spl, 1, spl)
x += 2
if x >= 240:
x = 0
self._x = x
def tick(self, ticks):
"""This is an outrageous hack but, at present, the RTC can only
wake us up every 125ms so we implement sub-ticks using a regular
timer to ensure we can read the sensor at 24Hz.
"""
t = machine.Timer(id=1, period=8000000)
t.start()
self._subtick(1)
wasp.system.keep_awake()
while t.time() < 41666:
pass
self._subtick(1)
while t.time() < 83332:
pass
self._subtick(1)
t.stop()
del t
@property
def debug(self):
return self._debug
@debug.setter
def debug(self, value):
self._debug = value
if value and self._hrdata:
self._hrdata.enable_debug()