micropython-nano-gui/gui/demos/epd29_async.py

127 wiersze
3.9 KiB
Python

# epd29_async.py Demo program for nano_gui on an Adafruit 2.9" flexible ePaper screen
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2020 Peter Hinch
# color_setup must set landcsape True, asyn True and must not set demo_mode
from cmath import exp, pi
import uasyncio as asyncio
from color_setup import ssd
# On a monochrome display Writer is more efficient than CWriter.
from gui.core.writer import Writer
from gui.core.nanogui import refresh
from gui.widgets.meter import Meter
from gui.widgets.label import Label
from gui.widgets.dial import Dial, Pointer
# Fonts
import gui.fonts.arial10 as arial10
import gui.fonts.font6 as small
ssd._asyn = True # HACK to make it config agnostic
# Some ports don't support uos.urandom.
# See https://github.com/peterhinch/micropython-samples/tree/master/random
def xorshift64star(modulo, seed = 0xf9ac6ba4):
x = seed
def func():
nonlocal x
x ^= x >> 12
x ^= ((x << 25) & 0xffffffffffffffff) # modulo 2**64
x ^= x >> 27
return (x * 0x2545F4914F6CDD1D) % modulo
return func
async def compass(evt): # TODO why does this not get drawn on 1st pass?
wri = Writer(ssd, arial10, verbose=False)
wri.set_clip(False, False, False)
v1 = 0 + 0.9j
v2 = exp(0 - (pi / 6) * 1j)
dial = Dial(wri, 5, 5, height = 75, ticks = 12, bdcolor=None,
label='Direction', style = Dial.COMPASS)
ptr = Pointer(dial)
while True:
ptr.value(v1)
v1 *= v2
# await asyncio.sleep_ms(100)
await evt.wait()
async def multi_fields(evt):
wri = Writer(ssd, small, verbose=False)
wri.set_clip(False, False, False)
nfields = []
dy = small.height() + 10
row = 2
col = 100
width = wri.stringlen('99.990')
for txt in ('X:', 'Y:', 'Z:'):
Label(wri, row, col, txt)
nfields.append(Label(wri, row, col, width, bdcolor=None)) # Draw border
row += dy
random = xorshift64star(2**24 - 1)
while True:
for _ in range(10):
for field in nfields:
value = random() / 167772
field.value('{:5.2f}'.format(value))
await evt.wait()
async def meter(evt):
wri = Writer(ssd, arial10, verbose=False)
wri.set_clip(False, False, False)
row = 10
col = 170
args = {'height' : 80,
'width' : 15,
'divisions' : 4,
'style' : Meter.BAR}
m0 = Meter(wri, row, col, legends=('0.0', '0.5', '1.0'), **args)
m1 = Meter(wri, row, col + 40, legends=('-1', '0', '+1'), **args)
m2 = Meter(wri, row, col + 80, legends=('-1', '0', '+1'), **args)
random = xorshift64star(2**24 - 1)
while True:
steps = 10
for n in range(steps + 1):
m0.value(random() / 16777216)
m1.value(n/steps)
m2.value(1 - n/steps)
await evt.wait()
async def main():
refresh(ssd, True) # Clear display
await ssd.wait()
print('Ready')
evt = asyncio.Event()
asyncio.create_task(meter(evt))
asyncio.create_task(multi_fields(evt))
asyncio.create_task(compass(evt))
while True:
# Normal procedure before refresh, but 10s sleep should mean it always returns immediately
await ssd.wait()
refresh(ssd) # Launches ._as_show()
await ssd.updated()
# Content has now been shifted out so coros can update
# framebuffer in background
evt.set()
evt.clear()
await asyncio.sleep(10) # Allow for slow refresh
tstr = '''Test of asynchronous code updating the EPD. This should
not be run for long periods as the EPD should not be updated more
frequently than every 180s.
'''
print(tstr)
try:
asyncio.run(main())
except KeyboardInterrupt:
# Defensive code: avoid leaving EPD hardware in an undefined state.
print('Waiting for display to become idle')
ssd.sleep() # Synchronous code. May block for 5s if display is updating.
finally:
_ = asyncio.new_event_loop()