Merge pull request #4 from adafruit/working_on_stuff

Several updates
This commit is contained in:
Scott Shawcroft 2025-04-30 15:06:41 -07:00 committed by GitHub
commit cec3533a3a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 106 additions and 21 deletions

View file

@ -1,7 +1,19 @@
import os
import time
import zipfile
import shutil
from pathlib import Path
import requests
LEARN_PROJECT_URLS = [
"https://cdn-learn.adafruit.com/downloads/zip/3194974/Metro/Metro_RP2350_Snake.zip?timestamp={}",
"https://cdn-learn.adafruit.com/downloads/zip/3195762/Metro/Metro_RP2350_Memory/memory_game.zip?timestamp={}",
"https://cdn-learn.adafruit.com/downloads/zip/3195805/Metro/Metro_RP2350_CircuitPython_Matrix.zip?timestamp={}",
"https://cdn-learn.adafruit.com/downloads/zip/3194658/Metro/Metro_RP2350_FlappyNyanCat.zip?timestamp={}",
"https://cdn-learn.adafruit.com/downloads/zip/3196927/Metro/Metro_RP2350_Match3/match3_game.zip?timestamp={}",
"https://cdn-learn.adafruit.com/downloads/zip/3194422/Metro/Metro_RP2350_Breakout.zip?timestamp={}",
# "",
]
def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir: Path, output_dir: Path):
# Get font name without extension
@ -53,6 +65,10 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
# Skip the lib directory as we'll handle it separately
if 'lib/' in path:
continue
if path.endswith("/"):
# skip directories, they will get created by
# mkdir(parents=True) below
continue
# Get the relative path from code_dir
rel_path = path[len(code_dir):]
@ -97,7 +113,22 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
# Clean up temporary directory
shutil.rmtree(temp_dir, ignore_errors=True)
def download_learn_projects():
for url in LEARN_PROJECT_URLS:
response = requests.get(url.format(int(time.time())), allow_redirects=True)
resp_url = response.url
#print(resp_url)
filename = resp_url.split("/")[-1].split("?")[0]
with open(f"learn-projects/{filename}", 'wb') as f:
f.write(response.content)
def main():
# download all learn project zips
download_learn_projects()
# Get the project root directory
root_dir = Path(__file__).parent

View file

@ -6,12 +6,15 @@ This example uses adafruit_display_text.label to display text using a custom fon
loaded by adafruit_bitmap_font
"""
import array
import atexit
import json
import displayio
import pathlib
import supervisor
import sys
import usb
import adafruit_pathlib as pathlib
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.text_box import TextBox
from adafruit_display_text.bitmap_label import Label
@ -22,9 +25,14 @@ import adafruit_usb_host_descriptors
from adafruit_anchored_group import AnchoredGroup
display = supervisor.runtime.display
scale = 1
if display.width > 360:
scale = 2
font_file = "/fonts/terminal.lvfontbin"
font = bitmap_font.load_font(font_file)
main_group = displayio.Group()
main_group = displayio.Group(scale=scale)
display.root_group = main_group
background_bmp = displayio.Bitmap(display.width, display.height, 1)
@ -43,8 +51,8 @@ mouse_bmp.pixel_shader.make_transparent(0)
mouse_tg = displayio.TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader)
# move it to the center of the display
mouse_tg.x = display.width // 2
mouse_tg.y = display.height // 2
mouse_tg.x = display.width // (2 * scale)
mouse_tg.y = display.height // (2 * scale)
# 046d:c52f
@ -98,17 +106,21 @@ for device in usb.core.find(find_all=True):
mouse = device
print(f"mouse interface: {mouse_interface_index} endpoint_address: {hex(mouse_endpoint_address)}")
mouse_was_attached = None
if mouse is not None:
# detach the kernel driver if needed
if mouse.is_kernel_driver_active(0):
mouse_was_attached = True
mouse.detach_kernel_driver(0)
else:
mouse_was_attached = False
# set configuration on the mouse so we can use it
mouse.set_configuration()
mouse_buf = array.array("b", [0] * 8)
WIDTH = 300
HEIGHT = 192
WIDTH = 280
HEIGHT = 182
config = {
"menu_title": "Launcher Menu",
@ -152,31 +164,56 @@ cell_width = WIDTH // config["width"]
default_icon_bmp, default_icon_palette = adafruit_imageload.load("launcher_assets/default_icon.bmp")
default_icon_palette.make_transparent(0)
menu_grid = GridLayout(x=10, y=26, width=WIDTH, height=HEIGHT, grid_size=(config["width"], config["height"]),
menu_grid = GridLayout(x=40, y=16, width=WIDTH, height=HEIGHT, grid_size=(config["width"], config["height"]),
divider_lines=False)
main_group.append(menu_grid)
menu_title_txt = Label(font, text=config["menu_title"])
menu_title_txt.anchor_point = (0.5, 0.5)
menu_title_txt.anchored_position = (display.width // 2, 2)
menu_title_txt.anchored_position = (display.width // (2 * scale), 2)
main_group.append(menu_title_txt)
app_titles = []
apps = []
app_path = pathlib.Path("/apps")
i = 0
pages = [{}]
cur_file_index = 0
cur_page = 0
for path in app_path.iterdir():
print(path)
cell_group = AnchoredGroup()
code_file = path / "code.py"
if not code_file.exists():
continue
cell_group = AnchoredGroup()
icon_file = path / "icon.bmp"
metadata_file = path / "metadata.json"
if not metadata_file.exists():
metadata_file = None
metadata = None
if metadata_file is not None:
with open(metadata_file.absolute(), "r") as f:
metadata = json.load(f)
if metadata is not None and "icon" in metadata:
icon_file = path / metadata["icon"]
else:
icon_file = path / "icon.bmp"
if not icon_file.exists():
icon_file = None
if metadata is not None and "title" in metadata:
title = metadata["title"]
else:
title = path.name
apps.append({
"title": path.name,
"icon": str(icon_file.absolute()),
"title": title,
"icon": str(icon_file.absolute()) if icon_file is not None else None,
"file": str(code_file.absolute())
})
if apps[-1]["icon"] is None:
@ -203,12 +240,12 @@ right_bmp, right_palette = adafruit_imageload.load("launcher_assets/arrow_right.
right_palette.make_transparent(0)
left_tg = AnchoredTileGrid(bitmap=left_bmp, pixel_shader=left_palette)
left_tg.anchor_point = (0, 1.0)
left_tg.anchored_position = (10, display.height - 2)
left_tg.anchor_point = (0, 0.5)
left_tg.anchored_position = (4, (display.height // 2 // scale) - 2)
right_tg = AnchoredTileGrid(bitmap=right_bmp, pixel_shader=right_palette)
right_tg.anchor_point = (1.0, 1.0)
right_tg.anchored_position = (display.width - 10, display.height - 2)
right_tg.anchor_point = (1.0, 0.5)
right_tg.anchored_position = ((display.width // scale) - 4, (display.height // 2 // scale) - 2)
main_group.append(left_tg)
main_group.append(right_tg)
@ -217,6 +254,20 @@ if mouse:
main_group.append(mouse_tg)
selected = 0
def atexit_callback():
"""
re-attach USB devices to kernel if needed.
:return:
"""
print("inside atexit callback")
if mouse_was_attached and not mouse.is_kernel_driver_active(0):
mouse.attach_kernel_driver(0)
atexit.register(atexit_callback)
# print(f"apps: {apps}")
while True:
index = None
@ -241,7 +292,7 @@ while True:
# attempt to read data from the mouse
# 10ms timeout, so we don't block long if there
# is no data
count = mouse.read(mouse_endpoint_address, mouse_buf, timeout=10)
count = mouse.read(mouse_endpoint_address, mouse_buf, timeout=20)
except usb.core.USBTimeoutError:
# skip the rest of the loop if there is no data
count = 0
@ -249,8 +300,8 @@ while True:
# update the mouse tilegrid x and y coordinates
# based on the delta values read from the mouse
if count > 0:
mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + mouse_buf[1]))
mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + mouse_buf[2]))
mouse_tg.x = max(0, min((display.width // scale) - 1, mouse_tg.x + mouse_buf[1]))
mouse_tg.y = max(0, min((display.height // scale) - 1, mouse_tg.y + mouse_buf[2]))
if mouse_buf[0] & (1 << 0) != 0:
clicked_cell = menu_grid.which_cell_contains((mouse_tg.x, mouse_tg.y))
@ -258,8 +309,11 @@ while True:
index = clicked_cell[1] * config["width"] + clicked_cell[0]
if index is not None:
supervisor.set_next_code_file(config["apps"][index]["file"], sticky_on_reload=True, reload_on_error=True,
working_directory="/apps/matrix")
# print("index", index)
# print(f"selected: {apps[index]}")
launch_file = apps[index]["file"]
supervisor.set_next_code_file(launch_file, sticky_on_reload=True, reload_on_error=True,
working_directory="/".join(launch_file.split("/")[:-1]))
if mouse and not mouse.is_kernel_driver_active(0):
mouse.attach_kernel_driver(0)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 918 B