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
|
||||
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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,3 +4,5 @@ examples/*.jpg
|
|||
examples/*.py
|
||||
images/*.jpg
|
||||
images/*.txt
|
||||
badges/*.txt
|
||||
badges/*.jpg
|
Loading…
Reference in New Issue