wasp-os/wasp/apps/testapp.py
Daniel Thompson 231f3b6fdd apps: software: Add an apps to enable/disable other apps
Currently wasp-os enables a narrow set of applications because we don't
want to consume RAM by importing the module and constructing the
application. We can improve on this situation by providing a small
(stateless) application that can be used to enable or diable applications.
This allows all the ROMed applications to be enabled using the GUI
without compromising on the ability to develop applications.

In fact this application significantlly reduces the RAM consumed in the
default case becasue the Self Test app does not need to maintain its
state.

Signed-off-by: Daniel Thompson <daniel@redfelineninja.org.uk>
2021-01-03 14:54:34 +00:00

267 lines
8.8 KiB
Python

# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2020 Daniel Thompson
"""Self Tests
~~~~~~~~~~~~~
"""
import wasp
import gc
import fonts
import icons
import machine
from apps.pager import PagerApp
class TestApp():
"""Simple test application.
.. figure:: res/SelfTestApp.png
:width: 179
Screenshot of the self test application
"""
NAME = 'Self Test'
ICON = icons.app
def __init__(self):
self.tests = ('Alarm', 'Button', 'Checkbox', 'Crash', 'Colours', 'Fill', 'Fill-H', 'Fill-V', 'Free Mem', 'Line', 'Notifications', 'RLE', 'String', 'Touch', 'Wrap')
self.test = self.tests[0]
self.scroll = wasp.widgets.ScrollIndicator()
self._checkbox = wasp.widgets.Checkbox(4, 104, 'Check me')
self._sliders = (
wasp.widgets.Slider(32, 10, 90, 0xf800),
wasp.widgets.Slider(64, 10, 140, 0x27e4),
wasp.widgets.Slider(32, 10, 190, 0x211f),
)
self._spinner = wasp.widgets.Spinner(90, 60, 0, 99)
def foreground(self):
"""Activate the application."""
self.on_screen = ( -1, -1, -1, -1, -1, -1 )
self._draw()
wasp.system.request_event(wasp.EventMask.TOUCH |
wasp.EventMask.SWIPE_UPDOWN |
wasp.EventMask.BUTTON)
def press(self, button, state):
draw = wasp.watch.drawable
if self.test == 'Alarm':
self._test_alarm()
elif self.test == 'Button':
draw.string('{}: {}'.format(button, state), 0, 108, width=240)
elif self.test == 'Crash':
self.crash()
elif self.test == 'String':
self._benchmark_string()
elif self.test == 'Touch':
draw.string('Button', 0, 108, width=240)
def swipe(self, event):
tests = self.tests
i = tests.index(self.test)
if event[0] == wasp.EventType.UP:
i += 1
if i >= len(tests):
i = 0
else:
i -= 1
if i < 0:
i = len(tests) - 1
self.test = tests[i]
self._draw()
def touch(self, event):
if self.test == 'Checkbox':
self._checkbox.touch(event)
elif self.test == 'Colours':
if event[2] > 90:
s = self._sliders[(event[2] - 90) // 50]
s.touch(event)
s.update()
self.scroll.draw()
self._update_colours()
elif self.test.startswith('Fill'):
self._benchmark_fill()
elif self.test == 'Notifications':
if self._spinner.touch(event):
notifications = wasp.system.notifications
if len(notifications) > self._spinner.value:
wasp.system.unnotify(
next(iter(notifications.keys())))
else:
wasp.system.notify(wasp.watch.rtc.get_uptime_ms(),
{
"src":"Hangouts",
"title":"A Name",
"body":"message contents"
})
elif self.test == 'RLE':
self._benchmark_rle()
elif self.test == 'String':
self._benchmark_string()
elif self.test == 'Touch':
wasp.watch.drawable.string('({}, {})'.format(
event[1], event[2]), 0, 108, width=240)
elif self.test == 'Wrap':
self._benchmark_wrap()
elif self.test == 'Line':
self._benchmark_line()
def _alarm(self):
wasp.system.wake()
wasp.system.switch(PagerApp('Alarm triggered'))
def _test_alarm(self):
def nop():
pass
now = wasp.watch.rtc.time()
wasp.system.set_alarm(now + 30, self._alarm)
wasp.system.set_alarm(now + 30, nop)
if not wasp.system.cancel_alarm(now + 30, nop):
bug()
wasp.watch.drawable.string("Done.", 12, 24+80)
def _benchmark_rle(self):
draw = wasp.watch.drawable
draw.fill(0, 0, 30, 240, 240-30)
self.scroll.draw()
t = machine.Timer(id=1, period=8000000)
t.start()
for i in range(0, 128, 16):
draw.blit(icons.software, i+16, i+32)
elapsed = t.time()
t.stop()
del t
draw.string('{}s'.format(elapsed / 1000000), 12, 24+192)
def _benchmark_fill(self):
draw = wasp.watch.drawable
draw.fill(0, 0, 30, 240, 240-30)
self.scroll.draw()
t = machine.Timer(id=1, period=8000000)
if self.test == 'Fill':
t.start()
draw.fill(0xffff, 60, 60, 120, 120)
elapsed = t.time()
elif self.test == 'Fill-H':
t.start()
for i in range(60, 180, 2):
draw.fill(0xffff, 60, i, 120, 1)
elapsed = t.time()
elif self.test == 'Fill-V':
t.start()
for i in range(60, 180, 2):
draw.fill(0xffff, i, 60, 1, 120)
elapsed = t.time()
t.stop()
del t
draw.string('{}s'.format(elapsed / 1000000), 12, 24+192)
def _benchmark_string(self):
draw = wasp.watch.drawable
draw.fill(0, 0, 30, 240, 240-30)
self.scroll.draw()
t = machine.Timer(id=1, period=8000000)
t.start()
draw.string("The quick brown", 12, 24+24)
draw.string("fox jumped over", 12, 24+48)
draw.string("the lazy dog.", 12, 24+72)
draw.string("0123456789", 12, 24+120)
draw.string('!"£$%^&*()', 12, 24+144)
elapsed = t.time()
t.stop()
del t
draw.string('{}s'.format(elapsed / 1000000), 12, 24+192)
def _benchmark_line(self):
draw = wasp.watch.drawable
# instead of calculating by trig functions, use LUT
points = (0, 50), (19, 46), (35, 35), (46, 19),
draw.fill(0, 70, 70, 100, 100)
self.scroll.draw()
t = machine.Timer(id=1, period=8000000)
t.start()
for x, y in points:
draw.line(120, 120, 120+x, 120+y, 4, 0xfb00) # red
draw.line(120, 120, 120+y, 120-x, 3, 0x07c0) # green
draw.line(120, 120, 120-x, 120-y, 5, 0x6b3f) # blue
draw.line(120, 120, 120-y, 120+x, 2, 0xffe0) # yellow
elapsed = t.time()
t.stop()
del t
draw.string('{}s'.format(elapsed / 1000000), 12, 24+192)
def _benchmark_wrap(self):
draw = wasp.watch.drawable
draw.fill(0, 0, 30, 240, 240-30)
self.scroll.draw()
t = machine.Timer(id=1, period=8000000)
t.start()
draw = wasp.watch.drawable
s = 'This\nis a very long string that will need to be wrappedinmultipledifferentways!'
chunks = draw.wrap(s, 240)
for i in range(len(chunks)-1):
sub = s[chunks[i]:chunks[i+1]].rstrip()
draw.string(sub, 0, 48+24*i)
elapsed = t.time()
t.stop()
del t
draw.string('{}s'.format(elapsed / 1000000), 12, 24+192)
def _draw(self):
"""Redraw the display from scratch."""
wasp.watch.display.mute(True)
draw = wasp.watch.drawable
draw.fill()
draw.set_font(fonts.sans24)
draw.string('{} test'.format(self.test),
0, 6, width=240)
if self.test == 'Alarm':
draw.string("Press button to", 12, 24+24)
draw.string("set alarm.", 12, 24+48)
elif self.test == 'Checkbox':
self._checkbox.draw()
elif self.test == 'Crash':
draw.string("Press button to", 12, 24+24)
draw.string("throw exception.", 12, 24+48)
elif self.test == 'Colours':
for s in self._sliders:
s.draw()
self._update_colours()
elif self.test == 'Free Mem':
if wasp.watch.free:
draw.string("Boot: {}".format(wasp.watch.free), 12, 3*24)
draw.string("Init: {}".format(wasp.free), 12, 4*24)
draw.string("Now: {}".format(gc.mem_free()), 12, 5*24)
gc.collect()
draw.string("GC: {}".format(gc.mem_free()), 12, 6*24)
else:
draw.string("Not supported", 12, 4*24)
elif self.test == 'Notifications':
self._spinner.value = len(wasp.system.notifications)
self._spinner.draw()
elif self.test == 'RLE':
draw.blit(self.ICON, 120-48, 120-32)
self.scroll.draw()
wasp.watch.display.mute(False)
def _update_colours(self):
draw = wasp.watch.drawable
r = self._sliders[0].value
g = self._sliders[1].value
b = self._sliders[2].value
rgb = (r << 11) + (g << 5) + b
draw.string('RGB565 #{:04x}'.format(rgb), 0, 6, width=240)
draw.fill(rgb, 60, 35, 120, 50)