summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.rst12
-rw-r--r--res/app_icon.pngbin7124 -> 6996 bytes
-rw-r--r--res/demo_icon.pngbin0 -> 11056 bytes
-rwxr-xr-xtools/rle_encode.py110
-rw-r--r--wasp/apps/demo.py270
-rw-r--r--wasp/apps/gameoflife.py16
-rw-r--r--wasp/boards/dsd6/manifest.py1
-rw-r--r--wasp/boards/nitrogen/manifest.py2
-rw-r--r--wasp/boards/pinetime/manifest.py2
-rw-r--r--wasp/demo.py65
-rw-r--r--wasp/draw565.py36
-rw-r--r--wasp/icons.py100
12 files changed, 459 insertions, 155 deletions
diff --git a/README.rst b/README.rst
index f804034..9efa694 100644
--- a/README.rst
+++ b/README.rst
@@ -110,18 +110,6 @@ access the MicroPython REPL, although currently you must send ^C to
interrupt the program that updates the watch display. You can use
``tools/wasptool --console`` to access the MicroPython REPL.
-Just for fun try:
-
-.. code-block:: python
-
- ^C
- import demo
- demo.run()
- # After watching the demo for a bit...
- ^C
- wasp.app.draw(watch)
- wasp.system.run()
-
To set the time and restart the main application:
.. code-block:: python
diff --git a/res/app_icon.png b/res/app_icon.png
index 574f75f..438cded 100644
--- a/res/app_icon.png
+++ b/res/app_icon.png
Binary files differ
diff --git a/res/demo_icon.png b/res/demo_icon.png
new file mode 100644
index 0000000..7312a0b
--- /dev/null
+++ b/res/demo_icon.png
Binary files differ
diff --git a/tools/rle_encode.py b/tools/rle_encode.py
index 36ada32..6dccbd7 100755
--- a/tools/rle_encode.py
+++ b/tools/rle_encode.py
@@ -8,6 +8,109 @@ import sys
import os.path
from PIL import Image
+def clut8_rgb888(i):
+ """Reference CLUT for wasp-os.
+
+ Technically speaking this is not a CLUT because the we lookup the colours
+ algorithmically to avoid the cost of a genuine CLUT. The palette is
+ designed to be fairly easy to generate algorithmically.
+
+ The palette includes all 216 web-safe colours together 4 grays and
+ 36 additional colours that target "gaps" at the brighter end of the web
+ safe set. There are 11 greys (plus black and white) although two are
+ fairly close together.
+
+ :param int i: Index (from 0..255 inclusive) into the CLUT
+ :return: 24-bit colour in RGB888 format
+ """
+ if i < 216:
+ rgb888 = ( i % 6) * 0x33
+ rg = i // 6
+ rgb888 += (rg % 6) * 0x3300
+ rgb888 += (rg // 6) * 0x330000
+ elif i < 252:
+ i -= 216
+ rgb888 = 0x7f + (( i % 3) * 0x33)
+ rg = i // 3
+ rgb888 += 0x4c00 + ((rg % 4) * 0x3300)
+ rgb888 += 0x7f0000 + ((rg // 4) * 0x330000)
+ else:
+ i -= 252
+ rgb888 = 0x2c2c2c + (0x101010 * i)
+
+ return rgb888
+
+def clut8_rgb565(i):
+ """RBG565 CLUT for wasp-os.
+
+ This CLUT implements the same palette as :py:meth:`clut8_888` but
+ outputs RGB565 pixels.
+
+ .. note::
+
+ This function is unused within this file but needs to be
+ maintained alongside the reference clut so it is reproduced
+ here.
+
+ :param int i: Index (from 0..255 inclusive) into the CLUT
+ :return: 16-bit colour in RGB565 format
+ """
+ if i < 216:
+ rgb565 = (( i % 6) * 0x33) >> 3
+ rg = i // 6
+ rgb565 += ((rg % 6) * (0x33 << 3)) & 0x07e0
+ rgb565 += ((rg // 6) * (0x33 << 8)) & 0xf800
+ elif i < 252:
+ i -= 216
+ rgb565 = (0x7f + (( i % 3) * 0x33)) >> 3
+ rg = i // 3
+ rgb565 += ((0x4c << 3) + ((rg % 4) * (0x33 << 3))) & 0x07e0
+ rgb565 += ((0x7f << 8) + ((rg // 4) * (0x33 << 8))) & 0xf800
+ else:
+ i -= 252
+ gr6 = (0x2c + (0x10 * i)) >> 2
+ gr5 = gr6 >> 1
+ rgb565 = (gr5 << 11) + (gr6 << 5) + gr5
+
+ return rgb565
+
+class ReverseCLUT:
+ def __init__(self, clut):
+ l = []
+ for i in range(256):
+ l.append(clut(i))
+ self.clut = tuple(l)
+ self.lookup = {}
+
+ def __call__(self, rgb888):
+ """Compare rgb888 to every element of the CLUT and pick the
+ closest match.
+ """
+ if rgb888 in self.lookup:
+ return self.lookup[rgb888]
+
+ best = 200000
+ index = -1
+ clut = self.clut
+ r = rgb888 >> 16
+ g = (rgb888 >> 8) & 0xff
+ b = rgb888 & 0xff
+
+ for i in range(256):
+ candidate = clut[i]
+ rd = r - (candidate >> 16)
+ gd = g - ((candidate >> 8) & 0xff)
+ bd = b - (candidate & 0xff)
+ # This is the Euclidian distance (squared)
+ distance = rd * rd + gd * gd + bd * bd
+ if distance < best:
+ best = distance
+ index = i
+
+ self.lookup[rgb888] = index
+ #print(f'# #{rgb888:06x} -> #{clut8_rgb888(index):06x}')
+ return index
+
def varname(p):
return os.path.basename(os.path.splitext(p)[0])
@@ -62,15 +165,18 @@ def encode_2bit(im):
assert(im.width <= 255)
assert(im.height <= 255)
+ full_palette = ReverseCLUT(clut8_rgb888)
+
rle = []
rl = 0
px = pixels[0, 0]
- palette = [0, 0xfc, 0x2d, 0xff]
+ # black, grey25, grey50, white
+ palette = [0, 254, 219, 215]
next_color = 1
def encode_pixel(px, rl):
nonlocal next_color
- px = (px[0] & 0xe0) | ((px[1] & 0xe0) >> 3) | ((px[2] & 0xc0) >> 6)
+ px = full_palette((px[0] << 16) + (px[1] << 8) + px[2])
if px not in palette:
rle.append(next_color << 6)
rle.append(px)
diff --git a/wasp/apps/demo.py b/wasp/apps/demo.py
new file mode 100644
index 0000000..17b31c6
--- /dev/null
+++ b/wasp/apps/demo.py
@@ -0,0 +1,270 @@
+# SPDX-License-Identifier: LGPL-3.0-or-later
+# Copyright (C) 2020 Daniel Thompson
+
+"""Logo demo for PineTime
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This demo is simply an alternating sweep of the Pine64 and
+MicroPython logos. It cycles through a variety of colours
+and swaps between the logos every 5 images (so if you change
+anything make sure len(colors) is not a multiple of 5).
+"""
+
+import wasp
+import icons
+
+# 2-bit RLE, generated from res/demo_icon.png, 292 bytes
+demo_icon = (
+ b'\x02'
+ b'`@'
+ b'.\xc1?\x1f\xc3?\x1d\xc5?\x1b\xc7?\x19\xc9?\x17'
+ b'\xcb?\x16\xcc?\x10\xc1\x06\xc8\x06\xc1?\n\xc4\x06\xc4'
+ b'\x06\xc3?\n\xc6\x0c\xc6?\x08\xc9\x08\xc8?\x08\xc7\x0c'
+ b'\xc7?\x06\xc6\x06\xc4\x06\xc5?\x06\xc4\x05\xc9\x06\xc3?'
+ b'\x06\xc1\x06\xce\x05\xc2?\n\xd2?\x0c\xd7?\x08\xdc?'
+ b'\x05\xdc\x05\xc18\xc3\x05\xd7\x06\xc38\xc5\x06\xd2\x05\xc6'
+ b'8\xc7\x06\xce\x05\xc88\xca\x05\xc9\x06\xca8\xcc\x06\xc4'
+ b'\x06\xcc8\xce\x0b\xcf8\xd0\x08\xd08\xce\x0b\xcf8\xcc'
+ b'\x06\xc4\x06\xcc8\xc9\x06\xc9\x06\xca8\xc7\x06\xcd\x06\xc8'
+ b'8\xc5\x06\xd2\x06\xc58\xc3\x05\xd7\x06\xc3>\xdb\x06\xc1'
+ b'<\xe08\xc2\x06\xdf\x07\xc12\xc3\x06\xdb\x06\xc42\xc6'
+ b'\x06\xd6\x06\xc54\xc7\x06\xd1\x06\xc84\xca\x05\xcd\x06\xc9'
+ b'6\xcb\x06\xc8\x05\xcc6\xcd\x06\xc3\x06\xcd7\xd0\n\xcf'
+ b'8\xd0\x08\xd08\xce\x05\xc1\x06\xcd:\xca\x06\xc5\x06\xcb'
+ b':\xc8\x06\xca\x05\xc8<\xc5\x05\xcf\x06\xc5<\xc3\x05\xd3'
+ b'\x06\xc2?\x04\xd8?\x07\xdc?\x05\xdb?\x08\xd7?\r'
+ b'\xd2?\x11\xce?\x15\xc9?\x1a\xc5?\x1d\xc3?\x1e\xc3'
+ b'?\x1e\xc3?\x1e\xc3?\x1e\xc3?\x1e\xc3?\x1e\xc3?'
+ b'Q'
+)
+
+colors = (
+ 0xffff,
+ 0xf800, # red
+ 0xffff,
+ 0xffe0, # yellow
+ 0xffff,
+ 0x07e0, # green
+ 0xffff,
+ 0x07ff, # cyan
+ 0xffff,
+ 0x001f, # blue
+ 0xffff,
+ 0xf81f, # magenta
+ )
+
+class Hack:
+ """wasptool uses class (starting in column 0) as a clue for chunk at a
+ time transmission. Hence we use fake classes to demark places it is safe
+ to split an evaluation.
+ """
+ pass
+
+# 1-bit RLE, generated from res/pine64.png, 961 bytes
+pine64 = (
+ 240, 240,
+ b'x\x01\xee\x03\xec\x05\xea\x07\xe8\t\xe6\x0b\xe4\r\xe2\x0f'
+ b'\xe0\x11\xde\x13\xdc\x15\xda\x17\xd8\x19\xd6\x1b\xd4\x1d\xd2\x1f'
+ b"\xd1 \xcf!\xce#\xcc%\xca'\xc8)\xc6+\xc4-"
+ b"\xc3-\xc6'\xcb#\xd0\x1d\xb6\x02\x1d\x19\x1b\x03\x99\x05"
+ b'\x1e\x13\x1c\x05\x99\x08\x1d\x0f\x1c\x08\x98\n\x1e\t\x1d\n'
+ b'\x97\r\x1e\x05\x1c\r\x97\x10:\x10\x96\x126\x12\x95\x15'
+ b'1\x15\x95\x17-\x18\x93\x1b(\x1a\x93\x1d$\x1c\x93\x1e'
+ b'!\x1f\x91\x1d%\x1d\x91\x1b*\x1a\x91\x19.\x19\x8f\x17'
+ b'\x19\x01\x19\x17\x8f\x15\x19\x05\x19\x15\x8f\x13\x19\t\x1a\x13'
+ b'\x8d\x12\x19\r\x1a\x11\x8d\x10\x18\x12\x1a\x10\x8c\r\x19\x17'
+ b'\x19\x0e\x8b\x0c\x19\x1b\x19\x0c\x8b\n\x19\x1f\x1a\n\x89\t'
+ b'\x18$\x1a\x08\x89\x07\x18)\x19\x06\x89\x04\x19-\x19\x05'
+ b'\x87\x03\x191\x19\x03\x87\x01\x186\x19\x01\x9e;\xb3?'
+ b'\xafC\xabG\xa6L\xa2Q\x9dU\x98Z\x94^\x90c'
+ b'\x8bg\x87k\x85kn\x01\x18f\x1a\x01V\x03\x19a'
+ b'\x1a\x03V\x05\x19]\x1a\x05V\x07\x19Y\x19\x08V\n'
+ b'\x18T\x1a\nV\x0c\x19O\x1a\x0cV\x0e\x19K\x19\x0f'
+ b'V\x11\x18G\x19\x11V\x13\x18B\x1a\x13V\x16\x18='
+ b'\x19\x16V\x18\x189\x19\x18V\x1a\x185\x19\x1aV\x1c'
+ b"\x181\x19\x1cV\x1f\x18+\x19\x1fV!\x18'\x19!"
+ b'V#\x18#\x19#V%\x18\x1f\x18&V(\x17\x1a'
+ b'\x19(V*\x18\x15\x19*V,\x18\x11\x18-V/'
+ b'\x17\r\x18/V1\x17\x08\x191V4\x17\x03\x184'
+ b'V6.6V8*8V:&:V= ='
+ b'V<"<V:&:V7+8V505'
+ b'V3\x19\x01\x1a3V0\x1a\x05\x1b0V.\x19\x0b'
+ b"\x1a.V,\x19\x0f\x1a,V)\x1a\x13\x1b)V'"
+ b"\x1a\x17\x1b'V%\x19\x1d\x1a%V#\x19!\x1a#"
+ b'V \x1a%\x1b V\x1e\x1a)\x1b\x1eV\x1c\x1a.'
+ b'\x1a\x1cV\x19\x1b2\x1b\x19V\x17\x1a7\x1b\x17V\x14'
+ b'\x1b<\x1a\x15V\x12\x1b@\x1b\x12V\x10\x1aE\x1b\x10'
+ b'V\x0e\x1aI\x1b\x0eV\x0b\x1bM\x1c\x0bV\t\x1bQ'
+ b'\x1c\tV\x07\x1aW\x1b\x07V\x04\x1b[\x1b\x05V\x02'
+ b'\x1b_\x1c\x02qc\x8ai\x85m\x81q}uyz'
+ b'vyZ\x03\x1cu\x1d\x03=\x04\x1cq\x1d\x04>\x06'
+ b'\x1cm\x1d\x06?\x08\x1ch\x1c\x08@\n\x1cd\x1c\n'
+ b'A\x0c\x1b_\x1c\x0cB\x0e\x1b[\x1c\x0eB\x11\x1bV'
+ b'\x1b\x11C\x12\x1bR\x1b\x12D\x14\x1bM\x1c\x14E\x16'
+ b'\x1aI\x1b\x16F\x18\x1aE\x1b\x18G\x1a\x1a?\x1b\x1a'
+ b'H\x1c\x1a;\x1b\x1cI\x1e\x197\x1a\x1eJ \x193'
+ b'\x1a J"\x1a-\x1b!L$\x19)\x1a$L&'
+ b"\x19%\x1a&M(\x18!\x1a'N*\x19\x1c\x19*"
+ b'O+\x19\x18\x19+P.\x18\x13\x19.Q/\x18\x0f'
+ b'\x19/R2\x18\n\x182S3\x18\x05\x193T5'
+ b'\x18\x01\x195T8,8U9(9V<"<'
+ b'W< <X:$:Y7(7Z4-5'
+ b'Z222[/\x1a\x01\x1b/\\-\x19\x06\x1b-'
+ b"])\x1a\x0b\x1b)^'\x1a\x0f\x1b'_$\x1a\x13"
+ b'\x1b$`!\x1a\x19\x1b!a\x1e\x1a\x1d\x1b\x1eb\x1c'
+ b'\x1a!\x1b\x1cc\x19\x1a%\x1b\x19d\x16\x1a*\x1c\x16'
+ b'd\x14\x1a/\x1b\x14e\x11\x1a3\x1b\x11f\x0f\x1a7'
+ b'\x1b\x0fg\x0b\x1a<\x1c\x0bh\t\x1a@\x1c\ti\x06'
+ b'\x1aE\x1b\x06j\x03\x1bI\x1c\x03\x86M\xa0S\x9bW'
+ b'\x97[\x93_\x8ee\x89i\x85m\x85i\x89e\x8d`'
+ b'\x93[\x97W\x9bS\x9fN\xa5I\xa9E\xadA\xb1<'
+ b'\xb68\xbb3\xbf/\xc3+\xc7&\xcd!\xd1\x1d\xd5\x19'
+ b'\xda\x13\xdf\x0f\xe2\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c'
+ b'\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c'
+ b'\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c'
+ b'\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c\xe4\x0c'
+ b's'
+)
+
+class Hack:
+ pass
+
+# 1-bit RLE, generated from res/micropython.png, 1491 bytes
+micropython = (
+ 240, 240,
+ b'\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00'
+ b'\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\x1fc'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!c\tc!c\tc!c\tc!c'
+ b'\tc!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\t-\t-'
+ b'\t-!-\t-\t-\t-!-\tc\t-'
+ b'!-\tc\t-!-\tc\t-!-\tc'
+ b'\t-!-\tc\t-!-\tc\t-!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t\x12\x0c\x0f!-'
+ b'\tc\t\x12\x0c\x0f!-\tc\t-!-\tc'
+ b'\t-!-\tc\t-!-\tc\t-!-'
+ b'\tc\t-!-\tc\t-!-\tc\t-'
+ b'!-\tc\t-!-\tc\t-!-\tc'
+ b'\t-!-\tc\t-!-\tc\t-!-'
+ b'\tc\t-!-\tc\t-!-\tc\t-'
+ b'!-\tc\t-!-\tc\t-!-\tc'
+ b'\t-\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00'
+ b'\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00'
+ b'\xff\x00\x11'
+)
+class DemoApp():
+ """Application for live demos.
+
+ Start this to give the watch something "interesting" to do when talking
+ over demos!
+ """
+ NAME = 'Demo'
+ ICON = demo_icon
+
+ def __init__(self):
+ self._logo = pine64
+ self._color = 0
+ self._i = 0
+
+ def foreground(self):
+ """Draw the first frame and establish the tick."""
+ self._draw()
+ wasp.system.request_tick(2000)
+
+ def tick(self, ticks):
+ """Handle the tick."""
+ self._draw()
+ wasp.system.keep_awake()
+
+ def _draw(self):
+ """Draw the next frame."""
+ draw = wasp.watch.drawable
+
+ if self._i < 5:
+ self._i += 1
+ else:
+ self._i = 0
+ if self._logo == pine64:
+ self._logo = micropython
+ else:
+ self._logo = pine64
+ draw.fill()
+ draw.rleblit(self._logo, fg=colors[self._color])
+ self._color += 1
+ if self._color >= len(colors):
+ self._color = 0
diff --git a/wasp/apps/gameoflife.py b/wasp/apps/gameoflife.py
index 080c214..f1f1dbe 100644
--- a/wasp/apps/gameoflife.py
+++ b/wasp/apps/gameoflife.py
@@ -36,11 +36,11 @@ def xorshift12(v: int) -> int:
@micropython.viper
def get_color(v: int) -> int:
- r = v >> 10
- g = (v >> 8) & 7
- b = (v >> 5) & 3
-
- return (r << 13) | (g << 7) | (b << 1) | 0x9c73
+ """Convert a 12-bit number into a reasonably bright RGB565 pixel"""
+ rgb = v ^ (v << 4)
+ while 0 == (rgb & 0xc710):
+ rgb += 0x2104
+ return rgb
@micropython.viper
def get_cell(board, stride: int, x: int, y: int) -> bool:
@@ -118,11 +118,11 @@ def game_of_life(b, xmax: int, ymax: int, nb):
icon = (
b'\x02'
b'`@'
- b'?\xff\xff\xee@\xd7B\x02B\x02B?\x16L?\x15'
+ b'?\xff\xff\xee@\xf8B\x02B\x02B?\x16L?\x15'
b'L?\x16B\x02B\x02B?\x1bB?\x1eD?\x1d'
- b'D?\x1eB?\x17\x80\xbe\x82\x02\x82\x06\x82\x02\x82?'
+ b'D?\x1eB?\x17\x80\xee\x82\x02\x82\x06\x82\x02\x82?'
b'\x0e\x88\x04\x88?\r\x88\x04\x88?\x0e\x82\x02\x82\x06B'
- b'\x02\x82?\x03\xc0\x97\xc2\x02\xc2\x02\xc2\x02\xc2\x02\xc2\x02'
+ b'\x02\x82?\x03\xc0\x89\xc2\x02\xc2\x02\xc2\x02\xc2\x02\xc2\x02'
b'\xc2\x02\xc2\x02\xc2\x02\xc2\x02\xc2\x02\xc25\xec4\xec5'
b'\xc2\x02\xc2\x02\xc2\x02\xc2\x02\xc2\x02\xc2\x02\xc2\x02\xc2\x02'
b'\xc2\x02\xc2\x02\xc2*B\x02B\x12\xc2\x06B\x06\xc2\x12'
diff --git a/wasp/boards/dsd6/manifest.py b/wasp/boards/dsd6/manifest.py
index bee48c0..c5befba 100644
--- a/wasp/boards/dsd6/manifest.py
+++ b/wasp/boards/dsd6/manifest.py
@@ -3,7 +3,6 @@
freeze('../..',
(
- 'demo.py',
'drivers/battery.py',
'drivers/signal.py',
'drivers/vibrator.py',
diff --git a/wasp/boards/nitrogen/manifest.py b/wasp/boards/nitrogen/manifest.py
index b17711b..e7f3503 100644
--- a/wasp/boards/nitrogen/manifest.py
+++ b/wasp/boards/nitrogen/manifest.py
@@ -3,12 +3,10 @@
freeze('../..',
(
- 'demo.py',
'drivers/battery.py',
'drivers/signal.py',
'drivers/st7789.py',
'drivers/vibrator.py',
- 'logo.py',
),
opt=3
)
diff --git a/wasp/boards/pinetime/manifest.py b/wasp/boards/pinetime/manifest.py
index d39ed05..f7cb9d9 100644
--- a/wasp/boards/pinetime/manifest.py
+++ b/wasp/boards/pinetime/manifest.py
@@ -12,7 +12,6 @@ freeze('../..',
'apps/stopwatch.py',
'apps/testapp.py',
'boot.py',
- 'demo.py',
'draw565.py',
'drivers/battery.py',
'drivers/cst816s.py',
@@ -25,7 +24,6 @@ freeze('../..',
'fonts/sans24.py',
'fonts/sans36.py',
'icons.py',
- 'logo.py',
'shell.py',
'wasp.py',
'widgets.py',
diff --git a/wasp/demo.py b/wasp/demo.py
deleted file mode 100644
index a16c306..0000000
--- a/wasp/demo.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# SPDX-License-Identifier: LGPL-3.0-or-later
-# Copyright (C) 2020 Daniel Thompson
-
-#
-# Logo demo for PineTime
-#
-# This demo is simply an alternating sweep of the Pine64 and
-# MicroPython logos. It cycles through a variety of colours
-# and swaps between the logos every 5 images (so make sure
-# len(colors) is not a multiple of 5 ;-) ).
-#
-
-import watch, logo, time, gc
-
-colors = (
- 0xffff,
- 0xf800, # red
- 0xffff,
- 0xffe0, # yellow
- 0xffff,
- 0x07e0, # green
- 0xffff,
- 0x07ff, # cyan
- 0xffff,
- 0x001f, # blue
- 0xffff,
- 0xf81f, # magenta
- )
-
-def textdemo():
- watch.display.fill(0)
- draw = watch.drawable
- draw.string("The quick brown", 12, 24)
- draw.string("fox jumped over", 12, 48)
- draw.string("the lazy dog.", 12, 72)
- time.sleep(2)
- draw.string("0123456789", 12, 120)
- draw.string('!"£$%^&*()', 12, 144)
- time.sleep(3)
-
-def run():
- l = logo.pine64
- i = 0
-
- watch.display.poweron()
- watch.backlight.set(2)
-
- while True:
- for c in colors:
- if i == 2:
- textdemo()
- if i < 5:
- i += 1
- else:
- i = 0
- if l == logo.pine64:
- l = logo.micropython
- else:
- l = logo.pine64
- watch.display.fill(0)
-
- watch.drawable.rleblit(l, fg=c)
- time.sleep(2)
- gc.collect()
-
diff --git a/wasp/draw565.py b/wasp/draw565.py
index a69e526..21b23ed 100644
--- a/wasp/draw565.py
+++ b/wasp/draw565.py
@@ -35,15 +35,25 @@ def _bitblit(bitbuf, pixels, bgfg: int, count: int):
pxp += 1
@micropython.viper
-def _expand_rgb(eightbit: int) -> int:
- r = eightbit >> 5
- r = (r << 2) | (r >> 1)
- g = (eightbit >> 2) & 7
- g *= 9
- b = eightbit & 3
- b *= 10
-
- return (r << 11) | (g << 5) | b
+def _clut8_rgb565(i: int) -> int:
+ if i < 216:
+ rgb565 = (( i % 6) * 0x33) >> 3
+ rg = i // 6
+ rgb565 += ((rg % 6) * (0x33 << 3)) & 0x07e0
+ rgb565 += ((rg // 6) * (0x33 << 8)) & 0xf800
+ elif i < 252:
+ i -= 216
+ rgb565 = (0x7f + (( i % 3) * 0x33)) >> 3
+ rg = i // 3
+ rgb565 += ((0x4c << 3) + ((rg % 4) * (0x33 << 3))) & 0x07e0
+ rgb565 += ((0x7f << 8) + ((rg // 4) * (0x33 << 8))) & 0xf800
+ else:
+ i -= 252
+ gr6 = (0x2c + (0x10 * i)) >> 2
+ gr5 = gr6 >> 1
+ rgb565 = (gr5 << 11) + (gr6 << 5) + gr5
+
+ return rgb565
@micropython.viper
def _fill(mv, color: int, count: int, offset: int):
@@ -179,11 +189,11 @@ class Draw565(object):
display.set_window(x, y, sx, sy)
- if sx <= (len(display.linebuffer) / 2) and not bool(sy & 1):
+ if sx <= (len(display.linebuffer) // 4) and not bool(sy & 1):
sx *= 2
- sy /= 2
+ sy //= 2
- palette = array.array('H', (0, 0xfffe, 0x7bef, 0xffff))
+ palette = array.array('H', (0, 0x4a69, 0x7bef, 0xffff))
next_color = 1
rl = 0
buf = memoryview(display.linebuffer)[0:2*sx]
@@ -204,7 +214,7 @@ class Draw565(object):
if op >= 255:
continue
else:
- palette[next_color] = _expand_rgb(op)
+ palette[next_color] = _clut8_rgb565(op)
if next_color < 3:
next_color += 1
else:
diff --git a/wasp/icons.py b/wasp/icons.py
index 9bfa92a..dec982a 100644
--- a/wasp/icons.py
+++ b/wasp/icons.py
@@ -21,10 +21,10 @@ bomb = (
app = (
b'\x02'
b'`@'
- b'\x1e@md<d<d;f?X\xec2\xf0/'
+ b'\x1e@\x81d<d<d;f?X\xec2\xf0/'
b'\xf2-\xf4,\xc3.\xc3,\xc3.\xc3,\xc3.\xc3,'
- b'\xc3.\xc3,\xc3.\xc3,\xc3\x0c\x80\xfc\x83\x10\xc0]'
- b'\xc3\x0c@\xffC,C\n\x87\x0c\xc7\nC,C\t'
+ b'\xc3.\xc3,\xc3.\xc3,\xc3\x0c\x80\xd2\x83\x10\xc0C'
+ b'\xc3\x0c@\xd7C,C\n\x87\x0c\xc7\nC,C\t'
b'\x83\x02\x84\n\xc4\x02\xc3\tC,C\x08\x82\x07\x82\x08'
b'\xc2\x07\xc2\x08C,C\x07\x82\t\x82\x06\xc2\t\xc2\x07'
b'C,C\x06\x82\x0b\x82\x04\xc2\x0b\xc2\x06C,C\x06'
@@ -36,7 +36,7 @@ app = (
b'C+D\x08\x82\t\x82\x04\xc2\t\xc2\x08C*E\t'
b'\x8c\x04\xcc\tC*E\n\x8b\x04\xcb\nC*E.'
b'C*E.C*E.C*E.C*E\n'
- b'\x80\xe9\x8b\x04\xc0o\xcb\nC+D\t\x8c\x04\xcc\t'
+ b'\x80\xbb\x8b\x04\xc0X\xcb\nC+D\t\x8c\x04\xcc\t'
b'C,C\x08\x82\t\x82\x04\xc2\t\xc2\x08C,C\x07'
b'\x82\n\x82\x04\xc2\n\xc2\x07C,C\x06\x82\x0b\x82\x04'
b'\xc2\x0b\xc1\x07C,C\x06\x82\x0b\x82\x04\xc2\x0b\xc2\x06'
@@ -49,14 +49,14 @@ app = (
b'C,C\n\x86\x0e\xc6\nC,C\x0c\x83\x10\xc3\x0c'
b'C,C.C,C.C,C.C,C.'
b'C,C.C,t-r/p2l?X@'
- b'mf;d<d<d\x1e'
+ b'\x81f;d<d<d\x1e'
)
# 2-bit RLE, generated from res/clock_icon.png, 288 bytes
clock = (
b'\x02'
b'`@'
- b'?\xff\xff\xff\xff\xff\xff\x8e@\xb6F\r\xc6!E\x0b'
+ b'?\xff\xff\xff\xff\xff\xff\x8e@\xacF\r\xc6!E\x0b'
b'\xc8\x0cH\x0b\xca\x1dI\x07\xcc\nH\n\xcc\x1bK\x06'
b'\xce\x08C\x02C\n\xc4\x05\xc4\x1aD\x03D\x06\xc2\x08'
b'\xc4\rC\t\xc4\x07\xc3\x19D\x05D\x10\xc4\x0cC\t'
@@ -76,62 +76,62 @@ clock = (
b'E\t\xcf?\xff\xff\xff\xff\xff\xff\xff\xffk'
)
-# 2-bit RLE, generated from res/settings_icon.png, 472 bytes
+# 2-bit RLE, generated from res/settings_icon.png, 468 bytes
settings = (
b'\x02'
b'`@'
- b'\x1e@md<d<d;f?X\xec2\xf0/'
- b'\xf2-\xf4,\xc3.\xc3,\xc3.\xc3,\xc3.\xc3,'
- b'\xc3\x14\x80\xb7\x86\x14\xc3,\xc3\x13\x88\x13\xc3,\xc3\x13'
- b'\x88\x13\xc3,\xc3\x12\x83\x04\x83\x12\xc3,\xc3\n\x84\x04'
- b'\x83\x04\x83\x04\x84\n\xc3,\xc3\t\x86\x01\x85\x04\x85\x01'
- b'\x86\t\xc3,\xc3\x08\x8c\x05\x8d\x08\xc3,\xc3\x07\x84\x02'
- b'\x86\x08\x86\x02\x84\x07\xc3,\xc3\x07\x83\x05\x81\x0e\x81\x05'
- b'\x83\x07\xc3,\xc3\x07\x83\x1a\x83\x07\xc3,\xc3\x07\x84\x18'
- b'\x84\x07\xc3,\xc3\x08\x83\n\xc0o\xc4\n\x83\x08@\xff'
- b'C,C\t\x83\x06\xca\x06\x83\tC,C\x08\x83\x06'
- b'\xcc\x06\x83\x08C,C\x08\x83\x05\xc4\x06\xc4\x05\x83\x08'
- b'C+D\x06\x85\x04\xc4\x08\xc4\x04\x85\x06C*E\x04'
- b'\x86\x05\xc3\n\xc3\x05\x86\x04C*E\x03\x87\x05\xc2\x0c'
- b'\xc2\x05\x87\x03C*E\x03\x83\x08\xc3\x0c\xc3\x08\x83\x03'
- b'C*E\x03\x83\x08\xc3\x0c\xc3\x08\x83\x03C*E\x03'
- b'\x83\x08\xc3\x0c\xc3\x08\x83\x03C*E\x03\x83\x08\xc3\x0c'
- b'\xc3\x08\x83\x03C*E\x03\x86\x06\xc2\x0c\xc2\x05\x87\x03'
- b'C+D\x04\x86\x05\xc3\n\xc3\x05\x86\x04C,C\x05'
- b'\x86\x04\xc4\x08\xc4\x04\x85\x06C,C\x08\x83\x05\xc4\x06'
- b'\xc4\x05\x83\x08C,C\x08\x83\x06\xcc\x06\x83\x08C,'
- b'C\t\x83\x06\xca\x06\x83\tC,C\x08\x83\n\xc4\n'
- b'\x83\x08C,C\x07\x84\x18\x84\x07C,C\x07\x83\x1a'
- b'\x83\x07C,C\x07\x83\x05\x81\x0e\x81\x05\x83\x07C,'
- b'C\x07\x84\x03\x85\x08\x86\x02\x84\x07C,C\x08\x8d\x04'
- b'\x8d\x08C,C\t\x86\x01\x85\x04\x85\x01\x86\tC,'
- b'C\n\x84\x04\x83\x04\x83\x04\x84\nC,C\x12\x83\x04'
- b'\x83\x12C,C\x13\x88\x13C,C\x13\x88\x13C,'
- b'C\x14\x86\x14C,C.C,C.C,C.'
- b'C,t-r/p2l?X\x80m\xa6;\xa4'
- b'<\xa4<\xa4\x1e'
+ b'\x1e\xa4<\xa4<\xa4;\xa6?X\xec2\xf0/\xf2-'
+ b'\xf4,\xc3.\xc3,\xc3.\xc3,\xc3.\xc3,\xc3\x14'
+ b'@\xadF\x14\xc3,\xc3\x13H\x13\xc3,\xc3\x13H\x13'
+ b'\xc3,\xc3\x12C\x04C\x12\xc3,\xc3\nD\x04C\x04'
+ b'C\x04D\n\xc3,\xc3\tF\x01E\x04E\x01F\t'
+ b'\xc3,\xc3\x08L\x05M\x08\xc3,\xc3\x07D\x02F\x08'
+ b'F\x02D\x07\xc3,\xc3\x07C\x05A\x0eA\x05C\x07'
+ b'\xc3,\xc3\x07C\x1aC\x07\xc3,\xc3\x07D\x18D\x07'
+ b'\xc3,\xc3\x08C\n\x80\xdd\x84\nC\x08\xc3,\xc3\t'
+ b'C\x06\x8a\x06C\t\xc3,\xc3\x08C\x06\x8c\x06C\x08'
+ b'\xc3,\xc3\x08C\x05\x84\x06\x84\x05C\x08\xc3+\xc4\x06'
+ b'E\x04\x84\x08\x84\x04E\x06\xc3*\xc5\x04F\x05\x83\n'
+ b'\x83\x05F\x04\xc3*\xc5\x03G\x05\x82\x0c\x82\x05G\x03'
+ b'\xc3*\xc5\x03C\x08\x83\x0c\x83\x08C\x03\xc3*\xc5\x03'
+ b'C\x08\x83\x0c\x83\x08C\x03\xc3*\xc5\x03C\x08\x83\x0c'
+ b'\x83\x08C\x03\xc3*\xc5\x03C\x08\x83\x0c\x83\x08C\x03'
+ b'\xc3*\xc5\x03F\x06\x82\x0c\x82\x05G\x03\xc3+\xc4\x04'
+ b'F\x05\x83\n\x83\x05F\x04\xc3,\xc3\x05F\x04\x84\x08'
+ b'\x84\x04E\x06\xc3,\xc3\x08C\x05\x84\x06\x84\x05C\x08'
+ b'\xc3,\xc3\x08C\x06\x8c\x06C\x08\xc3,\xc3\tC\x06'
+ b'\x8a\x06C\t\xc3,\xc3\x08C\n\x84\nC\x08\xc3,'
+ b'\xc3\x07D\x18D\x07\xc3,\xc3\x07C\x1aC\x07\xc3,'
+ b'\xc3\x07C\x05A\x0eA\x05C\x07\xc3,\xc3\x07D\x03'
+ b'E\x08F\x02D\x07\xc3,\xc3\x08M\x04M\x08\xc3,'
+ b'\xc3\tF\x01E\x04E\x01F\t\xc3,\xc3\nD\x04'
+ b'C\x04C\x04D\n\xc3,\xc3\x12C\x04C\x12\xc3,'
+ b'\xc3\x13H\x13\xc3,\xc3\x13H\x13\xc3,\xc3\x14F\x14'
+ b'\xc3,\xc3.\xc3,\xc3.\xc3,\xc3.\xc3,\xf4-'
+ b'\xf2/\xf02\xec?X\xc0\xdb\xe6;\xe4<\xe4<\xe4'
+ b'\x1e'
)
-# 2-bit RLE, generated from res/torch_icon.png, 247 bytes
+# 2-bit RLE, generated from res/torch_icon.png, 245 bytes
torch = (
b'\x02'
b'`@'
- b'?\xff\xff\xff\xff\xff\xff\xff&\xc6\x0c@\xfdB?\n'
+ b'?\xff\xff\xff\xff\xff\xff\xff&\xc6\x0c@\xd4B?\n'
b'\xca\tD?\x08\xc4\x06\xc2\x07F?\x07\xc3\x07\xc2\x06'
b'H?\x06\xc2\n\xc1\x04G\xc2A8\xc5\x08\xc2\t\xc2'
b'\x02F\xc3C7\xc7\x06\xc2\x0b\xc1F\xc2F\x1e\xe8\n'
b'\xc2C\xc3H\x1d\xe8\x0c\xc1N\x1d\xc2%\xc1\x0b\xc2N'
- b'\x1d\xc2%\xc1\x0c\xc1N\x1d\xc2\x04\x80m\x9d\x04\xc1\x0b'
- b'\xc2N\x1d\xc2\x06\x81\x03\x81\x03\x81\x03\x81\x03\x81\x03\x81'
- b'\x03\x81\x06\xc1\x0c\xc1N\x1d\xc2\x04\x9d\x04\xc1\x0b\xc2C'
- b'\xcaA\x1d\xc2\x06\x81\x03\x81\x03\x81\x03\x81\x03\x81\x03\x81'
- b'\x03\x81\x06\xc1\x0c\xc1N\x1d\xc2\x04\x9d\x04\xc1\x0b\xc2N'
- b'\x1d\xc2%\xc1\x0c\xc1N\x1d\xc2%\xc1\x0b\xc2N\x1d\xe8'
- b'\x0c\xc1N\x1e\xe8\n\xc2C\xc3H?\x05\xc2\x0b\xc1F'
- b'\xc2F?\x06\xc2\t\xc2\x02F\xc3C?\x06\xc2\n\xc1'
- b'\x04G\xc2A?\x07\xc3\x07\xc2\x06H?\x08\xc4\x06\xc2'
- b'\x07F?\n\xca\tD?\r\xc6\x0cB?\xff\xff\xff'
- b'\xff\xff\xff\x95'
+ b'\x1d\xc2%\xc1\x0c\xc1N\x1d\xc2\x04\x9d\x04\xc1\x0b\xc2N'
+ b'\x1d\xc2\x06\x81\x03\x81\x03\x81\x03\x81\x03\x81\x03\x81\x03\x81'
+ b'\x06\xc1\x0c\xc1N\x1d\xc2\x04\x9d\x04\xc1\x0b\xc2C\xcaA'
+ b'\x1d\xc2\x06\x81\x03\x81\x03\x81\x03\x81\x03\x81\x03\x81\x03\x81'
+ b'\x06\xc1\x0c\xc1N\x1d\xc2\x04\x9d\x04\xc1\x0b\xc2N\x1d\xc2'
+ b'%\xc1\x0c\xc1N\x1d\xc2%\xc1\x0b\xc2N\x1d\xe8\x0c\xc1'
+ b'N\x1e\xe8\n\xc2C\xc3H?\x05\xc2\x0b\xc1F\xc2F'
+ b'?\x06\xc2\t\xc2\x02F\xc3C?\x06\xc2\n\xc1\x04G'
+ b'\xc2A?\x07\xc3\x07\xc2\x06H?\x08\xc4\x06\xc2\x07F'
+ b'?\n\xca\tD?\r\xc6\x0cB?\xff\xff\xff\xff\xff'
+ b'\xff\x95'
)
# 1-bit RLE, generated from res/up_arrow.png, 16 bytes