Badger2040W: Finish core libs, add Badge.
This commit is contained in:
parent
379a1cb3ef
commit
23f792caa9
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
|
@ -0,0 +1,6 @@
|
||||||
|
mustelid inc
|
||||||
|
H. Badger
|
||||||
|
RP2040
|
||||||
|
2MB Flash
|
||||||
|
E ink
|
||||||
|
296x128px
|
|
@ -0,0 +1,171 @@
|
||||||
|
import time
|
||||||
|
import badger2040w
|
||||||
|
import badger_os
|
||||||
|
import jpegdec
|
||||||
|
|
||||||
|
# Global Constants
|
||||||
|
WIDTH = badger2040w.WIDTH
|
||||||
|
HEIGHT = badger2040w.HEIGHT
|
||||||
|
|
||||||
|
IMAGE_WIDTH = 104
|
||||||
|
|
||||||
|
COMPANY_HEIGHT = 30
|
||||||
|
DETAILS_HEIGHT = 20
|
||||||
|
NAME_HEIGHT = HEIGHT - COMPANY_HEIGHT - (DETAILS_HEIGHT * 2) - 2
|
||||||
|
TEXT_WIDTH = WIDTH - IMAGE_WIDTH - 1
|
||||||
|
|
||||||
|
COMPANY_TEXT_SIZE = 0.6
|
||||||
|
DETAILS_TEXT_SIZE = 0.5
|
||||||
|
|
||||||
|
LEFT_PADDING = 5
|
||||||
|
NAME_PADDING = 20
|
||||||
|
DETAIL_SPACING = 10
|
||||||
|
|
||||||
|
BADGE_PATH = "/badges/badge.txt"
|
||||||
|
|
||||||
|
DEFAULT_TEXT = """mustelid inc
|
||||||
|
H. Badger
|
||||||
|
RP2040
|
||||||
|
2MB Flash
|
||||||
|
E ink
|
||||||
|
296x128px
|
||||||
|
/badges/badge.jpg
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Utility functions
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# Reduce the size of a string until it fits within a given width
|
||||||
|
def truncatestring(text, text_size, width):
|
||||||
|
while True:
|
||||||
|
length = display.measure_text(text, text_size)
|
||||||
|
if length > 0 and length > width:
|
||||||
|
text = text[:-1]
|
||||||
|
else:
|
||||||
|
text += ""
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Drawing functions
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
# Draw the badge, including user text
|
||||||
|
def draw_badge():
|
||||||
|
display.set_pen(0)
|
||||||
|
display.clear()
|
||||||
|
|
||||||
|
# Draw badge image
|
||||||
|
jpeg.open_file(badge_image)
|
||||||
|
jpeg.decode(WIDTH - IMAGE_WIDTH, 0)
|
||||||
|
|
||||||
|
# Draw a border around the image
|
||||||
|
display.set_pen(0)
|
||||||
|
display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - 1, 0)
|
||||||
|
display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - IMAGE_WIDTH, HEIGHT - 1)
|
||||||
|
display.line(WIDTH - IMAGE_WIDTH, HEIGHT - 1, WIDTH - 1, HEIGHT - 1)
|
||||||
|
display.line(WIDTH - 1, 0, WIDTH - 1, HEIGHT - 1)
|
||||||
|
|
||||||
|
# Uncomment this if a white background is wanted behind the company
|
||||||
|
# display.set_pen(15)
|
||||||
|
# display.rectangle(1, 1, TEXT_WIDTH, COMPANY_HEIGHT - 1)
|
||||||
|
|
||||||
|
# Draw the company
|
||||||
|
display.set_pen(15) # Change this to 0 if a white background is used
|
||||||
|
display.set_font("serif")
|
||||||
|
display.text(company, LEFT_PADDING, (COMPANY_HEIGHT // 2) + 1, WIDTH, COMPANY_TEXT_SIZE)
|
||||||
|
|
||||||
|
# Draw a white background behind the name
|
||||||
|
display.set_pen(15)
|
||||||
|
display.rectangle(1, COMPANY_HEIGHT + 1, TEXT_WIDTH, NAME_HEIGHT)
|
||||||
|
|
||||||
|
# Draw the name, scaling it based on the available width
|
||||||
|
display.set_pen(0)
|
||||||
|
display.set_font("sans")
|
||||||
|
name_size = 2.0 # A sensible starting scale
|
||||||
|
while True:
|
||||||
|
name_length = display.measure_text(name, name_size)
|
||||||
|
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1:
|
||||||
|
name_size -= 0.01
|
||||||
|
else:
|
||||||
|
display.text(name, (TEXT_WIDTH - name_length) // 2, (NAME_HEIGHT // 2) + COMPANY_HEIGHT + 1, WIDTH, name_size)
|
||||||
|
break
|
||||||
|
|
||||||
|
# Draw a white backgrounds behind the details
|
||||||
|
display.set_pen(15)
|
||||||
|
display.rectangle(1, HEIGHT - DETAILS_HEIGHT * 2, TEXT_WIDTH, DETAILS_HEIGHT - 1)
|
||||||
|
display.rectangle(1, HEIGHT - DETAILS_HEIGHT, TEXT_WIDTH, DETAILS_HEIGHT - 1)
|
||||||
|
|
||||||
|
# Draw the first detail's title and text
|
||||||
|
display.set_pen(0)
|
||||||
|
display.set_font("sans")
|
||||||
|
name_length = display.measure_text(detail1_title, DETAILS_TEXT_SIZE)
|
||||||
|
display.text(detail1_title, LEFT_PADDING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), WIDTH, DETAILS_TEXT_SIZE)
|
||||||
|
display.text(detail1_text, 5 + name_length + DETAIL_SPACING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), WIDTH, DETAILS_TEXT_SIZE)
|
||||||
|
|
||||||
|
# Draw the second detail's title and text
|
||||||
|
name_length = display.measure_text(detail2_title, DETAILS_TEXT_SIZE)
|
||||||
|
display.text(detail2_title, LEFT_PADDING, HEIGHT - (DETAILS_HEIGHT // 2), WIDTH, DETAILS_TEXT_SIZE)
|
||||||
|
display.text(detail2_text, LEFT_PADDING + name_length + DETAIL_SPACING, HEIGHT - (DETAILS_HEIGHT // 2), WIDTH, DETAILS_TEXT_SIZE)
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Program setup
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
# Create a new Badger and set it to update NORMAL
|
||||||
|
display = badger2040w.Badger2040W()
|
||||||
|
display.led(128)
|
||||||
|
display.set_update_speed(badger2040w.UPDATE_NORMAL)
|
||||||
|
|
||||||
|
jpeg = jpegdec.JPEG(display.display)
|
||||||
|
|
||||||
|
# Open the badge file
|
||||||
|
try:
|
||||||
|
badge = open(BADGE_PATH, "r")
|
||||||
|
except OSError:
|
||||||
|
with open(BADGE_PATH, "w") as f:
|
||||||
|
f.write(DEFAULT_TEXT)
|
||||||
|
f.flush()
|
||||||
|
badge = open(BADGE_PATH, "r")
|
||||||
|
|
||||||
|
# Read in the next 6 lines
|
||||||
|
company = badge.readline() # "mustelid inc"
|
||||||
|
name = badge.readline() # "H. Badger"
|
||||||
|
detail1_title = badge.readline() # "RP2040"
|
||||||
|
detail1_text = badge.readline() # "2MB Flash"
|
||||||
|
detail2_title = badge.readline() # "E ink"
|
||||||
|
detail2_text = badge.readline() # "296x128px"
|
||||||
|
badge_image = badge.readline() # /badges/badge.jpg
|
||||||
|
|
||||||
|
# Truncate all of the text (except for the name as that is scaled)
|
||||||
|
company = truncatestring(company, COMPANY_TEXT_SIZE, TEXT_WIDTH)
|
||||||
|
|
||||||
|
detail1_title = truncatestring(detail1_title, DETAILS_TEXT_SIZE, TEXT_WIDTH)
|
||||||
|
detail1_text = truncatestring(detail1_text, DETAILS_TEXT_SIZE,
|
||||||
|
TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail1_title, DETAILS_TEXT_SIZE))
|
||||||
|
|
||||||
|
detail2_title = truncatestring(detail2_title, DETAILS_TEXT_SIZE, TEXT_WIDTH)
|
||||||
|
detail2_text = truncatestring(detail2_text, DETAILS_TEXT_SIZE,
|
||||||
|
TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail2_title, DETAILS_TEXT_SIZE))
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Main program
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
draw_badge()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if display.pressed(badger2040w.BUTTON_A) or display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C) or display.pressed(badger2040w.BUTTON_UP) or display.pressed(badger2040w.BUTTON_DOWN):
|
||||||
|
badger_os.warning(display, "To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt")
|
||||||
|
time.sleep(4)
|
||||||
|
|
||||||
|
draw_badge()
|
||||||
|
|
||||||
|
display.update()
|
||||||
|
|
||||||
|
# If on battery, halt the Badger to save power, it will wake up if any of the front buttons are pressed
|
||||||
|
display.halt()
|
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
|
@ -1,8 +1,8 @@
|
||||||
import badger2040w
|
import badger2040w
|
||||||
from badger2040w import WIDTH
|
from badger2040w import WIDTH
|
||||||
|
|
||||||
TEXT_SIZE = 0.45
|
TEXT_SIZE = 1
|
||||||
LINE_HEIGHT = 16
|
LINE_HEIGHT = 15
|
||||||
|
|
||||||
display = badger2040w.Badger2040W()
|
display = badger2040w.Badger2040W()
|
||||||
display.led(128)
|
display.led(128)
|
||||||
|
@ -18,24 +18,23 @@ display.set_pen(15)
|
||||||
display.text("badgerOS", 3, 4, WIDTH, 1)
|
display.text("badgerOS", 3, 4, WIDTH, 1)
|
||||||
display.text("info", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1)
|
display.text("info", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1)
|
||||||
|
|
||||||
display.set_font("sans")
|
|
||||||
display.set_pen(0)
|
display.set_pen(0)
|
||||||
|
|
||||||
y = 16 + int(LINE_HEIGHT / 2)
|
y = 16 + int(LINE_HEIGHT / 2)
|
||||||
|
|
||||||
display.text("Made by Pimoroni, powered by MicroPython", 0, y, WIDTH, TEXT_SIZE)
|
display.text("Made by Pimoroni, powered by MicroPython", 5, y, WIDTH, TEXT_SIZE)
|
||||||
y += LINE_HEIGHT
|
y += LINE_HEIGHT
|
||||||
display.text("Dual-core RP2040, 133MHz, 264KB RAM", 0, y, WIDTH, TEXT_SIZE)
|
display.text("Dual-core RP2040, 133MHz, 264KB RAM", 5, y, WIDTH, TEXT_SIZE)
|
||||||
y += LINE_HEIGHT
|
y += LINE_HEIGHT
|
||||||
display.text("2MB Flash (1MB OS, 1MB Storage)", 0, y, WIDTH, TEXT_SIZE)
|
display.text("2MB Flash (1MB OS, 1MB Storage)", 5, y, WIDTH, TEXT_SIZE)
|
||||||
y += LINE_HEIGHT
|
y += LINE_HEIGHT
|
||||||
display.text("296x128 pixel Black/White e-Ink", 0, y, WIDTH, TEXT_SIZE)
|
display.text("296x128 pixel Black/White e-Ink", 5, y, WIDTH, TEXT_SIZE)
|
||||||
y += LINE_HEIGHT
|
y += LINE_HEIGHT
|
||||||
y += LINE_HEIGHT
|
y += LINE_HEIGHT
|
||||||
|
|
||||||
display.text("For more info:", 0, y, WIDTH, TEXT_SIZE)
|
display.text("For more info:", 5, y, WIDTH, TEXT_SIZE)
|
||||||
y += LINE_HEIGHT
|
y += LINE_HEIGHT
|
||||||
display.text("https://pimoroni.com/badger2040w", 0, y, WIDTH, TEXT_SIZE)
|
display.text("https://pimoroni.com/badger2040w", 5, y, WIDTH, TEXT_SIZE)
|
||||||
|
|
||||||
display.update()
|
display.update()
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,6 @@ else:
|
||||||
# Otherwise restore previously running app
|
# Otherwise restore previously running app
|
||||||
badger_os.state_launch()
|
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 = badger2040.Badger2040W()
|
||||||
display.set_font("bitmap8")
|
display.set_font("bitmap8")
|
||||||
display.led(128)
|
display.led(128)
|
||||||
|
@ -51,29 +47,6 @@ 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
|
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):
|
def draw_disk_usage(x):
|
||||||
_, f_used, _ = badger_os.get_disk_usage()
|
_, f_used, _ = badger_os.get_disk_usage()
|
||||||
|
|
||||||
|
@ -114,7 +87,8 @@ def render():
|
||||||
for i in range(max_icons):
|
for i in range(max_icons):
|
||||||
x = centers[i]
|
x = centers[i]
|
||||||
label = examples[i + (state["page"] * 3)]
|
label = examples[i + (state["page"] * 3)]
|
||||||
icon = f"{APP_DIR}/icon-{label}.jpg"
|
icon_label = label.replace("_", "-")
|
||||||
|
icon = f"{APP_DIR}/icon-{icon_label}.jpg"
|
||||||
label = label.replace("_", " ")
|
label = label.replace("_", " ")
|
||||||
jpeg.open_file(icon)
|
jpeg.open_file(icon)
|
||||||
jpeg.decode(x - 32, 24)
|
jpeg.decode(x - 32, 24)
|
||||||
|
@ -134,9 +108,6 @@ def render():
|
||||||
display.set_pen(0)
|
display.set_pen(0)
|
||||||
display.rectangle(0, 0, WIDTH, 16)
|
display.rectangle(0, 0, WIDTH, 16)
|
||||||
draw_disk_usage(90)
|
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.set_pen(15)
|
||||||
display.text("badgerOS", 4, 4, WIDTH, 1.0)
|
display.text("badgerOS", 4, 4, WIDTH, 1.0)
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,9 @@ UPDATE_MEDIUM = 1
|
||||||
UPDATE_FAST = 2
|
UPDATE_FAST = 2
|
||||||
UPDATE_TURBO = 3
|
UPDATE_TURBO = 3
|
||||||
|
|
||||||
|
LED = 22
|
||||||
|
ENABLE_3V3 = 10
|
||||||
|
|
||||||
WIDTH = 296
|
WIDTH = 296
|
||||||
HEIGHT = 128
|
HEIGHT = 128
|
||||||
|
|
||||||
|
@ -69,26 +72,39 @@ def system_speed(speed):
|
||||||
class Badger2040W():
|
class Badger2040W():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.display = PicoGraphics(DISPLAY_INKY_PACK)
|
self.display = PicoGraphics(DISPLAY_INKY_PACK)
|
||||||
|
self._led = machine.PWM(machine.Pin(LED))
|
||||||
|
self._led.freq(1000)
|
||||||
|
self._led.duty_u16(0)
|
||||||
|
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
# Glue to redirect calls to PicoGraphics
|
# Glue to redirect calls to PicoGraphics
|
||||||
return getattr(self.display, item)
|
return getattr(self.display, item)
|
||||||
|
|
||||||
def led(self, brightness):
|
def led(self, brightness):
|
||||||
pass
|
brightness = max(0, min(255, brightness))
|
||||||
|
self._led.duty_u16(int(brightness * 256))
|
||||||
|
|
||||||
def invert(self, invert):
|
def invert(self, invert):
|
||||||
pass
|
raise RuntimeError("Display invert not supported in PicoGraphics.")
|
||||||
|
|
||||||
def thickness(self, thickness):
|
def thickness(self, thickness):
|
||||||
print("Thickness!")
|
raise RuntimeError("Thickness not supported in PicoGraphics.")
|
||||||
|
|
||||||
def halt(self):
|
def halt(self):
|
||||||
|
enable = machine.Pin(ENABLE_3V3, machine.Pin.OUT)
|
||||||
|
enable.off()
|
||||||
|
while not self.pressed_any():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def pressed(self, button):
|
def pressed(self, button):
|
||||||
return BUTTONS[button].value() == 1
|
return BUTTONS[button].value() == 1
|
||||||
|
|
||||||
|
def pressed_any(self):
|
||||||
|
for button in BUTTONS.values():
|
||||||
|
if button.value():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
@micropython.native
|
@micropython.native
|
||||||
def icon(self, data, index, data_w, icon_size, x, y):
|
def icon(self, data, index, data_w, icon_size, x, y):
|
||||||
s_x = (index * icon_size) % data_w
|
s_x = (index * icon_size) % data_w
|
||||||
|
|
|
@ -4,3 +4,5 @@ examples/*.jpg
|
||||||
examples/*.py
|
examples/*.py
|
||||||
images/*.jpg
|
images/*.jpg
|
||||||
images/*.txt
|
images/*.txt
|
||||||
|
badges/*.txt
|
||||||
|
badges/*.jpg
|
Loading…
Reference in New Issue