diff --git a/README.rst b/README.rst index df68cee..a6b9f98 100644 --- a/README.rst +++ b/README.rst @@ -261,3 +261,7 @@ application (and the "blank" white screen is a torch application): .. image:: res/LevelApp.png :alt: Shows a time as words in the wasp-os simulator :width: 179 + +.. image:: res/BeaconApp.png + :alt: Flash the relatively powerful HRS LED repeatedly + :width: 179 \ No newline at end of file diff --git a/apps/Beacon.py b/apps/Beacon.py new file mode 100644 index 0000000..d8423cf --- /dev/null +++ b/apps/Beacon.py @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +# Copyright (C) 2021 Francesco Gazzetta +"""Beacon application +~~~~~~~~~~~~~~~~~~~~~ + +Flash the relatively powerful HRS LED repeatedly, mostly for signaling purposes. + +Frequency and intensity can be changed. + +The blinking is handled by the HRS, so this app consumes very little power. +With BLE and/or step counter disabled and blinking frequency set to the minimum, +the watch's battery will last for many days. + +.. figure:: res/BeaconApp.png + :width: 179 +""" + +import wasp +import machine +from micropython import const + +class BeaconApp(): + NAME = "Beacon" + # 2-bit RLE, 96x64, generated from res/beacon_icon.png, 336 bytes + ICON = ( + b'\x02' + b'`@' + b'?\xff\x11@\xfcB?\x1dB\x80z\x82B?\x1aA' + b'\x86A?\x18A\x88A?\t\xc0\x18\xc3\nA\x8aA' + b'\n\xc3=\xc5\x04N\x04\xc5?\x06\xc3\x02A\xcaA\x02' + b'\xc3?\x10A\xcaA?\x08\xcb\x02A\xc3@\x1eD\xc3' + b'\x80\xfc\x81\x02\xcc9\xcb\x01\x81\xc4D\xc4\x81\x01\xcc?' + b'\x06\x81\xcc\x81?\x0f\xc3\x01\x81\xcc\x81\x01\xc3?\x06\xc5' + b'\x04\x8e\x04\xc5=\xc3\t\x81\xc0z\xcc\x81\t@\x18C' + b'?\x07\x81\xcc\x81?\x12\x81\xce\x81?\x11\x81\xce\x81?' + b'\x11\x81\xce\x81?\x11\x81\xce\x81?\x11\x81\xce\x81?\x11' + b'\x81\xce\x81?\x11\x81\xce\x81?\x10\x81\xd0\x81?\x0f\x81' + b'\xd0\x81?\x0f\x92?\x0f\x81\x80\x81\x90\xc0\xfc\xc1?\x0f' + b'\xc1\x90\xc1?\x0f\xc1\x90\xc1?\x0e\xc1\x92\xc1?\r\xc1' + b'\x92\xc1?\r\xc1\x92\xc1?\r\xc1\x92\xc1?\r\xc1\x92' + b'\xc1?\r\xc1\x92\xc1?\r\xc1\x92\xc1?\x0c\xc1\x94\xc1' + b'?\x0b\xd6?\x0b\xc1@zT\xc1?\x0b\xc1T\xc1?' + b'\x0b\xc1T\xc1?\x0b\xc1T\xc1?\n\xc1V\xc1?\t' + b'\xc1V\xc1?\t\xc1V\xc1?\t\xc1V\xc1?\t\xc1' + b'V\xc1?\t\xc1V\xc1?\t\xc1V\xc1?\x08\xda?' + b'\x07\xc1\x98\xc1?\x07\xc1\x98\xc1?\x07\xc1\x98\xc1?\x07' + b'\xc1\x98\xc1?\x07\xc1\x98\xc1?\x06\xc1\x9a\xc1?\x05\xc1' + b'\x9a\xc1?\x05\xc1\x9a\xc1?\x05\xdc?\xff\x04' + ) + + + def __init__(self): + self._checkbox = wasp.widgets.Checkbox(10, 45, "Enable beacon") + self._slider_current = wasp.widgets.Slider(4, 10, 110, 0x27e4) + self._slider_wait_time = wasp.widgets.Slider(8, 10, 180) + + def foreground(self): + wasp.system.bar.clock = True + self._draw() + wasp.system.request_event(wasp.EventMask.TOUCH) + + def _draw(self): + draw = wasp.watch.drawable + draw.fill() + wasp.system.bar.draw() + self._checkbox.draw() + draw.string("Intensity:", 10, 85) + self._slider_current.draw() + draw.string("Frequency:", 10, 155) + self._slider_wait_time.draw() + self._draw_preview() + + def touch(self, event): + if self._checkbox.touch(event): + if self._checkbox.state: + wasp.watch.hrs.enable() + wasp.watch.hrs.set_hwt(self._slider_wait_time.value) + wasp.watch.hrs.set_drive(self._slider_current.value) + else: + wasp.watch.hrs.disable() + self._checkbox.update() + elif event[2] >= 180: + if self._slider_wait_time.touch(event): + wasp.watch.hrs.set_hwt(self._slider_wait_time.value) + self._slider_wait_time.update() + self._draw_preview() + elif event[2] >= 110: + if self._slider_current.touch(event): + wasp.watch.hrs.set_drive(self._slider_current.value) + self._slider_current.update() + self._draw_preview() + wasp.system.bar.update() + + def _draw_preview(self): + """ + Draw a dashed line representing intensity and frequency + with thickness and separation of dashes + """ + draw = wasp.watch.drawable + draw.fill(None, 10, 220, 227, 20) + x = 10 + while x < 220: + wasp.watch.drawable.fill(0x27e4, x, 227, 8, (self._slider_current.value + 1) * 3) + x += (8 - self._slider_wait_time.value) * 8 diff --git a/docs/apps.rst b/docs/apps.rst index 6432d3b..e6c0a63 100644 --- a/docs/apps.rst +++ b/docs/apps.rst @@ -45,6 +45,8 @@ Applications .. automodule:: apps.alarm +.. automodule:: Beacon + .. automodule:: apps.calc .. automodule:: apps.demo diff --git a/res/BeaconApp.png b/res/BeaconApp.png new file mode 100644 index 0000000..8fc4754 Binary files /dev/null and b/res/BeaconApp.png differ diff --git a/res/beacon_icon.png b/res/beacon_icon.png new file mode 100644 index 0000000..4bd99f9 Binary files /dev/null and b/res/beacon_icon.png differ diff --git a/wasp/boards/simulator/watch.py b/wasp/boards/simulator/watch.py index 900d1d6..860c414 100644 --- a/wasp/boards/simulator/watch.py +++ b/wasp/boards/simulator/watch.py @@ -159,6 +159,12 @@ class HRS(): self._i = 0 self._step = 1 + def read_reg(self, addr): + pass + + def write_reg(self, addr, val): + pass + def enable(self): pass @@ -178,6 +184,12 @@ class HRS(): return d + def set_drive(self, drive): + pass + + def set_hwt(self, t): + pass + backlight = Backlight() spi = SPI(0) spi.init(polarity=1, phase=1, baudrate=8000000) diff --git a/wasp/drivers/hrs3300.py b/wasp/drivers/hrs3300.py index 80c8df0..c6027c4 100644 --- a/wasp/drivers/hrs3300.py +++ b/wasp/drivers/hrs3300.py @@ -13,10 +13,13 @@ _I2CADDR = const(0x44) _ID = const(0x00) _ENABLE = const(0x01) _ENABLE_HEN = const(0x80) +_ENABLE_HWT = const(0x70) +_ENABLE_PDRIVE1 = const(0x08) _C1DATAM = const(0x08) _C0DATAM = const(0x09) _C0DATAH = const(0x0a) _PDRIVER = const(0x0c) +_PDRIVER_PDRIVE0 = const(0x40) _C1DATAH = const(0x0d) _C1DATAL = const(0x0e) _C0DATAL = const(0x0f) @@ -88,11 +91,40 @@ class HRS3300: self.write_reg(_HGAIN, hgain << 2) def set_drive(self, drive): + """ + Set LED drive current + + Parameters: + drive (int) LED drive current + 0 = 12.5 mA + 1 = 20 mA + 2 = 30 mA + 3 = 40 mA + """ en = self.read_reg(_ENABLE) pd = self.read_reg(_PDRIVER) - en = (en & 0xf7) | ((drive & 2) << 2) - pd = (pd & 0xbf) | ((drive & 1) << 6) + en = (en & ~_ENABLE_PDRIVE1 ) | ((drive & 2) << 2) + pd = (pd & ~_PDRIVER_PDRIVE0) | ((drive & 1) << 6) self.write_reg(_ENABLE, en) self.write_reg(_PDRIVER, pd) + + def set_hwt(self, t): + """ + Set wait time between each conversion cycle + + Parameters: + t (int) Wait time between each conversion cycle + 0 = 800 ms + 1 = 400 ms + 2 = 200 ms + 3 = 100 ms + 4 = 75 ms + 5 = 50 ms + 6 = 12.5 ms + 7 = 0 ms + """ + en = self.read_reg(_ENABLE) + en = (en & ~_ENABLE_HWT) | (t << 4) + self.write_reg(_ENABLE, en) diff --git a/wasp/widgets.py b/wasp/widgets.py index 556c7f5..9d80502 100644 --- a/wasp/widgets.py +++ b/wasp/widgets.py @@ -430,7 +430,9 @@ class Slider(): v = 0 elif v >= self._steps: v = self._steps - 1 + changed = self.value != v self.value = v + return changed class Spinner(): """A simple Spinner widget.