Badger2040W: Finish core libs, add Badge.

This commit is contained in:
Phil Howard 2023-01-19 12:17:31 +00:00 committed by Phil Howard
parent 379a1cb3ef
commit 23f792caa9
10 changed files with 210 additions and 45 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -0,0 +1,6 @@
mustelid inc
H. Badger
RP2040
2MB Flash
E ink
296x128px

View File

@ -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

View File

@ -1,8 +1,8 @@
import badger2040w
from badger2040w import WIDTH
TEXT_SIZE = 0.45
LINE_HEIGHT = 16
TEXT_SIZE = 1
LINE_HEIGHT = 15
display = badger2040w.Badger2040W()
display.led(128)
@ -18,24 +18,23 @@ display.set_pen(15)
display.text("badgerOS", 3, 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)
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
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
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
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
display.text("For more info:", 0, y, WIDTH, TEXT_SIZE)
display.text("For more info:", 5, y, WIDTH, TEXT_SIZE)
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()

View File

@ -20,10 +20,6 @@ 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)
@ -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
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()
@ -114,7 +87,8 @@ def render():
for i in range(max_icons):
x = centers[i]
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("_", " ")
jpeg.open_file(icon)
jpeg.decode(x - 32, 24)
@ -134,9 +108,6 @@ def render():
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)

View File

@ -28,6 +28,9 @@ UPDATE_MEDIUM = 1
UPDATE_FAST = 2
UPDATE_TURBO = 3
LED = 22
ENABLE_3V3 = 10
WIDTH = 296
HEIGHT = 128
@ -69,26 +72,39 @@ def system_speed(speed):
class Badger2040W():
def __init__(self):
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):
# Glue to redirect calls to PicoGraphics
return getattr(self.display, item)
def led(self, brightness):
pass
brightness = max(0, min(255, brightness))
self._led.duty_u16(int(brightness * 256))
def invert(self, invert):
pass
raise RuntimeError("Display invert not supported in PicoGraphics.")
def thickness(self, thickness):
print("Thickness!")
raise RuntimeError("Thickness not supported in PicoGraphics.")
def halt(self):
pass
enable = machine.Pin(ENABLE_3V3, machine.Pin.OUT)
enable.off()
while not self.pressed_any():
pass
def pressed(self, button):
return BUTTONS[button].value() == 1
def pressed_any(self):
for button in BUTTONS.values():
if button.value():
return True
return False
@micropython.native
def icon(self, data, index, data_w, icon_size, x, y):
s_x = (index * icon_size) % data_w

View File

@ -4,3 +4,5 @@ examples/*.jpg
examples/*.py
images/*.jpg
images/*.txt
badges/*.txt
badges/*.jpg