kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
Scale widget added. Pass initial test.
rodzic
5ec4948f91
commit
dca99bf247
|
@ -0,0 +1,155 @@
|
|||
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
|
||||
|
||||
from micropython import const
|
||||
import framebuf
|
||||
|
||||
|
||||
# register definitions
|
||||
SET_CONTRAST = const(0x81)
|
||||
SET_ENTIRE_ON = const(0xA4)
|
||||
SET_NORM_INV = const(0xA6)
|
||||
SET_DISP = const(0xAE)
|
||||
SET_MEM_ADDR = const(0x20)
|
||||
SET_COL_ADDR = const(0x21)
|
||||
SET_PAGE_ADDR = const(0x22)
|
||||
SET_DISP_START_LINE = const(0x40)
|
||||
SET_SEG_REMAP = const(0xA0)
|
||||
SET_MUX_RATIO = const(0xA8)
|
||||
SET_COM_OUT_DIR = const(0xC0)
|
||||
SET_DISP_OFFSET = const(0xD3)
|
||||
SET_COM_PIN_CFG = const(0xDA)
|
||||
SET_DISP_CLK_DIV = const(0xD5)
|
||||
SET_PRECHARGE = const(0xD9)
|
||||
SET_VCOM_DESEL = const(0xDB)
|
||||
SET_CHARGE_PUMP = const(0x8D)
|
||||
|
||||
# Subclassing FrameBuffer provides support for graphics primitives
|
||||
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
|
||||
class SSD1306(framebuf.FrameBuffer):
|
||||
def __init__(self, width, height, external_vcc):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.external_vcc = external_vcc
|
||||
self.pages = self.height // 8
|
||||
self.buffer = bytearray(self.pages * self.width)
|
||||
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
|
||||
self.init_display()
|
||||
|
||||
def init_display(self):
|
||||
for cmd in (
|
||||
SET_DISP | 0x00, # off
|
||||
# address setting
|
||||
SET_MEM_ADDR,
|
||||
0x00, # horizontal
|
||||
# resolution and layout
|
||||
SET_DISP_START_LINE | 0x00,
|
||||
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
|
||||
SET_MUX_RATIO,
|
||||
self.height - 1,
|
||||
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
|
||||
SET_DISP_OFFSET,
|
||||
0x00,
|
||||
SET_COM_PIN_CFG,
|
||||
0x02 if self.width > 2 * self.height else 0x12,
|
||||
# timing and driving scheme
|
||||
SET_DISP_CLK_DIV,
|
||||
0x80,
|
||||
SET_PRECHARGE,
|
||||
0x22 if self.external_vcc else 0xF1,
|
||||
SET_VCOM_DESEL,
|
||||
0x30, # 0.83*Vcc
|
||||
# display
|
||||
SET_CONTRAST,
|
||||
0xFF, # maximum
|
||||
SET_ENTIRE_ON, # output follows RAM contents
|
||||
SET_NORM_INV, # not inverted
|
||||
# charge pump
|
||||
SET_CHARGE_PUMP,
|
||||
0x10 if self.external_vcc else 0x14,
|
||||
SET_DISP | 0x01,
|
||||
): # on
|
||||
self.write_cmd(cmd)
|
||||
self.fill(0)
|
||||
self.show()
|
||||
|
||||
def poweroff(self):
|
||||
self.write_cmd(SET_DISP | 0x00)
|
||||
|
||||
def poweron(self):
|
||||
self.write_cmd(SET_DISP | 0x01)
|
||||
|
||||
def contrast(self, contrast):
|
||||
self.write_cmd(SET_CONTRAST)
|
||||
self.write_cmd(contrast)
|
||||
|
||||
def invert(self, invert):
|
||||
self.write_cmd(SET_NORM_INV | (invert & 1))
|
||||
|
||||
def show(self):
|
||||
x0 = 0
|
||||
x1 = self.width - 1
|
||||
if self.width == 64:
|
||||
# displays with width of 64 pixels are shifted by 32
|
||||
x0 += 32
|
||||
x1 += 32
|
||||
self.write_cmd(SET_COL_ADDR)
|
||||
self.write_cmd(x0)
|
||||
self.write_cmd(x1)
|
||||
self.write_cmd(SET_PAGE_ADDR)
|
||||
self.write_cmd(0)
|
||||
self.write_cmd(self.pages - 1)
|
||||
self.write_data(self.buffer)
|
||||
|
||||
|
||||
class SSD1306_I2C(SSD1306):
|
||||
def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False):
|
||||
self.i2c = i2c
|
||||
self.addr = addr
|
||||
self.temp = bytearray(2)
|
||||
self.write_list = [b"\x40", None] # Co=0, D/C#=1
|
||||
super().__init__(width, height, external_vcc)
|
||||
|
||||
def write_cmd(self, cmd):
|
||||
self.temp[0] = 0x80 # Co=1, D/C#=0
|
||||
self.temp[1] = cmd
|
||||
self.i2c.writeto(self.addr, self.temp)
|
||||
|
||||
def write_data(self, buf):
|
||||
self.write_list[1] = buf
|
||||
self.i2c.writevto(self.addr, self.write_list)
|
||||
|
||||
|
||||
class SSD1306_SPI(SSD1306):
|
||||
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
|
||||
self.rate = 10 * 1024 * 1024
|
||||
dc.init(dc.OUT, value=0)
|
||||
res.init(res.OUT, value=0)
|
||||
cs.init(cs.OUT, value=1)
|
||||
self.spi = spi
|
||||
self.dc = dc
|
||||
self.res = res
|
||||
self.cs = cs
|
||||
import time
|
||||
|
||||
self.res(1)
|
||||
time.sleep_ms(1)
|
||||
self.res(0)
|
||||
time.sleep_ms(10)
|
||||
self.res(1)
|
||||
super().__init__(width, height, external_vcc)
|
||||
|
||||
def write_cmd(self, cmd):
|
||||
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
|
||||
self.cs(1)
|
||||
self.dc(0)
|
||||
self.cs(0)
|
||||
self.spi.write(bytearray([cmd]))
|
||||
self.cs(1)
|
||||
|
||||
def write_data(self, buf):
|
||||
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
|
||||
self.cs(1)
|
||||
self.dc(1)
|
||||
self.cs(0)
|
||||
self.spi.write(buf)
|
||||
self.cs(1)
|
|
@ -0,0 +1,15 @@
|
|||
# colors.py Standard color constants for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
||||
from drivers.ssd1351.ssd1351 import SSD1351 as SSD
|
||||
|
||||
GREEN = SSD.rgb(0, 255, 0)
|
||||
RED = SSD.rgb(255, 0, 0)
|
||||
BLUE = SSD.rgb(0, 0, 255)
|
||||
YELLOW = SSD.rgb(255, 255, 0)
|
||||
BLACK = 0
|
||||
WHITE = SSD.rgb(255, 255, 255)
|
||||
LIGHTGREEN = SSD.rgb(0, 100, 0)
|
||||
|
|
@ -177,190 +177,3 @@ class DObject():
|
|||
self.label.value(text, invert, fgcolor, bgcolor, bdcolor)
|
||||
else:
|
||||
raise ValueError('Attempt to update nonexistent label.')
|
||||
|
||||
# text: str display string int save width
|
||||
class Label(DObject):
|
||||
def __init__(self, writer, row, col, text, invert=False, fgcolor=None, bgcolor=None, bdcolor=False):
|
||||
# Determine width of object
|
||||
if isinstance(text, int):
|
||||
width = text
|
||||
text = None
|
||||
else:
|
||||
width = writer.stringlen(text)
|
||||
height = writer.height
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor)
|
||||
if text is not None:
|
||||
self.value(text, invert)
|
||||
|
||||
def value(self, text=None, invert=False, fgcolor=None, bgcolor=None, bdcolor=None):
|
||||
txt = super().value(text)
|
||||
# Redraw even if no text supplied: colors may have changed.
|
||||
self.invert = invert
|
||||
self.fgcolor = self.def_fgcolor if fgcolor is None else fgcolor
|
||||
self.bgcolor = self.def_bgcolor if bgcolor is None else bgcolor
|
||||
if bdcolor is False:
|
||||
self.def_bdcolor = False
|
||||
self.bdcolor = self.def_bdcolor if bdcolor is None else bdcolor
|
||||
self.show()
|
||||
return txt
|
||||
|
||||
def show(self):
|
||||
txt = super().value()
|
||||
if txt is None: # No content to draw. Future use.
|
||||
return
|
||||
super().show() # Draw or erase border
|
||||
wri = self.writer
|
||||
dev = self.device
|
||||
wri.setcolor(self.fgcolor, self.bgcolor)
|
||||
Writer.set_textpos(dev, self.row, self.col)
|
||||
wri.setcolor(self.fgcolor, self.bgcolor)
|
||||
wri.printstring(txt, self.invert)
|
||||
wri.setcolor() # Restore defaults
|
||||
|
||||
class Meter(DObject):
|
||||
BAR = 1
|
||||
LINE = 0
|
||||
def __init__(self, writer, row, col, *, height=50, width=10,
|
||||
fgcolor=None, bgcolor=None, ptcolor=None, bdcolor=None,
|
||||
divisions=5, label=None, style=0, legends=None, value=None):
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor)
|
||||
self.divisions = divisions
|
||||
if label is not None:
|
||||
Label(writer, row + height + 3, col, label)
|
||||
self.style = style
|
||||
self.legends = legends
|
||||
self.ptcolor = ptcolor if ptcolor is not None else self.fgcolor
|
||||
self.value(value)
|
||||
|
||||
def value(self, n=None, color=None):
|
||||
if n is None:
|
||||
return super().value()
|
||||
n = super().value(min(1, max(0, n)))
|
||||
if color is not None:
|
||||
self.ptcolor = color
|
||||
self.show()
|
||||
return n
|
||||
|
||||
def show(self):
|
||||
super().show() # Draw or erase border
|
||||
val = super().value()
|
||||
wri = self.writer
|
||||
dev = self.device
|
||||
width = self.width
|
||||
height = self.height
|
||||
legends = self.legends
|
||||
x0 = self.col
|
||||
x1 = self.col + width
|
||||
y0 = self.row
|
||||
y1 = self.row + height
|
||||
if self.divisions > 0:
|
||||
dy = height / (self.divisions) # Tick marks
|
||||
for tick in range(self.divisions + 1):
|
||||
ypos = int(y0 + dy * tick)
|
||||
dev.hline(x0 + 2, ypos, x1 - x0 - 4, self.fgcolor)
|
||||
|
||||
if legends is not None: # Legends
|
||||
dy = 0 if len(legends) <= 1 else height / (len(legends) -1)
|
||||
yl = y1 - wri.height / 2 # Start at bottom
|
||||
for legend in legends:
|
||||
Label(wri, int(yl), x1 + 4, legend)
|
||||
yl -= dy
|
||||
y = int(y1 - val * height) # y position of slider
|
||||
if self.style == self.LINE:
|
||||
dev.hline(x0, y, width, self.ptcolor) # Draw pointer
|
||||
else:
|
||||
w = width / 2
|
||||
dev.fill_rect(int(x0 + w - 2), y, 4, y1 - y, self.ptcolor)
|
||||
|
||||
|
||||
class LED(DObject):
|
||||
def __init__(self, writer, row, col, *, height=12,
|
||||
fgcolor=None, bgcolor=None, bdcolor=None, label=None):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor)
|
||||
if label is not None:
|
||||
self.label = Label(writer, row + height + 3, col, label)
|
||||
self.radius = self.height // 2
|
||||
|
||||
def color(self, c=None):
|
||||
self.fgcolor = self.bgcolor if c is None else c
|
||||
self.show()
|
||||
|
||||
def show(self):
|
||||
super().show()
|
||||
wri = self.writer
|
||||
dev = self.device
|
||||
r = self.radius
|
||||
fillcircle(dev, self.col + r, self.row + r, r, self.fgcolor)
|
||||
if isinstance(self.bdcolor, int):
|
||||
circle(dev, self.col + r, self.row + r, r, self.bdcolor)
|
||||
|
||||
|
||||
class Pointer():
|
||||
def __init__(self, dial):
|
||||
self.dial = dial
|
||||
self.val = 0 + 0j
|
||||
self.color = None
|
||||
|
||||
def value(self, v=None, color=None):
|
||||
self.color = color
|
||||
if v is not None:
|
||||
if isinstance(v, complex):
|
||||
l = cmath.polar(v)[0]
|
||||
if l > 1:
|
||||
self.val = v/l
|
||||
else:
|
||||
self.val = v
|
||||
else:
|
||||
raise ValueError('Pointer value must be complex.')
|
||||
self.dial.vectors.add(self)
|
||||
self.dial._set_pend(self.dial) # avoid redrawing for each vector
|
||||
return self.val
|
||||
|
||||
class Dial(DObject):
|
||||
CLOCK = 0
|
||||
COMPASS = 1
|
||||
def __init__(self, writer, row, col, *, height=50,
|
||||
fgcolor=None, bgcolor=None, bdcolor=False, ticks=4,
|
||||
label=None, style=0, pip=None):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor)
|
||||
self.style = style
|
||||
self.pip = self.fgcolor if pip is None else pip
|
||||
if label is not None:
|
||||
self.label = Label(writer, row + height + 3, col, label)
|
||||
radius = int(height / 2)
|
||||
self.radius = radius
|
||||
self.ticks = ticks
|
||||
self.xorigin = col + radius
|
||||
self.yorigin = row + radius
|
||||
self.vectors = set()
|
||||
|
||||
def show(self):
|
||||
super().show()
|
||||
# cache bound variables
|
||||
dev = self.device
|
||||
ticks = self.ticks
|
||||
radius = self.radius
|
||||
xo = self.xorigin
|
||||
yo = self.yorigin
|
||||
# vectors (complex)
|
||||
vor = xo + 1j * yo
|
||||
vtstart = 0.9 * radius + 0j # start of tick
|
||||
vtick = 0.1 * radius + 0j # tick
|
||||
vrot = cmath.exp(2j * cmath.pi/ticks) # unit rotation
|
||||
for _ in range(ticks):
|
||||
polar(dev, vor + conj(vtstart), vtick, self.fgcolor)
|
||||
vtick *= vrot
|
||||
vtstart *= vrot
|
||||
circle(dev, xo, yo, radius, self.fgcolor)
|
||||
vshort = 1000 # Length of shortest vector
|
||||
for v in self.vectors:
|
||||
color = self.fgcolor if v.color is None else v.color
|
||||
val = v.value() * radius # val is complex
|
||||
vshort = min(vshort, cmath.polar(val)[0])
|
||||
if self.style == Dial.CLOCK:
|
||||
polar(dev, vor, val, color)
|
||||
else:
|
||||
arrow(dev, vor, val, 5, color)
|
||||
if isinstance(self.pip, int) and vshort > 5:
|
||||
fillcircle(dev, xo, yo, 2, self.pip)
|
||||
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
|
||||
# Initialise hardware
|
||||
from ssd1351_setup import ssd, height # Create a display instance
|
||||
from gui.core.nanogui import Dial, Pointer, refresh, Label
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
refresh(ssd) # Initialise and clear display.
|
||||
|
||||
# Now import other modules
|
||||
|
|
|
@ -24,7 +24,8 @@ import gc
|
|||
# Initialise hardware
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
|
||||
from gui.core.nanogui import Dial, Pointer, refresh
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
refresh(ssd) # Initialise and clear display.
|
||||
|
||||
# Now import other modules
|
||||
|
|
|
@ -13,7 +13,10 @@ import uasyncio as asyncio
|
|||
import pyb
|
||||
import uos
|
||||
from gui.core.writer import CWriter
|
||||
from gui.core.nanogui import LED, Meter, refresh
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.led import LED
|
||||
from gui.widgets.meter import Meter
|
||||
|
||||
refresh(ssd)
|
||||
|
||||
# Fonts
|
||||
|
|
|
@ -13,7 +13,10 @@ import uasyncio as asyncio
|
|||
import pyb
|
||||
import uos
|
||||
from gui.core.writer import CWriter
|
||||
from gui.core.nanogui import LED, Meter, refresh
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.led import LED
|
||||
from gui.widgets.meter import Meter
|
||||
|
||||
refresh(ssd)
|
||||
|
||||
# Fonts
|
||||
|
|
|
@ -12,7 +12,11 @@ import cmath
|
|||
import utime
|
||||
import uos
|
||||
from gui.core.writer import Writer, CWriter
|
||||
from gui.core.nanogui import Label, Meter, LED, Dial, Pointer, refresh
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.led import LED
|
||||
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
|
||||
|
@ -149,6 +153,7 @@ def compass(x):
|
|||
refresh(ssd)
|
||||
|
||||
print('Color display test is running.')
|
||||
print('Test runs to completion.')
|
||||
clock(70)
|
||||
compass(70)
|
||||
meter()
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
|
||||
from gui.core.nanogui import Label, Meter, LED, refresh
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.led import LED
|
||||
from gui.widgets.meter import Meter
|
||||
from gui.widgets.label import Label
|
||||
|
||||
refresh(ssd)
|
||||
# Fonts
|
||||
import gui.fonts.arial10 as arial10
|
||||
|
@ -96,6 +100,7 @@ def vari_fields():
|
|||
refresh(ssd)
|
||||
|
||||
print('Color display test is running.')
|
||||
print('Test runs to completion.')
|
||||
meter()
|
||||
multi_fields(t = 10)
|
||||
vari_fields()
|
||||
|
|
|
@ -6,19 +6,6 @@
|
|||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
# WIRING (Adafruit pin nos and names)
|
||||
# Pyb SSD
|
||||
# 3v3 Vin (10)
|
||||
# Gnd Gnd (11)
|
||||
# X1 DC (3 DC)
|
||||
# X2 CS (5 OC OLEDCS)
|
||||
# X3 Rst (4 R RESET)
|
||||
# X6 CLK (2 CL SCK)
|
||||
# X8 DATA (1 SI MOSI)
|
||||
|
||||
height = 96 # 1.27 inch 96*128 (rows*cols) display
|
||||
# height = 128 # 1.5 inch 128*128 display
|
||||
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
|
||||
import cmath
|
||||
|
@ -27,7 +14,10 @@ import utime
|
|||
import uos
|
||||
from gui.core.writer import Writer, CWriter
|
||||
from gui.core.fplot import PolarGraph, PolarCurve, CartesianGraph, Curve, TSequence
|
||||
from gui.core.nanogui import Label, refresh
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
||||
|
||||
|
||||
refresh(ssd)
|
||||
|
||||
# Fonts
|
||||
|
@ -163,6 +153,7 @@ def seq():
|
|||
refresh(ssd)
|
||||
utime.sleep_ms(100)
|
||||
|
||||
print('Test runs to completion.')
|
||||
seq()
|
||||
utime.sleep(1.5)
|
||||
liss()
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# scale.py Test/demo of scale widget for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
||||
# Usage:
|
||||
# import gui.demos.scale
|
||||
# Initialise hardware
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.core.writer import CWriter
|
||||
|
||||
import uasyncio as asyncio
|
||||
from gui.core.colors import *
|
||||
import gui.fonts.arial10 as arial10
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.scale import Scale
|
||||
|
||||
# COROUTINES
|
||||
async def radio(scale):
|
||||
cv = 88.0 # Current value
|
||||
val = 108.0 # Target value
|
||||
while True:
|
||||
v1, v2 = val, cv
|
||||
steps = 200
|
||||
delta = (val - cv) / steps
|
||||
for _ in range(steps):
|
||||
cv += delta
|
||||
# Map user variable to -1.0..+1.0
|
||||
scale.value(2 * (cv - 88)/(108 - 88) - 1)
|
||||
await asyncio.sleep_ms(200)
|
||||
val, cv = v2, v1
|
||||
|
||||
async def default(scale, lbl):
|
||||
cv = -1.0 # Current
|
||||
val = 1.0
|
||||
while True:
|
||||
v1, v2 = val, cv
|
||||
steps = 400
|
||||
delta = (val - cv) / steps
|
||||
for _ in range(steps):
|
||||
cv += delta
|
||||
scale.value(cv)
|
||||
lbl.value('{:4.3f}'.format(cv))
|
||||
refresh(ssd)
|
||||
await asyncio.sleep_ms(250)
|
||||
val, cv = v2, v1
|
||||
|
||||
|
||||
def test():
|
||||
refresh(ssd) # Initialise and clear display.
|
||||
CWriter.set_textpos(ssd, 0, 0) # In case previous tests have altered it
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
wri.set_clip(True, True, False)
|
||||
lbl = Label(wri, ssd.height - wri.height - 2, 0, 50)
|
||||
scale = Scale(wri, 5, 5)
|
||||
asyncio.run(default(scale, lbl))
|
||||
|
||||
test()
|
|
@ -0,0 +1,229 @@
|
|||
# Code generated by font-to-py.py.
|
||||
# Font: FreeSans.ttf
|
||||
version = '0.1'
|
||||
|
||||
def height():
|
||||
return 17
|
||||
|
||||
def max_width():
|
||||
return 17
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return False
|
||||
|
||||
_font =\
|
||||
b'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x06\x00\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x80'\
|
||||
b'\x00\xc0\x00\x00\x00\x00\x06\x00\x00\xf0\xf0\xf0\xa0\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x19'\
|
||||
b'\x00\x19\x00\x13\x00\x7f\x80\x12\x00\x32\x00\x32\x00\xff\x80\x26'\
|
||||
b'\x00\x24\x00\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x10'\
|
||||
b'\x00\x3c\x00\x56\x00\xd3\x00\xd3\x00\xd0\x00\xd0\x00\x3c\x00\x17'\
|
||||
b'\x00\x13\x00\xd3\x00\xd6\x00\x7c\x00\x10\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0f\x00\x00\x00\x78\x20\xcc\x40\xcc\x80\xcc\x80\xc9\x00\x31'\
|
||||
b'\x00\x02\x78\x04\xcc\x04\xcc\x08\xcc\x08\xcc\x10\x78\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x1e\x00\x33\x00\x33\x00\x33'\
|
||||
b'\x00\x1e\x00\x18\x00\x74\xc0\xe6\xc0\xc3\x80\xc1\x80\xe3\x80\x3c'\
|
||||
b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\xc0\xc0\xc0\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x10\x20'\
|
||||
b'\x20\x60\x40\xc0\xc0\xc0\xc0\xc0\xc0\x40\x60\x20\x30\x10\x00\x06'\
|
||||
b'\x00\x80\xc0\x40\x60\x20\x30\x30\x30\x30\x30\x30\x20\x60\x40\xc0'\
|
||||
b'\x80\x00\x07\x00\x20\xa8\x70\x50\x50\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x30\x00\x30\x00\x30\x00\xfc\x00\x30\x00\x30\x00\x30'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\xc0\x40\x40\x80\x00\x06\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x04'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00'\
|
||||
b'\x00\x00\x05\x00\x08\x08\x10\x10\x10\x20\x20\x20\x40\x40\x40\x80'\
|
||||
b'\x80\x00\x00\x00\x00\x09\x00\x00\x00\x3c\x00\x66\x00\x42\x00\xc3'\
|
||||
b'\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\x42\x00\x66\x00\x3c'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x10\x00\x30'\
|
||||
b'\x00\xf0\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30'\
|
||||
b'\x00\x30\x00\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00'\
|
||||
b'\x00\x3c\x00\x66\x00\xc3\x00\xc3\x00\x03\x00\x06\x00\x0c\x00\x38'\
|
||||
b'\x00\x60\x00\x40\x00\xc0\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x09\x00\x00\x00\x7c\x00\xe7\x00\xc3\x00\x03\x00\x02\x00\x1c'\
|
||||
b'\x00\x07\x00\x03\x00\x03\x00\xc3\x00\xe6\x00\x3c\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x09\x00\x00\x00\x0c\x00\x0c\x00\x1c\x00\x2c'\
|
||||
b'\x00\x2c\x00\x4c\x00\x8c\x00\x8c\x00\xfe\x00\x0c\x00\x0c\x00\x0c'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x7e\x00\x40'\
|
||||
b'\x00\x40\x00\x80\x00\xbc\x00\xe6\x00\x03\x00\x03\x00\x03\x00\xc3'\
|
||||
b'\x00\x66\x00\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00'\
|
||||
b'\x00\x3c\x00\x66\x00\x43\x00\xc0\x00\xc0\x00\xfc\x00\xe6\x00\xc3'\
|
||||
b'\x00\xc3\x00\xc3\x00\x66\x00\x3c\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x09\x00\x00\x00\xff\x00\x03\x00\x02\x00\x06\x00\x04\x00\x0c'\
|
||||
b'\x00\x08\x00\x18\x00\x18\x00\x10\x00\x30\x00\x30\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x09\x00\x00\x00\x3c\x00\x66\x00\xc3\x00\xc3'\
|
||||
b'\x00\x66\x00\x3c\x00\x66\x00\xc3\x00\xc3\x00\xc3\x00\x66\x00\x3c'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x3c\x00\x66'\
|
||||
b'\x00\xc3\x00\xc3\x00\xc3\x00\x67\x00\x3b\x00\x03\x00\x03\x00\xc2'\
|
||||
b'\x00\x66\x00\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00'\
|
||||
b'\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00'\
|
||||
b'\x04\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\xc0\x40'\
|
||||
b'\x40\x80\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03'\
|
||||
b'\x00\x0e\x00\x38\x00\xc0\x00\xe0\x00\x38\x00\x07\x00\x01\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00\xff\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x70\x00\x1c\x00\x03\x00\x07'\
|
||||
b'\x00\x1c\x00\xe0\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09'\
|
||||
b'\x00\x3c\x00\xc7\x00\xc3\x00\x03\x00\x03\x00\x06\x00\x0c\x00\x08'\
|
||||
b'\x00\x18\x00\x18\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x11\x00\x07\xe0\x00\x0c\x38\x00\x30\x0c\x00\x20\x06'\
|
||||
b'\x00\x63\xb7\x00\x4c\x73\x00\xcc\x63\x00\xd8\x63\x00\xd8\x63\x00'\
|
||||
b'\xd8\x46\x00\xdc\xce\x00\x6f\x78\x00\x30\x00\x00\x18\x00\x00\x0f'\
|
||||
b'\xe0\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x06\x00\x0e\x00\x0b\x00'\
|
||||
b'\x1b\x00\x1b\x00\x11\x80\x31\x80\x31\x80\x3f\xc0\x60\xc0\x60\x40'\
|
||||
b'\x40\x60\xc0\x60\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xfe\x00'\
|
||||
b'\xc3\x80\xc1\x80\xc1\x80\xc1\x80\xc3\x00\xfe\x00\xc1\x80\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\xc1\x80\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0c\x00\x1f\x80\x30\xc0\x60\x60\x40\x60\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\x40\x60\x60\x60\x30\xc0\x1f\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0c\x00\xff\x00\xc1\x80\xc0\xc0\xc0\x60\xc0\x60'\
|
||||
b'\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\xc0\xc1\x80\xff\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xff\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xff\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\xff\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xfe\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0d\x00\x0f\xc0\x30\x60\x60\x30\x60\x00\xc0\x00\xc0\x00\xc1\xf0'\
|
||||
b'\xc0\x30\xc0\x30\x60\x30\x60\x70\x30\xf0\x0f\x10\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0c\x00\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xff\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x00\x00\x00\x00\x09\x00\x06\x00\x06'\
|
||||
b'\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06\x00\xc6'\
|
||||
b'\x00\xc6\x00\xc4\x00\x78\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b'\
|
||||
b'\x00\xc0\xc0\xc1\x80\xc3\x00\xc6\x00\xcc\x00\xd8\x00\xfc\x00\xe6'\
|
||||
b'\x00\xc6\x00\xc3\x00\xc1\x80\xc1\x80\xc0\xc0\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0a\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0'\
|
||||
b'\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xfe\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0e\x00\xe0\x38\xe0\x38\xf0\x78\xf0'\
|
||||
b'\x78\xd0\x58\xd8\xd8\xd8\xd8\xc8\x98\xcd\x98\xcd\x98\xc5\x18\xc7'\
|
||||
b'\x18\xc7\x18\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\xe0\x60\xe0'\
|
||||
b'\x60\xf0\x60\xd0\x60\xd8\x60\xcc\x60\xc4\x60\xc6\x60\xc3\x60\xc3'\
|
||||
b'\x60\xc1\xe0\xc0\xe0\xc0\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x0d'\
|
||||
b'\x00\x1f\x80\x30\xc0\x60\x60\xe0\x60\xc0\x30\xc0\x30\xc0\x30\xc0'\
|
||||
b'\x30\xc0\x30\xe0\x60\x60\x60\x30\xc0\x1f\x80\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\xff\x00\xc1\x80\xc0\xc0\xc0\xc0\xc0\xc0\xc1'\
|
||||
b'\x80\xff\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x1f\x80\x30\xc0\x60\x60\xe0'\
|
||||
b'\x60\xc0\x30\xc0\x30\xc0\x30\xc0\x30\xc0\x30\xe1\x60\x61\xe0\x30'\
|
||||
b'\xc0\x1f\xe0\x00\x20\x00\x00\x00\x00\x00\x00\x0c\x00\xff\x00\xc1'\
|
||||
b'\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc1\x80\xff\x00\xc1\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\xc0\xc0\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x0b'\
|
||||
b'\x00\x3f\x00\x61\x80\xc0\xc0\xc0\x00\xc0\x00\x60\x00\x3e\x00\x07'\
|
||||
b'\x80\x01\xc0\xc0\xc0\xc0\xc0\x61\x80\x3f\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\xff\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18'\
|
||||
b'\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0c\x00\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x61'\
|
||||
b'\x80\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xc0\x60\x40'\
|
||||
b'\x40\x60\xc0\x60\xc0\x20\x80\x31\x80\x31\x80\x11\x00\x1b\x00\x0b'\
|
||||
b'\x00\x0a\x00\x0e\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10'\
|
||||
b'\x00\xc1\x83\xc1\x82\x42\x86\x62\xc6\x62\xc6\x62\x44\x24\x44\x24'\
|
||||
b'\x6c\x34\x2c\x3c\x28\x18\x38\x18\x38\x18\x18\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\x60\x40\x20\xc0\x31\x80\x19\x00\x1b\x00\x0e'\
|
||||
b'\x00\x06\x00\x0e\x00\x1b\x00\x11\x80\x31\x80\x60\xc0\x40\x60\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x40\x60\x60\x60\x30\xc0\x30'\
|
||||
b'\xc0\x19\x80\x0d\x00\x0f\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06'\
|
||||
b'\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\xff\x80\x01'\
|
||||
b'\x80\x03\x00\x06\x00\x06\x00\x0c\x00\x18\x00\x18\x00\x30\x00\x60'\
|
||||
b'\x00\x60\x00\xc0\x00\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x05'\
|
||||
b'\x00\xe0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xe0\x05\x00\x80\x80\x40\x40\x40\x20\x20\x20\x10\x10\x10\x08'\
|
||||
b'\x08\x00\x00\x00\x00\x05\x00\xe0\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x60\xe0\x08\x00\x00\x30\x30\x78\x48\x48'\
|
||||
b'\x84\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\xff\xc0\x00\x00\x00\x00\x00\x00\x04'\
|
||||
b'\x00\xc0\x40\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7c\x00\xc6\x00'\
|
||||
b'\x06\x00\x06\x00\x7e\x00\xc6\x00\xc6\x00\xce\x00\x77\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x09\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xde\x00\xe3\x00\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xe3\x00'\
|
||||
b'\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x3c\x00\x66\x00\xc3\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc3\x00\x66\x00\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00'\
|
||||
b'\x03\x00\x03\x00\x03\x00\x03\x00\x3b\x00\x67\x00\xc3\x00\xc3\x00'\
|
||||
b'\xc3\x00\xc3\x00\xc3\x00\x67\x00\x3b\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3c\x00\x66\x00'\
|
||||
b'\xc3\x00\xc3\x00\xff\x00\xc0\x00\xc3\x00\x66\x00\x3c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x05\x00\x30\x60\x60\x60\xf0\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x3b\x00\x67\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\xc3'\
|
||||
b'\x00\x67\x00\x3b\x00\x03\x00\x03\x00\xc6\x00\x7c\x00\x09\x00\xc0'\
|
||||
b'\x00\xc0\x00\xc0\x00\xc0\x00\xde\x00\xe3\x00\xc3\x00\xc3\x00\xc3'\
|
||||
b'\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x04\x00\xc0\x00\x00\x00\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\x00\x00\x00\x00\x04\x00\x60\x00\x00\x00\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\xc0\x09\x00\xc0\x00\xc0\x00\xc0\x00\xc0'\
|
||||
b'\x00\xc6\x00\xcc\x00\xd8\x00\xf8\x00\xe8\x00\xcc\x00\xc6\x00\xc6'\
|
||||
b'\x00\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\xdd\xe0\xe7\x30\xc6\x30\xc6\x30'\
|
||||
b'\xc6\x30\xc6\x30\xc6\x30\xc6\x30\xc6\x30\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\x00\xe3\x00'\
|
||||
b'\xc3\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x3c\x00\x66\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\x66\x00'\
|
||||
b'\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\xde\x00\xe3\x00\xc1\x80\xc1\x80\xc1\x80\xc1\x80'\
|
||||
b'\xc1\x80\xe3\x00\xde\x00\xc0\x00\xc0\x00\xc0\x00\x00\x00\x0a\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x3b\x00\x67\x00\xc3\x00\xc3\x00'\
|
||||
b'\xc3\x00\xc3\x00\xc3\x00\x67\x00\x3b\x00\x03\x00\x03\x00\x03\x00'\
|
||||
b'\x00\x00\x06\x00\x00\x00\x00\x00\xd8\xe0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x7c\xc6\xc0\xc0\x70'\
|
||||
b'\x0e\xc6\xc6\x7c\x00\x00\x00\x00\x05\x00\x00\x00\x60\x60\xf0\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x70\x00\x00\x00\x00\x09\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\xc3\x00\xc3'\
|
||||
b'\x00\xc3\x00\xc7\x00\x7b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08'\
|
||||
b'\x00\x00\x00\x00\x00\xc3\x43\x62\x66\x26\x34\x3c\x18\x18\x00\x00'\
|
||||
b'\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6\x30\x46\x30'\
|
||||
b'\x47\x20\x6f\x20\x69\x60\x29\x60\x29\xc0\x39\xc0\x10\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x42\x66\x34\x18'\
|
||||
b'\x18\x1c\x24\x66\x43\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\xc3'\
|
||||
b'\x42\x42\x66\x24\x24\x3c\x18\x18\x18\x10\x30\x60\x08\x00\x00\x00'\
|
||||
b'\x00\x00\xfe\x0c\x08\x18\x30\x60\x40\xc0\xfe\x00\x00\x00\x00\x06'\
|
||||
b'\x00\x30\x60\x60\x60\x60\x60\x60\xe0\xc0\xe0\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x30\x04\x00\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\x00\x06\x00\xc0\x60\x60\x60\x60\x60\x60\x70\x30'\
|
||||
b'\x70\x60\x60\x60\x60\x60\x60\xc0\x09\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x62\x00\x9e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
|
||||
_index =\
|
||||
b'\x00\x00\x13\x00\x26\x00\x39\x00\x5d\x00\x81\x00\xa5\x00\xc9\x00'\
|
||||
b'\xdc\x00\xef\x00\x02\x01\x15\x01\x39\x01\x4c\x01\x5f\x01\x72\x01'\
|
||||
b'\x85\x01\xa9\x01\xcd\x01\xf1\x01\x15\x02\x39\x02\x5d\x02\x81\x02'\
|
||||
b'\xa5\x02\xc9\x02\xed\x02\x00\x03\x13\x03\x37\x03\x5b\x03\x7f\x03'\
|
||||
b'\xa3\x03\xd8\x03\xfc\x03\x20\x04\x44\x04\x68\x04\x8c\x04\xb0\x04'\
|
||||
b'\xd4\x04\xf8\x04\x0b\x05\x2f\x05\x53\x05\x77\x05\x9b\x05\xbf\x05'\
|
||||
b'\xe3\x05\x07\x06\x2b\x06\x4f\x06\x73\x06\x97\x06\xbb\x06\xdf\x06'\
|
||||
b'\x03\x07\x27\x07\x4b\x07\x6f\x07\x82\x07\x95\x07\xa8\x07\xbb\x07'\
|
||||
b'\xdf\x07\xf2\x07\x16\x08\x3a\x08\x5e\x08\x82\x08\xa6\x08\xb9\x08'\
|
||||
b'\xdd\x08\x01\x09\x14\x09\x27\x09\x4b\x09\x5e\x09\x82\x09\xa6\x09'\
|
||||
b'\xca\x09\xee\x09\x12\x0a\x25\x0a\x38\x0a\x4b\x0a\x6f\x0a\x82\x0a'\
|
||||
b'\xa6\x0a\xb9\x0a\xcc\x0a\xdf\x0a\xf2\x0a\x05\x0b\x18\x0b\x3c\x0b'\
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
|
||||
def _chr_addr(ordch):
|
||||
offset = 2 * (ordch - 32)
|
||||
return int.from_bytes(_index[offset:offset + 2], 'little')
|
||||
|
||||
def get_ch(ch):
|
||||
ordch = ord(ch)
|
||||
ordch = ordch if ordch >= 32 and ordch <= 126 else ord('?')
|
||||
offset = _chr_addr(ordch)
|
||||
width = int.from_bytes(_font[offset:offset + 2], 'little')
|
||||
next_offs = _chr_addr(ordch +1)
|
||||
return _mvfont[offset + 2:next_offs], 17, width
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
# dial.py Dial and Pointer classes for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
import cmath
|
||||
from gui.core.nanogui import DObject, polar, conj, circle, arrow, fillcircle
|
||||
from gui.widgets.label import Label
|
||||
|
||||
class Pointer():
|
||||
def __init__(self, dial):
|
||||
self.dial = dial
|
||||
self.val = 0 + 0j
|
||||
self.color = None
|
||||
|
||||
def value(self, v=None, color=None):
|
||||
self.color = color
|
||||
if v is not None:
|
||||
if isinstance(v, complex):
|
||||
l = cmath.polar(v)[0]
|
||||
if l > 1:
|
||||
self.val = v/l
|
||||
else:
|
||||
self.val = v
|
||||
else:
|
||||
raise ValueError('Pointer value must be complex.')
|
||||
self.dial.vectors.add(self)
|
||||
self.dial._set_pend(self.dial) # avoid redrawing for each vector
|
||||
return self.val
|
||||
|
||||
class Dial(DObject):
|
||||
CLOCK = 0
|
||||
COMPASS = 1
|
||||
def __init__(self, writer, row, col, *, height=50,
|
||||
fgcolor=None, bgcolor=None, bdcolor=False, ticks=4,
|
||||
label=None, style=0, pip=None):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor)
|
||||
self.style = style
|
||||
self.pip = self.fgcolor if pip is None else pip
|
||||
if label is not None:
|
||||
self.label = Label(writer, row + height + 3, col, label)
|
||||
radius = int(height / 2)
|
||||
self.radius = radius
|
||||
self.ticks = ticks
|
||||
self.xorigin = col + radius
|
||||
self.yorigin = row + radius
|
||||
self.vectors = set()
|
||||
|
||||
def show(self):
|
||||
super().show()
|
||||
# cache bound variables
|
||||
dev = self.device
|
||||
ticks = self.ticks
|
||||
radius = self.radius
|
||||
xo = self.xorigin
|
||||
yo = self.yorigin
|
||||
# vectors (complex)
|
||||
vor = xo + 1j * yo
|
||||
vtstart = 0.9 * radius + 0j # start of tick
|
||||
vtick = 0.1 * radius + 0j # tick
|
||||
vrot = cmath.exp(2j * cmath.pi/ticks) # unit rotation
|
||||
for _ in range(ticks):
|
||||
polar(dev, vor + conj(vtstart), vtick, self.fgcolor)
|
||||
vtick *= vrot
|
||||
vtstart *= vrot
|
||||
circle(dev, xo, yo, radius, self.fgcolor)
|
||||
vshort = 1000 # Length of shortest vector
|
||||
for v in self.vectors:
|
||||
color = self.fgcolor if v.color is None else v.color
|
||||
val = v.value() * radius # val is complex
|
||||
vshort = min(vshort, cmath.polar(val)[0])
|
||||
if self.style == Dial.CLOCK:
|
||||
polar(dev, vor, val, color)
|
||||
else:
|
||||
arrow(dev, vor, val, 5, color)
|
||||
if isinstance(self.pip, int) and vshort > 5:
|
||||
fillcircle(dev, xo, yo, 2, self.pip)
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
# label.py Label class for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
from gui.core.nanogui import DObject
|
||||
from gui.core.writer import Writer
|
||||
|
||||
# text: str display string int save width
|
||||
class Label(DObject):
|
||||
def __init__(self, writer, row, col, text, invert=False, fgcolor=None, bgcolor=None, bdcolor=False):
|
||||
# Determine width of object
|
||||
if isinstance(text, int):
|
||||
width = text
|
||||
text = None
|
||||
else:
|
||||
width = writer.stringlen(text)
|
||||
height = writer.height
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor)
|
||||
if text is not None:
|
||||
self.value(text, invert)
|
||||
|
||||
def value(self, text=None, invert=False, fgcolor=None, bgcolor=None, bdcolor=None):
|
||||
txt = super().value(text)
|
||||
# Redraw even if no text supplied: colors may have changed.
|
||||
self.invert = invert
|
||||
self.fgcolor = self.def_fgcolor if fgcolor is None else fgcolor
|
||||
self.bgcolor = self.def_bgcolor if bgcolor is None else bgcolor
|
||||
if bdcolor is False:
|
||||
self.def_bdcolor = False
|
||||
self.bdcolor = self.def_bdcolor if bdcolor is None else bdcolor
|
||||
self.show()
|
||||
return txt
|
||||
|
||||
def show(self):
|
||||
txt = super().value()
|
||||
if txt is None: # No content to draw. Future use.
|
||||
return
|
||||
super().show() # Draw or erase border
|
||||
wri = self.writer
|
||||
dev = self.device
|
||||
Writer.set_textpos(dev, self.row, self.col)
|
||||
wri.setcolor(self.fgcolor, self.bgcolor)
|
||||
wri.printstring(txt, self.invert)
|
||||
wri.setcolor() # Restore defaults
|
|
@ -0,0 +1,28 @@
|
|||
# led.py LED class for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
from gui.core.nanogui import DObject, fillcircle, circle
|
||||
from gui.widgets.label import Label
|
||||
|
||||
class LED(DObject):
|
||||
def __init__(self, writer, row, col, *, height=12,
|
||||
fgcolor=None, bgcolor=None, bdcolor=None, label=None):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor)
|
||||
if label is not None:
|
||||
self.label = Label(writer, row + height + 3, col, label)
|
||||
self.radius = self.height // 2
|
||||
|
||||
def color(self, c=None):
|
||||
self.fgcolor = self.bgcolor if c is None else c
|
||||
self.show()
|
||||
|
||||
def show(self):
|
||||
super().show()
|
||||
wri = self.writer
|
||||
dev = self.device
|
||||
r = self.radius
|
||||
fillcircle(dev, self.col + r, self.row + r, r, self.fgcolor)
|
||||
if isinstance(self.bdcolor, int):
|
||||
circle(dev, self.col + r, self.row + r, r, self.bdcolor)
|
|
@ -0,0 +1,63 @@
|
|||
# meter.py Meter class for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
from gui.core.nanogui import DObject
|
||||
from gui.widgets.label import Label
|
||||
|
||||
|
||||
class Meter(DObject):
|
||||
BAR = 1
|
||||
LINE = 0
|
||||
def __init__(self, writer, row, col, *, height=50, width=10,
|
||||
fgcolor=None, bgcolor=None, ptcolor=None, bdcolor=None,
|
||||
divisions=5, label=None, style=0, legends=None, value=None):
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor)
|
||||
self.divisions = divisions
|
||||
if label is not None:
|
||||
Label(writer, row + height + 3, col, label)
|
||||
self.style = style
|
||||
self.legends = legends
|
||||
self.ptcolor = ptcolor if ptcolor is not None else self.fgcolor
|
||||
self.value(value)
|
||||
|
||||
def value(self, n=None, color=None):
|
||||
if n is None:
|
||||
return super().value()
|
||||
n = super().value(min(1, max(0, n)))
|
||||
if color is not None:
|
||||
self.ptcolor = color
|
||||
self.show()
|
||||
return n
|
||||
|
||||
def show(self):
|
||||
super().show() # Draw or erase border
|
||||
val = super().value()
|
||||
wri = self.writer
|
||||
dev = self.device
|
||||
width = self.width
|
||||
height = self.height
|
||||
legends = self.legends
|
||||
x0 = self.col
|
||||
x1 = self.col + width
|
||||
y0 = self.row
|
||||
y1 = self.row + height
|
||||
if self.divisions > 0:
|
||||
dy = height / (self.divisions) # Tick marks
|
||||
for tick in range(self.divisions + 1):
|
||||
ypos = int(y0 + dy * tick)
|
||||
dev.hline(x0 + 2, ypos, x1 - x0 - 4, self.fgcolor)
|
||||
|
||||
if legends is not None: # Legends
|
||||
dy = 0 if len(legends) <= 1 else height / (len(legends) -1)
|
||||
yl = y1 - wri.height / 2 # Start at bottom
|
||||
for legend in legends:
|
||||
Label(wri, int(yl), x1 + 4, legend)
|
||||
yl -= dy
|
||||
y = int(y1 - val * height) # y position of slider
|
||||
if self.style == self.LINE:
|
||||
dev.hline(x0, y, width, self.ptcolor) # Draw pointer
|
||||
else:
|
||||
w = width / 2
|
||||
dev.fill_rect(int(x0 + w - 2), y, 4, y1 - y, self.ptcolor)
|
|
@ -0,0 +1,123 @@
|
|||
# scale.py Extension to nano-gui providing the Scale class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
||||
# Usage:
|
||||
# from gui.widgets.scale import Scale
|
||||
|
||||
# NEED print_left, get_stringsize
|
||||
|
||||
from gui.core.nanogui import DObject
|
||||
from gui.core.writer import Writer
|
||||
from gui.core.colors import BLACK
|
||||
|
||||
class Scale(DObject):
|
||||
def __init__(self, writer, row, col, *,
|
||||
ticks=200, legendcb=None, tickcb=None,
|
||||
height=0, width=100, border=2, fgcolor=None, bgcolor=None,
|
||||
pointercolor=None, fontcolor=None):
|
||||
if ticks % 2:
|
||||
raise ValueError('ticks arg must be divisible by 2')
|
||||
self.ticks = ticks
|
||||
self.tickcb = tickcb
|
||||
def lcb(f):
|
||||
return '{:3.1f}'.format(f)
|
||||
self.legendcb = legendcb if legendcb is not None else lcb
|
||||
bgcolor = BLACK if bgcolor is None else bgcolor
|
||||
text_ht = writer.font.height()
|
||||
ctrl_ht = 12 # Minimum height for ticks
|
||||
min_ht = text_ht + 2 * border + 2 # Ht of text, borders and gap between text and ticks
|
||||
if height < min_ht + ctrl_ht:
|
||||
height = min_ht + ctrl_ht # min workable height
|
||||
else:
|
||||
ctrl_ht = height - min_ht # adjust ticks for greater height
|
||||
width &= 0xfffe # Make divisible by 2: avoid 1 pixel pointer offset
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, fgcolor)
|
||||
self.x0 = col + border
|
||||
self.x1 = col + self.width - border
|
||||
self.y0 = row + border
|
||||
self.y1 = row + self.height - border
|
||||
self.ptrcolor = pointercolor if pointercolor is not None else self.fgcolor
|
||||
# Define tick dimensions
|
||||
ytop = self.y0 + text_ht + 2 # Top of scale graphic (2 pixel gap)
|
||||
ycl = ytop + (self.y1 - ytop) // 2 # Centre line
|
||||
self.sdl = round(ctrl_ht * 1 / 3) # Length of small tick.
|
||||
self.sdy0 = ycl - self.sdl // 2
|
||||
self.mdl = round(ctrl_ht * 2 / 3) # Medium tick
|
||||
self.mdy0 = ycl - self.mdl // 2
|
||||
self.ldl = ctrl_ht # Large tick
|
||||
self.ldy0 = ycl - self.ldl // 2
|
||||
|
||||
def show(self):
|
||||
wri = self.writer
|
||||
dev = self.device
|
||||
x0: int = self.x0 # Internal rectangle occupied by scale and text
|
||||
x1: int = self.x1
|
||||
y0: int = self.y0
|
||||
y1: int = self.y1
|
||||
dev.fill_rect(x0, y0, x1 - x0, y1 - y0, self.bgcolor)
|
||||
super().show()
|
||||
# Scale is drawn using ints. Each division is 10 units.
|
||||
val: int = self._value # 0..ticks*10
|
||||
# iv increments for each tick. Its value modulo N determines tick length
|
||||
iv: int # val / 10 at a tick position
|
||||
d: int # val % 10: offset relative to a tick position
|
||||
fx: int # X offset of current tick in value units
|
||||
if val >= 100: # Whole LHS of scale will be drawn
|
||||
iv, d = divmod(val - 100, 10) # Initial value
|
||||
fx = 10 - d
|
||||
iv += 1
|
||||
else: # Scale will scroll right
|
||||
iv = 0
|
||||
fx = 100 - val
|
||||
|
||||
# Window shows 20 divisions, each of which corresponds to 10 units of value.
|
||||
# So pixels per unit value == win_width/200
|
||||
win_width: int = x1 - x0
|
||||
ticks: int = self.ticks # Total # of ticks visible and hidden
|
||||
while True:
|
||||
x: int = x0 + (fx * win_width) // 200 # Current X position
|
||||
ys: int # Start Y position for tick
|
||||
yl: int # tick length
|
||||
if x > x1 or iv > ticks: # Out of space or data (scroll left)
|
||||
break
|
||||
if not iv % 10:
|
||||
txt = self.legendcb(self._fvalue(iv * 10))
|
||||
tlen = wri.stringlen(txt)
|
||||
Writer.set_textpos(dev, y0, min(x, x1 - tlen))
|
||||
wri.setcolor(self.fgcolor, self.bgcolor)
|
||||
wri.printstring(txt)
|
||||
wri.setcolor()
|
||||
ys = self.ldy0 # Large tick
|
||||
yl = self.ldl
|
||||
elif not iv % 5:
|
||||
ys = self.mdy0
|
||||
yl = self.mdl
|
||||
else:
|
||||
ys = self.sdy0
|
||||
yl = self.sdl
|
||||
if self.tickcb is None:
|
||||
color = self.fgcolor
|
||||
else:
|
||||
color = self.tickcb(self._fvalue(iv * 10), self.fgcolor)
|
||||
dev.vline(x, ys, yl, color) # Draw tick
|
||||
fx += 10
|
||||
iv += 1
|
||||
|
||||
dev.vline(x0 + (x1 - x0) // 2, y0, y1 - y0, self.ptrcolor) # Draw pointer
|
||||
|
||||
def _to_int(self, v):
|
||||
return round((v + 1.0) * self.ticks * 5) # 0..self.ticks*10
|
||||
|
||||
def _fvalue(self, v=None):
|
||||
return v / (5 * self.ticks) - 1.0
|
||||
|
||||
def value(self, val=None): # User method to get or set value
|
||||
if val is not None:
|
||||
val = min(max(val, - 1.0), 1.0)
|
||||
v = self._to_int(val)
|
||||
if v != self._value:
|
||||
self._value = v
|
||||
self.show()
|
||||
return self._fvalue(self._value)
|
|
@ -0,0 +1,34 @@
|
|||
# ssd1351_setup.py Customise for your hardware config
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
||||
# Demo of initialisation procedure designed to minimise risk of memory fail
|
||||
# when instantiating the frame buffer. The aim is to do this as early as
|
||||
# possible before importing other modules.
|
||||
|
||||
# WIRING (Adafruit pin nos and names)
|
||||
# Pyb SSD
|
||||
# 3v3 Vin (10)
|
||||
# Gnd Gnd (11)
|
||||
# Y1 DC (3 DC)
|
||||
# Y2 CS (5 OC OLEDCS)
|
||||
# Y3 Rst (4 R RESET)
|
||||
# Y6 CLK (2 CL SCK)
|
||||
# Y8 DATA (1 SI MOSI)
|
||||
|
||||
height = 96 # 1.27 inch 96*128 (rows*cols) display
|
||||
|
||||
import machine
|
||||
import gc
|
||||
from drivers.ssd1351.ssd1351 import SSD1351 as SSD
|
||||
|
||||
height = 96 # 1.27 inch 96*128 (rows*cols) display
|
||||
# height = 128 # 1.5 inch 128*128 display
|
||||
|
||||
pdc = machine.Pin('Y1', machine.Pin.OUT_PP, value=0)
|
||||
pcs = machine.Pin('Y2', machine.Pin.OUT_PP, value=1)
|
||||
prst = machine.Pin('Y3', machine.Pin.OUT_PP, value=1)
|
||||
spi = machine.SPI(2)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs, pdc, prst, height) # Create a display instance
|
Ładowanie…
Reference in New Issue