Badger2040W: Add examples and libs.

feature/badger2040w
Phil Howard 2022-11-25 16:48:03 +00:00
rodzic ac2da23c96
commit 81d9b2ab81
10 zmienionych plików z 1205 dodań i 2 usunięć

Wyświetl plik

@ -0,0 +1,3 @@
SSID = ""
PSK = ""
COUNTRY = ""

Wyświetl plik

@ -0,0 +1,160 @@
import time
import machine
import ntptime
import badger2040w
display = badger2040w.Badger2040W()
WIDTH, HEIGHT = display.get_bounds()
display.connect()
# We're going to keep the badger on, so slow down the system clock if on battery
display.set_update_speed(3)
ntptime.settime()
rtc = machine.RTC()
display.set_font("gothic")
cursors = ["year", "month", "day", "hour", "minute"]
set_clock = False
cursor = 0
last = 0
# Set up the buttons
button_down = machine.Pin(badger2040w.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_up = machine.Pin(badger2040w.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_a = machine.Pin(badger2040w.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_b = machine.Pin(badger2040w.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_c = machine.Pin(badger2040w.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
def days_in_month(month, year):
if month == 2 and ((year % 4 == 0 and year % 100 != 0) or year % 400 == 0):
return 29
return (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[month - 1]
# Button handling function
def button(pin):
global last, set_clock, cursor, year, month, day, hour, minute
time.sleep(0.01)
if not pin.value():
return
if button_a.value() and button_c.value():
machine.reset()
adjust = 0
changed = False
if pin == button_b:
set_clock = not set_clock
changed = True
if not set_clock:
rtc.datetime((year, month, day, 0, hour, minute, second, 0))
if set_clock:
if pin == button_c:
cursor += 1
cursor %= len(cursors)
if pin == button_a:
cursor -= 1
cursor %= len(cursors)
if pin == button_up:
adjust = 1
if pin == button_down:
adjust = -1
if cursors[cursor] == "year":
year += adjust
year = max(year, 2022)
day = min(day, days_in_month(month, year))
if cursors[cursor] == "month":
month += adjust
month = min(max(month, 1), 12)
day = min(day, days_in_month(month, year))
if cursors[cursor] == "day":
day += adjust
day = min(max(day, 1), days_in_month(month, year))
if cursors[cursor] == "hour":
hour += adjust
hour %= 24
if cursors[cursor] == "minute":
minute += adjust
minute %= 60
if set_clock or changed:
draw_clock()
# Register the button handling function with the buttons
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
def draw_clock():
hms = "{:02}:{:02}:{:02}".format(hour, minute, second)
ymd = "{:04}/{:02}/{:02}".format(year, month, day)
hms_width = display.measure_text(hms, 1.8)
hms_offset = int((WIDTH / 2) - (hms_width / 2))
h_width = display.measure_text(hms[0:2], 1.8)
mi_width = display.measure_text(hms[3:5], 1.8)
mi_offset = display.measure_text(hms[0:3], 1.8)
ymd_width = display.measure_text(ymd, 1.0)
ymd_offset = int((WIDTH / 2) - (ymd_width / 2))
y_width = display.measure_text(ymd[0:4], 1.0)
m_width = display.measure_text(ymd[5:7], 1.0)
m_offset = display.measure_text(ymd[0:5], 1.0)
d_width = display.measure_text(ymd[8:10], 1.0)
d_offset = display.measure_text(ymd[0:8], 1.0)
display.set_pen(15)
display.clear()
display.set_pen(0)
display.text(hms, hms_offset, 40, 0, 1.8)
display.text(ymd, ymd_offset, 100, 0, 1.0)
if set_clock:
if cursors[cursor] == "year":
display.line(ymd_offset, 120, ymd_offset + y_width, 120)
if cursors[cursor] == "month":
display.line(ymd_offset + m_offset, 120, ymd_offset + m_offset + m_width, 120)
if cursors[cursor] == "day":
display.line(ymd_offset + d_offset, 120, ymd_offset + d_offset + d_width, 120)
if cursors[cursor] == "hour":
display.line(hms_offset, 70, hms_offset + h_width, 70)
if cursors[cursor] == "minute":
display.line(hms_offset + mi_offset, 70, hms_offset + mi_offset + mi_width, 70)
display.update()
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
if (year, month, day) == (2021, 1, 1):
rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0))
last_second = second
while True:
if not set_clock:
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
if second != last_second:
draw_clock()
last_second = second
time.sleep(0.01)

Wyświetl plik

@ -0,0 +1,240 @@
import gc
import time
import math
import badger2040w as badger2040
import launchericons
import badger_os
# Reduce clock speed to 48MHz
badger2040.system_speed(badger2040.SYSTEM_NORMAL)
changed = False
exited_to_launcher = False
woken_by_button = badger2040.woken_by_button() # Must be done before we clear_pressed_to_wake
if badger2040.pressed_to_wake(badger2040.BUTTON_A) and badger2040.pressed_to_wake(badger2040.BUTTON_C):
# Pressing A and C together at start quits app
exited_to_launcher = badger_os.state_clear_running()
else:
# Otherwise restore previously running app
badger_os.state_launch()
# for e.g. 2xAAA batteries, try max 3.4 min 3.0
MAX_BATTERY_VOLTAGE = 4.0
MIN_BATTERY_VOLTAGE = 3.2
display = badger2040.Badger2040W()
display.set_font("bitmap8")
display.led(128)
state = {
"page": 0,
"font_size": 1,
"inverted": False,
"running": "launcher"
}
badger_os.state_load("launcher", state)
display.invert(state["inverted"])
icons = bytearray(launchericons.data())
icons_width = 576
examples = [
("_clock", 0),
("_fonts", 1),
("_ebook", 2),
("_image", 3),
("_list", 4),
("_badge", 5),
("_qrgen", 8),
("_info", 6),
("_help", 7),
]
font_sizes = (0.5, 0.7, 0.9)
# Approximate center lines for buttons A, B and C
centers = (41, 147, 253)
MAX_PAGE = math.ceil(len(examples) / 3)
WIDTH = 296
def map_value(input, in_min, in_max, out_min, out_max):
return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min
def draw_battery(level, x, y):
# Outline
display.set_pen(15)
display.rectangle(x, y, 19, 10)
# Terminal
display.rectangle(x + 19, y + 3, 2, 4)
display.set_pen(0)
display.rectangle(x + 1, y + 1, 17, 8)
if level < 1:
display.set_pen(0)
display.line(x + 3, y, x + 3 + 10, y + 10)
display.line(x + 3 + 1, y, x + 3 + 11, y + 10)
display.set_pen(15)
display.line(x + 2 + 2, y - 1, x + 4 + 12, y + 11)
display.line(x + 2 + 3, y - 1, x + 4 + 13, y + 11)
return
# Battery Bars
display.set_pen(15)
for i in range(4):
if level / 4 > (1.0 * i) / 4:
display.rectangle(i * 4 + x + 2, y + 2, 3, 6)
def draw_disk_usage(x):
_, f_used, _ = badger_os.get_disk_usage()
display.set_pen(15)
display.image(
bytearray(
(
0b00000000,
0b00111100,
0b00111100,
0b00111100,
0b00111000,
0b00000000,
0b00000000,
0b00000001,
)
),
8,
8,
x,
4,
)
display.rectangle(x + 10, 3, 80, 10)
display.set_pen(0)
display.rectangle(x + 11, 4, 78, 8)
display.set_pen(15)
display.rectangle(x + 12, 5, int(76 / 100.0 * f_used), 6)
display.text("{:.2f}%".format(f_used), x + 91, 4, WIDTH, 1.0)
def render():
display.set_pen(15)
display.clear()
display.set_pen(0)
max_icons = min(3, len(examples[(state["page"] * 3):]))
for i in range(max_icons):
x = centers[i]
label, icon = examples[i + (state["page"] * 3)]
label = label[1:].replace("_", " ")
display.set_pen(0)
display.icon(icons, icon, icons_width, 64, x - 32, 24)
w = display.measure_text(label, font_sizes[state["font_size"]])
display.text(label, int(x - (w / 2)), 16 + 80, WIDTH, font_sizes[state["font_size"]])
for i in range(MAX_PAGE):
x = 286
y = int((128 / 2) - (MAX_PAGE * 10 / 2) + (i * 10))
display.set_pen(0)
display.rectangle(x, y, 8, 8)
if state["page"] != i:
display.set_pen(15)
display.rectangle(x + 1, y + 1, 6, 6)
display.set_pen(0)
display.rectangle(0, 0, WIDTH, 16)
draw_disk_usage(90)
vbat = badger_os.get_battery_level()
bat = int(map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, 4))
draw_battery(bat, WIDTH - 22 - 3, 3)
display.set_pen(15)
display.text("badgerOS", 4, 4, WIDTH, 1.0)
display.update()
def wait_for_user_to_release_buttons():
pr = display.pressed
while pr(badger2040.BUTTON_A) or pr(badger2040.BUTTON_B) or pr(badger2040.BUTTON_C) or pr(badger2040.BUTTON_UP) or pr(badger2040.BUTTON_DOWN):
time.sleep(0.01)
def launch_example(index):
wait_for_user_to_release_buttons()
file = examples[(state["page"] * 3) + index][0]
for k in locals().keys():
if k not in ("gc", "file", "badger_os"):
del locals()[k]
gc.collect()
badger_os.launch(file)
def button(pin):
global changed
changed = True
if not display.pressed(badger2040.BUTTON_USER): # User button is NOT held down
if pin == badger2040.BUTTON_A:
launch_example(0)
if pin == badger2040.BUTTON_B:
launch_example(1)
if pin == badger2040.BUTTON_C:
launch_example(2)
if pin == badger2040.BUTTON_UP:
if state["page"] > 0:
state["page"] -= 1
render()
if pin == badger2040.BUTTON_DOWN:
if state["page"] < MAX_PAGE - 1:
state["page"] += 1
render()
else: # User button IS held down
if pin == badger2040.BUTTON_UP:
state["font_size"] += 1
if state["font_size"] == len(font_sizes):
state["font_size"] = 0
render()
if pin == badger2040.BUTTON_DOWN:
state["font_size"] -= 1
if state["font_size"] < 0:
state["font_size"] = 0
render()
if pin == badger2040.BUTTON_A:
state["inverted"] = not state["inverted"]
display.invert(state["inverted"])
render()
if exited_to_launcher or not woken_by_button:
wait_for_user_to_release_buttons()
display.set_update_speed(badger2040.UPDATE_MEDIUM)
render()
display.set_update_speed(badger2040.UPDATE_FAST)
while True:
if display.pressed(badger2040.BUTTON_A):
button(badger2040.BUTTON_A)
if display.pressed(badger2040.BUTTON_B):
button(badger2040.BUTTON_B)
if display.pressed(badger2040.BUTTON_C):
button(badger2040.BUTTON_C)
if display.pressed(badger2040.BUTTON_UP):
button(badger2040.BUTTON_UP)
if display.pressed(badger2040.BUTTON_DOWN):
button(badger2040.BUTTON_DOWN)
if changed:
badger_os.state_save("launcher", state)
changed = False
display.halt()

Wyświetl plik

@ -0,0 +1,297 @@
# Code generated by convert.py.
_data =\
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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\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\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x0f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x01\xff\xfe\x00\x00\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x3f\xfc\x00\x00\x00'\
b'\x00\x00\x00\x0f\xfc\x00\x00\x00\x00\x00\x00\x1f\xf8\x00\x00\x00'\
b'\x03\xff\xf8\x61\x98\x1f\xff\xc0\x00\x00\x0f\xff\xff\xc0\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\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x7f\xfe\x00\x00\x00\x00\x00\x00\x7f\xff\x80\x00\x00'\
b'\x00\x00\x00\xff\xff\x00\x00\x00\x03\xff\xf8\x61\x98\x1f\xff\xc0'\
b'\x00\x00\x3f\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xff\xff\xff\xff\x80\x00'\
b'\x00\x1f\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x7f\xfe\x00\x00\x00'\
b'\x00\x00\x03\xff\xff\xf0\x00\x00\x00\x00\x07\xff\xff\xe0\x00\x00'\
b'\x03\x00\x18\x01\xf9\x98\x00\xc0\x00\x00\x7f\xff\xff\xf8\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x3f\xff\xff\xff\xff\xf0\x00\x00\xff\xff\xff\xff\xff\xfc\x00'\
b'\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x0f\xff\xff\xfc\x00\x00'\
b'\x00\x00\x1f\xff\xff\xf8\x00\x00\x03\x00\x18\x01\xf9\x98\x00\xc0'\
b'\x00\x01\xff\xc0\x0f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\
b'\x01\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\
b'\x00\x00\x1f\xff\xff\xfe\x00\x00\x00\x00\x3f\xff\xff\xfc\x00\x00'\
b'\x03\x3f\x18\x60\x18\x18\xfc\xc0\x00\x03\xfe\x00\x01\xff\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x03\xff\xff\xff\xff\xff\xff\x00'\
b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x00\x7f\xf0\x03\xff\x80\x00'\
b'\x00\x00\xff\xe0\x07\xff\x00\x00\x03\x3f\x18\x60\x18\x18\xfc\xc0'\
b'\x00\x07\xf8\x00\x00\x7f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\
b'\x03\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\
b'\x00\x00\xff\x80\x00\x7f\xc0\x00\x00\x01\xff\x00\x00\xff\x80\x00'\
b'\x03\x3f\x19\x98\x61\x98\xfc\xc0\x00\x0f\xf0\x00\x00\x3f\xc0\x00'\
b'\x00\x00\x03\xff\xff\xff\xfe\x00\x00\x03\xff\x80\x03\xfe\x00\x00'\
b'\x00\xff\xff\xff\xff\xff\xfc\x00\x03\xff\xff\xff\xff\xff\xff\x00'\
b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x01\xfe\x00\x00\x1f\xe0\x00'\
b'\x00\x03\xfc\x00\x00\x3f\xc0\x00\x03\x3f\x19\x98\x61\x98\xfc\xc0'\
b'\x00\x0f\xc0\x00\x00\x0f\xc0\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\
b'\x00\x3f\xff\xf0\x1f\xff\xf0\x00\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\
b'\x00\x03\xfc\x00\x00\x0f\xf0\x00\x00\x07\xf8\x00\x00\x1f\xe0\x00'\
b'\x03\x3f\x19\x87\xe1\x98\xfc\xc0\x00\x1f\x80\x00\x00\x07\xe0\x00'\
b'\x00\x00\x03\xff\xff\xff\xfe\x00\x00\xff\xff\xfe\x3f\xff\xfc\x00'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\
b'\x00\x00\x00\xfc\x3f\x00\x00\x00\x00\x03\xf0\x00\x60\x03\xf0\x00'\
b'\x00\x07\xe0\x00\x00\x07\xe0\x00\x03\x3f\x19\x87\xe1\x98\xfc\xc0'\
b'\x00\x3f\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\
b'\x03\xff\xff\xff\xff\xff\xff\x00\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x00\x00\x00\xfc\x3f\x00\x00\x00'\
b'\x00\x07\xe0\x01\xf8\x01\xf8\x00\x00\x0f\xc0\x00\x00\x03\xf0\x00'\
b'\x03\x00\x18\x79\x98\x18\x00\xc0\x00\x7e\x00\x07\x00\x01\xf8\x00'\
b'\x00\x00\x03\xff\xff\xff\xfe\x00\x03\xff\xff\xff\xff\xff\xff\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\
b'\x00\x0f\xff\xfc\x3f\xff\xf0\x00\x00\x0f\xc0\x01\xf8\x00\xfc\x00'\
b'\x00\x1f\x80\x0f\xe0\x01\xf8\x00\x03\x00\x18\x79\x98\x18\x00\xc0'\
b'\x00\x7e\x00\x07\x00\x01\xf8\x00\x00\x00\x03\xff\xff\xff\xfe\x00'\
b'\x07\xfe\x00\xff\xff\x03\xff\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe3\xff\xc0\x00\x00\x1f\x00\x00\x7f\xff\xfc\x3f\xff\xfe\x00'\
b'\x00\x1f\x80\x01\xfc\x00\x7e\x00\x00\x3f\x00\x3f\xf0\x00\xfc\x00'\
b'\x03\x00\x18\x79\x98\x18\x00\xc0\x00\xfc\x00\x07\x00\x00\xfc\x00'\
b'\x00\x00\x03\xff\xff\xff\xfe\x00\x07\xe0\x00\x1f\xf0\x00\x1f\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\
b'\x00\xff\xff\xfc\x3f\xff\xff\x00\x00\x1f\x80\x01\xf8\x00\x7e\x00'\
b'\x00\x3f\x00\x7f\xf8\x00\xfc\x00\x03\xff\xf9\x99\x99\x9f\xff\xc0'\
b'\x00\xf8\x00\x07\x00\x00\x7c\x00\x00\x00\x00\x00\x3f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\xc0\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xff\xff\xfc\x3f\xff\xff\x80'\
b'\x00\x3f\x00\x01\xf8\x00\x3f\x00\x00\x7e\x00\xff\xfc\x00\x7e\x00'\
b'\x03\xff\xf9\x99\x99\x9f\xff\xc0\x00\xf8\x00\x07\x00\x00\x7c\x00'\
b'\x00\x00\x00\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\
b'\x01\xff\xff\xfc\x3f\xff\xff\x80\x00\x3e\x00\x00\xf0\x00\x1f\x00'\
b'\x00\x7c\x01\xfc\xfe\x00\x3e\x00\x00\x00\x00\x61\x9f\x80\x00\x00'\
b'\x01\xf0\x00\x07\x00\x00\x3e\x00\x00\x00\x00\x00\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x00\xff\xff\x00\x0f\x80'\
b'\x00\x3e\x00\x00\x00\x00\x1f\x00\x00\x7c\x03\xf0\x3f\x00\x3e\x00'\
b'\x00\x00\x00\x61\x9f\x80\x00\x00\x01\xf0\x00\x07\x00\x00\x3e\x00'\
b'\x00\x00\x00\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\
b'\x01\xf0\x00\x7f\xfe\x00\x0f\x80\x00\x7c\x00\x00\x00\x00\x0f\x80'\
b'\x00\xf8\x03\xe0\x1f\x00\x1f\x00\x03\xc0\xfe\x78\x60\x00\xf0\x00'\
b'\x01\xf0\x00\x07\x00\x00\x3e\x00\x00\x00\x00\x00\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe0\x00\x00\x00\x06\x1f\x00\x01\xf0\x00\x7f\xfe\x00\x0f\x80'\
b'\x00\x7c\x00\x3f\x80\x00\x0f\x80\x00\xf8\x03\xc0\x0f\x00\x1f\x00'\
b'\x03\xc0\xfe\x78\x60\x00\xf0\x00\x01\xe0\x00\x07\x00\x00\x1e\x00'\
b'\x00\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x0f\x1f\x00'\
b'\x01\xf0\x00\x3f\xfc\x00\x0f\x80\x00\x7c\x00\x7f\xe0\x00\x0f\x80'\
b'\x00\xf8\x03\xc0\x0f\x80\x1f\x00\x03\xff\x00\x1f\xff\x87\xff\x00'\
b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe0\x00\x00\x00\x1f\x9f\x00\x01\xf0\x00\x1f\xf8\x00\x0f\x80'\
b'\x00\x78\x00\xff\xf0\x00\x07\x80\x00\xf0\x03\xc0\x0f\x80\x0f\x00'\
b'\x03\xff\x00\x1f\xff\x87\xff\x00\x03\xe0\x00\x07\x00\x00\x1f\x00'\
b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x3f\x9f\x00'\
b'\x01\xf0\x00\x07\xe0\x00\x0f\x80\x00\xf8\x00\x7f\xf0\x00\x07\xc0'\
b'\x01\xf0\x03\xc0\x0f\x80\x0f\x80\x03\xcf\xf8\x61\xff\xe7\x33\xc0'\
b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe0\x00\x00\x20\x7f\x1f\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\
b'\x00\xf8\x00\x7f\xf0\x00\x07\xc0\x01\xf0\x00\x00\x1f\x00\x0f\x80'\
b'\x03\xcf\xf8\x61\xff\xe7\x33\xc0\x03\xe0\x00\x07\x00\x00\x1f\x00'\
b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe7\xff\xc0\x70\xfe\x1f\x00'\
b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\xf8\x00\x07\xf0\x00\x07\xc0'\
b'\x01\xf0\x00\x00\x7f\x00\x0f\x80\x00\x33\xe1\x9f\x98\x78\xf0\xc0'\
b'\x03\xe0\x00\x07\x00\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe7\xff\xc0\xf9\xfc\x1f\x00\x01\xf0\x01\xc0\x07\xfe\x0f\x80'\
b'\x00\xf8\x00\x07\xf0\x00\x07\xc0\x01\xf0\x00\x00\xfe\x00\x0f\x80'\
b'\x00\x33\xe1\x9f\x98\x78\xf0\xc0\x03\xe0\x00\x07\xc0\x00\x1f\x00'\
b'\x01\xff\xff\xfc\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x00\x00\x08\x00\xfc\x00\x03\xe7\xff\xc1\xff\xf8\x1f\x00'\
b'\x01\xf0\x03\xe0\x07\xfe\x0f\x80\x00\xf8\x00\x07\xf0\x00\x07\xc0'\
b'\x01\xf0\x00\x03\xfe\x00\x0f\x80\x03\x00\x19\xfe\x01\x9f\x00\xc0'\
b'\x03\xe0\x00\x07\xe0\x00\x1f\x00\x01\xff\xff\xfc\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x00\x00\x1c\x00\xfc\x00'\
b'\x03\xe7\xff\xc0\xff\xf0\x1f\x00\x01\xf0\x07\xf0\x07\xfe\x0f\x80'\
b'\x00\xf8\x00\x0f\xe0\x00\x07\xc0\x01\xf0\x00\x03\xf8\x00\x0f\x80'\
b'\x03\x00\x19\xfe\x01\x9f\x00\xc0\x03\xe0\x00\x03\xf8\x00\x1f\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x00\x00\x3e\x00\xfc\x00\x03\xe0\x00\x00\x7f\xe0\x1f\x00'\
b'\x01\xf0\x07\xf0\x07\xfe\x0f\x80\x00\xf8\x00\x0f\xe0\x00\x07\xc0'\
b'\x01\xf0\x00\x07\xf0\x00\x0f\x80\x03\xcc\x07\x9f\x87\x87\x03\x00'\
b'\x01\xe0\x00\x00\xfe\x00\x1e\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x01\x00\x7e\x00\xfc\x00'\
b'\x03\xe0\x00\x00\x3f\xc0\x1f\x00\x01\xf0\x07\xf0\x00\x00\x0f\x80'\
b'\x00\xf8\x00\x0f\xe0\x00\x07\xc0\x01\xf0\x00\x07\xc0\x00\x0f\x80'\
b'\x03\xcc\x07\x9f\x87\x87\x03\x00\x01\xf0\x00\x00\x3f\x00\x3e\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x03\x80\x7f\x00\xfc\x00\x03\xe0\x00\x00\x1f\x80\x1f\x00'\
b'\x01\xf0\x07\xf0\x00\x00\x0f\x80\x00\x78\x00\x0f\xe0\x00\x07\x80'\
b'\x00\xf0\x00\x0f\x80\x00\x0f\x00\x03\x3c\xfe\x19\xe6\x60\x33\xc0'\
b'\x01\xf0\x00\x00\x1f\xc0\x3e\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x07\xc0\xff\x80\xfc\x00'\
b'\x03\xe0\x00\x00\x0f\x00\x1f\x00\x01\xf0\x03\xe0\x00\x00\x0f\x80'\
b'\x00\x7c\x00\x0f\xe0\x00\x0f\x80\x00\xf8\x00\x0f\x80\x00\x1f\x00'\
b'\x03\x3c\xfe\x19\xe6\x60\x33\xc0\x01\xf0\x00\x00\x07\xe0\x3e\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x07\xe1\xff\xc0\xfc\x00\x03\xe0\x00\x00\x06\x00\x1f\x00'\
b'\x01\xf0\x00\x00\x07\xfe\x0f\x80\x00\x7c\x00\x1f\xe0\x00\x0f\x80'\
b'\x00\xf8\x00\x0f\x80\x00\x1f\x00\x03\x0f\xe1\x87\x9e\x60\xcc\xc0'\
b'\x00\xf8\x00\x00\x01\xe0\x7c\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x0f\xe3\xff\xc0\xfc\x00'\
b'\x03\xe3\xff\xc0\x00\x00\x1f\x00\x01\xf0\x00\x00\x07\xfe\x0f\x80'\
b'\x00\x7c\x00\x1f\xc0\x00\x0f\x80\x00\xf8\x00\x07\x00\x00\x1f\x00'\
b'\x03\x0f\xe1\x87\x9e\x60\xcc\xc0\x00\xf8\x00\x00\x00\xc0\x7c\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x1f\xf7\xff\xe0\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\
b'\x01\xf0\x01\xc0\x07\xfe\x0f\x80\x00\x3e\x00\x1f\xc0\x00\x1f\x00'\
b'\x00\x7c\x00\x00\x00\x00\x3e\x00\x03\x3c\xfe\x00\x79\xff\xcc\x00'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x3f\xff\xff\xf0\xfc\x00'\
b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x1f\xfc\x07\xfe\x0f\x80'\
b'\x00\x3e\x00\x1f\xc0\x00\x1f\x00\x00\x7c\x00\x00\x00\x00\x3e\x00'\
b'\x03\x3c\xfe\x00\x79\xff\xcc\x00\x00\x7e\x00\x00\x00\x01\xf8\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe0\x00\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\x7f\xff\xff\xf8\xfc\x00\x03\xe7\xff\xc0\x00\x00\x1f\x00'\
b'\x01\xf0\x3f\xfe\x00\x00\x0f\x80\x00\x3f\x00\x1f\xc0\x00\x3f\x00'\
b'\x00\x7e\x00\x02\x00\x00\x7e\x00\x00\x00\x01\xfe\x01\x80\xcc\x00'\
b'\x00\x7e\x00\x00\x00\x01\xf8\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\
b'\x07\xe0\x00\x0f\x80\x00\x1f\x80\x00\xfc\x7f\xff\xff\xf8\xfc\x00'\
b'\x03\xe7\xff\xc0\x00\x00\x1f\x00\x01\xf0\x7f\xff\x00\x00\x0f\x80'\
b'\x00\x1f\x80\x1f\xc7\x00\x7e\x00\x00\x3f\x00\x0f\x80\x00\xfc\x00'\
b'\x00\x00\x01\xfe\x01\x80\xcc\x00\x00\x3f\x00\x00\x00\x03\xf0\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xe3\xff\x0f\x80\x00\x1f\x80'\
b'\x00\xfc\xff\xff\xff\xfc\xfc\x00\x03\xe3\xff\xc0\x00\x00\x1f\x00'\
b'\x01\xf0\x7f\xff\x00\x00\x0f\x80\x00\x1f\x80\x1f\xcf\x00\x7e\x00'\
b'\x00\x3f\x00\x0f\x80\x00\xfc\x00\x03\xff\xf9\xfe\x79\x98\xf0\xc0'\
b'\x00\x1f\x80\x00\x00\x07\xe0\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\
b'\x07\xff\xff\xff\x83\xff\x1f\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x01\xf0\x7f\xff\x00\x00\x0f\x80'\
b'\x00\x0f\xc0\x0f\xff\x00\xfc\x00\x00\x1f\x80\x0f\x80\x01\xf8\x00'\
b'\x03\xff\xf9\xfe\x79\x98\xf0\xc0\x00\x0f\xc0\x00\x00\x0f\xc0\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xff\xff\xff\x8f\xff\xff\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\
b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x07\xe0\x07\xff\x01\xf8\x00'\
b'\x00\x0f\xc0\x0f\x80\x03\xf0\x00\x03\x00\x19\x80\x1f\x80\xc0\x00'\
b'\x00\x0f\xf0\x00\x00\x3f\xc0\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\
b'\x07\xff\xff\xff\xbf\xff\xff\x80\x00\xfc\x00\x00\x00\x00\xfc\x00'\
b'\x03\xe0\x00\x00\x00\x00\x1f\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\
b'\x00\x03\xf0\x03\xfc\x03\xf0\x00\x00\x07\xe0\x07\x00\x07\xe0\x00'\
b'\x03\x00\x19\x80\x1f\x80\xc0\x00\x00\x07\xf8\x00\x00\x7f\x80\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x07\xff\xff\xff\xff\xff\xff\x80'\
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x03\xe0\x00\x00\x00\x00\x1f\x00'\
b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x03\xfc\x00\x70\x0f\xf0\x00'\
b'\x00\x07\xf8\x00\x00\x1f\xe0\x00\x03\x00\x19\x80\x1f\x80\xc0\x00'\
b'\x00\x03\xfe\x00\x01\xff\x00\x00\x00\x01\xfe\x00\x1f\xe0\x00\x00'\
b'\x07\xfe\x01\xff\xff\xff\xff\x80\x00\xff\xff\xff\xff\xff\xfc\x00'\
b'\x03\xff\xff\xff\xff\xff\xff\x00\x01\xf0\x00\x00\x00\x00\x0f\x80'\
b'\x00\x01\xfe\x00\x00\x1f\xe0\x00\x00\x03\xfc\x00\x00\x3f\xc0\x00'\
b'\x03\x3f\x18\x01\xff\xff\xff\x00\x00\x01\xff\xc0\x0f\xfe\x00\x00'\
b'\x00\x01\xfe\x00\x1f\xe0\x00\x00\x03\xf0\x00\x1f\xfe\x01\xff\x80'\
b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x03\xff\xff\xff\xff\xff\xff\x00'\
b'\x01\xf0\x00\x00\x00\x00\x0f\x80\x00\x00\xff\x80\x00\x7f\xc0\x00'\
b'\x00\x01\xff\x00\x00\xff\x80\x00\x03\x3f\x18\x01\xff\xff\xff\x00'\
b'\x00\x00\x7f\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x01\x80\x00\x07\xf8\x00\x3f\x00\x00\x7f\xff\xff\xff\xff\xf8\x00'\
b'\x03\xff\xff\xff\xff\xff\xff\x00\x01\xff\xff\xff\xff\xff\xff\x80'\
b'\x00\x00\x7f\xf0\x03\xff\x80\x00\x00\x00\xff\xe0\x07\xff\x00\x00'\
b'\x03\x3f\x18\x66\x1e\x7f\x33\xc0\x00\x00\x3f\xff\xff\xf0\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xe0\x00\x06\x00'\
b'\x00\x7f\xff\xff\xff\xff\xf8\x00\x01\xff\xff\xff\xff\xff\xfe\x00'\
b'\x01\xff\xff\xff\xff\xff\xff\x80\x00\x00\x1f\xff\xff\xfe\x00\x00'\
b'\x00\x00\x3f\xff\xff\xfc\x00\x00\x03\x3f\x18\x66\x1e\x7f\x33\xc0'\
b'\x00\x00\x0f\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x3f\xff\xff\xff\xff\xf0\x00'\
b'\x00\xff\xff\xff\xff\xff\xfc\x00\x00\xff\xff\xff\xff\xff\xff\x00'\
b'\x00\x00\x0f\xff\xff\xfc\x00\x00\x00\x00\x1f\xff\xff\xf8\x00\x00'\
b'\x03\x3f\x18\x18\x19\xe7\x0c\xc0\x00\x00\x01\xff\xfe\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\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x7f\xff\xff\xff\xff\xfe\x00\x00\x00\x03\xff\xff\xf0\x00\x00'\
b'\x00\x00\x07\xff\xff\xe0\x00\x00\x03\x3f\x18\x18\x19\xe7\x0c\xc0'\
b'\x00\x00\x00\x3f\xf0\x00\x00\x00\x00\x00\x00\x00\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\x00\x00\x3f\xff\xff\xff\xff\xfc\x00'\
b'\x00\x00\x00\x7f\xff\x80\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00'\
b'\x03\x00\x19\xe6\x01\x9f\xc0\xc0\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xfc\x00\x00\x00'\
b'\x00\x00\x00\x1f\xf8\x00\x00\x00\x03\x00\x19\xe6\x01\x9f\xc0\xc0'\
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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x03\xff\xf9\xe7\x81\xe0\x30\xc0\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x03\xff\xf9\xe7\x81\xe0\x30\xc0'\
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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\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\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
_mvdata = memoryview(_data)
def data():
return _mvdata

Wyświetl plik

@ -0,0 +1,133 @@
import machine
from picographics import PicoGraphics, DISPLAY_INKY_PACK
from network_manager import NetworkManager
import WIFI_CONFIG
import uasyncio
import gc
import wakeup
BUTTON_UP = 15
BUTTON_DOWN = 11
BUTTON_A = 12
BUTTON_B = 13
BUTTON_C = 14
BUTTON_USER = 23
BUTTON_MASK = 0b11111 << 11
SYSTEM_VERY_SLOW = 0
SYSTEM_SLOW = 1
SYSTEM_NORMAL = 2
SYSTEM_FAST = 3
SYSTEM_TURBO = 4
UPDATE_NORMAL = 0
UPDATE_MEDIUM = 1
UPDATE_FAST = 2
UPDATE_TURBO = 3
WIDTH = 296
HEIGHT = 128
SYSTEM_FREQS = [
4000000,
12000000,
48000000,
133000000,
250000000
]
WAKEUP_GPIO_STATE = wakeup.get_gpio_state()
BUTTONS = {
11: machine.Pin(11),
12: machine.Pin(12),
13: machine.Pin(13),
14: machine.Pin(14),
15: machine.Pin(15),
23: machine.Pin(23)
}
def woken_by_button():
return WAKEUP_GPIO_STATE & BUTTON_MASK > 0
def pressed_to_wake(button):
return WAKEUP_GPIO_STATE & (1 << button) > 0
def system_speed(speed):
try:
machine.freq(SYSTEM_FREQS[speed])
except IndexError:
pass
class Badger2040W():
def __init__(self):
self.display = PicoGraphics(DISPLAY_INKY_PACK)
def __getattr__(self, item):
# Glue to redirect calls to PicoGraphics
if item in dir(self.display):
return getattr(self.display, item)
elif item in self.__dict__.keys():
return getattr(self, item)
else:
raise AttributeError(f"No attribute '{item}'")
def led(self, brightness):
pass
def invert(self, invert):
pass
def thickness(self, thickness):
print("Thickness!")
def halt(self):
pass
def pressed(self, button):
return BUTTONS[button].value() == 1
@micropython.native
def icon(self, data, index, data_w, icon_size, x, y):
s_x = (index * icon_size) % data_w
s_y = int((index * icon_size) / data_w)
for o_y in range(icon_size):
for o_x in range(icon_size):
o = ((o_y + s_y) * data_w) + (o_x + s_x)
bm = 0b10000000 >> (o & 0b111)
if data[o >> 3] & bm:
self.display.pixel(x + o_x, y + o_y)
def image(self, data, w, h, x, y):
for oy in range(h):
row = data[oy]
for ox in range(w):
if row & 0b1 == 0:
self.display.pixel(x + ox, y + oy)
row >>= 1
def status_handler(self, mode, status, ip):
print(mode, status, ip)
self.display.set_pen(15)
self.display.clear()
self.display.set_pen(0)
if status:
self.display.text("Connected!", 10, 10, 300, 0.5)
self.display.text(ip, 10, 30, 300, 0.5)
else:
self.display.text("Connecting...", 10, 10, 300, 0.5)
self.display.update()
def connect(self):
self.display.set_update_speed(2)
network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=self.status_handler)
uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))
gc.collect()

Wyświetl plik

@ -0,0 +1,185 @@
"""Keep track of app state in persistent flash storage."""
import os
import gc
import time
import json
import machine
import badger2040w as badger2040
def get_battery_level():
return 0
# Battery measurement
vbat_adc = machine.ADC(badger2040.PIN_BATTERY)
vref_adc = machine.ADC(badger2040.PIN_1V2_REF)
vref_en = machine.Pin(badger2040.PIN_VREF_POWER)
vref_en.init(machine.Pin.OUT)
vref_en.value(0)
# Enable the onboard voltage reference
vref_en.value(1)
# Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries
vdd = 1.24 * (65535 / vref_adc.read_u16())
vbat = (
(vbat_adc.read_u16() / 65535) * 3 * vdd
) # 3 in this is a gain, not rounding of 3.3V
# Disable the onboard voltage reference
vref_en.value(0)
# Convert the voltage to a level to display onscreen
return vbat
def get_disk_usage():
# f_bfree and f_bavail should be the same?
# f_files, f_ffree, f_favail and f_flag are unsupported.
f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs("/")
f_total_size = f_frsize * f_blocks
f_total_free = f_bsize * f_bfree
f_total_used = f_total_size - f_total_free
f_used = 100 / f_total_size * f_total_used
f_free = 100 / f_total_size * f_total_free
return f_total_size, f_used, f_free
def state_running():
state = {"running": "launcher"}
state_load("launcher", state)
return state["running"]
def state_clear_running():
running = state_running()
state_modify("launcher", {"running": "launcher"})
return running != "launcher"
def state_set_running(app):
state_modify("launcher", {"running": app})
def state_launch():
app = state_running()
if app is not None and app != "launcher":
launch("_" + app)
def state_delete(app):
try:
os.remove("/state/{}.json".format(app))
except OSError:
pass
def state_save(app, data):
try:
with open("/state/{}.json".format(app), "w") as f:
f.write(json.dumps(data))
f.flush()
except OSError:
import os
try:
os.stat("/state")
except OSError:
os.mkdir("/state")
state_save(app, data)
def state_modify(app, data):
state = {}
state_load(app, state)
state.update(data)
state_save(app, state)
def state_load(app, defaults):
try:
data = json.loads(open("/state/{}.json".format(app), "r").read())
if type(data) is dict:
defaults.update(data)
return True
except (OSError, ValueError):
pass
state_save(app, defaults)
return False
def launch(file):
state_set_running(file[1:])
gc.collect()
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
def quit_to_launcher(pin):
if button_a.value() and button_c.value():
machine.reset()
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher)
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher)
try:
try:
__import__(file[1:]) # Try to import _[file] (drop underscore prefix)
except ImportError:
__import__(file) # Failover to importing [_file]
except ImportError:
# If the app doesn't exist, notify the user
warning(None, "Could not launch: " + file[1:])
time.sleep(4.0)
except Exception as e:
# If the app throws an error, catch it and display!
print(e)
warning(None, str(e))
time.sleep(4.0)
# If the app exits or errors, do not relaunch!
state_clear_running()
machine.reset() # Exit back to launcher
# Draw an overlay box with a given message within it
def warning(display, message, width=badger2040.WIDTH - 40, height=badger2040.HEIGHT - 40, line_spacing=20, text_size=0.6):
print(message)
if display is None:
display = badger2040.Badger2040W()
display.led(128)
# Draw a light grey background
display.set_pen(12)
display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height)
# Take the provided message and split it up into
# lines that fit within the specified width
words = message.split(" ")
lines = []
current_line = ""
for word in words:
if display.measure_text(current_line + word + " ", text_size) < width:
current_line += word + " "
else:
lines.append(current_line.strip())
current_line = word + " "
lines.append(current_line.strip())
display.set_pen(0)
# Display each line of text from the message, centre-aligned
num_lines = len(lines)
for i in range(num_lines):
length = display.measure_text(lines[i], text_size)
current_line = (i * line_spacing) - ((num_lines - 1) * line_spacing) // 2
display.text(lines[i], (badger2040.WIDTH - length) // 2, (badger2040.HEIGHT // 2) + current_line, badger2040.WIDTH, text_size)
display.update()

Wyświetl plik

@ -0,0 +1,107 @@
import rp2
import network
import machine
import uasyncio
class NetworkManager:
_ifname = ("Client", "Access Point")
def __init__(self, country="GB", client_timeout=30, access_point_timeout=5, status_handler=None, error_handler=None):
rp2.country(country)
self._ap_if = network.WLAN(network.AP_IF)
self._sta_if = network.WLAN(network.STA_IF)
self._mode = network.STA_IF
self._client_timeout = client_timeout
self._access_point_timeout = access_point_timeout
self._status_handler = status_handler
self._error_handler = error_handler
self.UID = ("{:02X}" * 8).format(*machine.unique_id())
def isconnected(self):
return self._sta_if.isconnected() or self._ap_if.isconnected()
def config(self, var):
if self._sta_if.active():
return self._sta_if.config(var)
else:
if var == "password":
return self.UID
return self._ap_if.config(var)
def mode(self):
if self._sta_if.isconnected():
return self._ifname[0]
if self._ap_if.isconnected():
return self._ifname[1]
return None
def ifaddress(self):
if self._sta_if.isconnected():
return self._sta_if.ifconfig()[0]
if self._ap_if.isconnected():
return self._ap_if.ifconfig()[0]
return '0.0.0.0'
def disconnect(self):
if self._sta_if.isconnected():
self._sta_if.disconnect()
if self._ap_if.isconnected():
self._ap_if.disconnect()
async def wait(self, mode):
while not self.isconnected():
self._handle_status(mode, None)
await uasyncio.sleep_ms(1000)
def _handle_status(self, mode, status):
if callable(self._status_handler):
self._status_handler(self._ifname[mode], status, self.ifaddress())
def _handle_error(self, mode, msg):
if callable(self._error_handler):
if self._error_handler(self._ifname[mode], msg):
return
raise RuntimeError(msg)
async def client(self, ssid, psk):
if self._sta_if.isconnected():
self._handle_status(network.STA_IF, True)
return
self._ap_if.disconnect()
self._ap_if.active(False)
self._sta_if.active(True)
self._sta_if.connect(ssid, psk)
try:
await uasyncio.wait_for(self.wait(network.STA_IF), self._client_timeout)
self._handle_status(network.STA_IF, True)
except uasyncio.TimeoutError:
self._sta_if.active(False)
self._handle_status(network.STA_IF, False)
self._handle_error(network.STA_IF, "WIFI Client Failed")
async def access_point(self):
if self._ap_if.isconnected():
self._handle_status(network.AP_IF, True)
return
self._sta_if.disconnect()
self._sta_if.active(False)
self._ap_if.ifconfig(("10.10.1.1", "255.255.255.0", "10.10.1.1", "10.10.1.1"))
self._ap_if.config(password=self.UID)
self._ap_if.active(True)
try:
await uasyncio.wait_for(self.wait(network.AP_IF), self._access_point_timeout)
self._handle_status(network.AP_IF, True)
except uasyncio.TimeoutError:
self._sta_if.active(False)
self._handle_status(network.AP_IF, False)
self._handle_error(network.AP_IF, "WIFI Client Failed")

Wyświetl plik

@ -0,0 +1,67 @@
import usocket
def urlopen(url, data=None, method="GET"):
if data is not None and method == "GET":
method = "POST"
try:
proto, dummy, host, path = url.split("/", 3)
except ValueError:
proto, dummy, host = url.split("/", 2)
path = ""
if proto == "http:":
port = 80
elif proto == "https:":
import ussl
port = 443
else:
raise ValueError("Unsupported protocol: " + proto)
if ":" in host:
host, port = host.split(":", 1)
port = int(port)
ai = usocket.getaddrinfo(host, port, 0, usocket.SOCK_STREAM)
ai = ai[0]
s = usocket.socket(ai[0], ai[1], ai[2])
try:
s.connect(ai[-1])
if proto == "https:":
s = ussl.wrap_socket(s, server_hostname=host)
s.write(method)
s.write(b" /")
s.write(path)
s.write(b" HTTP/1.0\r\nHost: ")
s.write(host)
s.write(b"\r\n")
if data:
s.write(b"Content-Length: ")
s.write(str(len(data)))
s.write(b"\r\n")
s.write(b"\r\n")
if data:
s.write(data)
l = s.readline()
l = l.split(None, 2)
# print(l)
status = int(l[1])
while True:
l = s.readline()
if not l or l == b"\r\n":
break
# print(l)
if l.startswith(b"Transfer-Encoding:"):
if b"chunked" in l:
raise ValueError("Unsupported " + l)
elif l.startswith(b"Location:"):
raise NotImplementedError("Redirects not yet supported")
except OSError:
s.close()
raise
return s

Wyświetl plik

@ -1 +1,10 @@
# Hello World
import WIFI_CONFIG
if WIFI_CONFIG.SSID == "":
import badger2040w
badger2040w.init()
badger2040w.screen.set_pen(15)
badger2040w.screen.clear()
badger2040w.screen.set_pen(0)
badger2040w.screen.text("Please configure your WiFi in WIFI_CONFIG.py")
badger2040w.screen.update()

Wyświetl plik

@ -1 +1,3 @@
main.py
*.py
lib/*.py
lib/urllib/*.py