Add Pico presets engine, patterns, and tests.

Wire the Pico to UART-driven preset selection, add pattern modules and presets data, remove old p2p/settings code, and update tests and LED driver.

Made-with: Cursor
This commit is contained in:
2026-03-03 19:28:11 +13:00
parent 646b988cdd
commit 52a5f0f8c4
44 changed files with 2175 additions and 373 deletions

75
pico/src/patterns/pose.py Normal file
View File

@@ -0,0 +1,75 @@
class Pose:
def __init__(self, driver):
self.driver = driver
def run(self, preset):
"""
Pose pattern: simple static bands that turn the hoop on
within the specified n ranges, across ALL strips.
Uses the preset's n values as inclusive ranges over the
logical ring (driver.n):
- n1n2: color c[0]
- n3n4: color c[1]
- n5n6: color c[2]
- n7n8: color c[3]
"""
# Base colors (up to 4), missing ones default to black
colors = list(preset.c) if getattr(preset, "c", None) else []
while len(colors) < 4:
colors.append((0, 0, 0))
# Apply preset/global brightness once per color
c1 = self.driver.apply_brightness(colors[0], preset.b)
c2 = self.driver.apply_brightness(colors[1], preset.b)
c3 = self.driver.apply_brightness(colors[2], preset.b)
c4 = self.driver.apply_brightness(colors[3], preset.b)
# Helper to normalize and clamp a range
def norm_range(a, b, max_len):
a = int(a)
b = int(b)
if a > b:
a, b = b, a
if b < 0 or a >= max_len:
return None
a = max(0, a)
b = min(max_len - 1, b)
if a > b:
return None
return a, b
# For Pose, apply the same ranges on EVERY strip:
# each color band is repeated across all strips.
for strip in self.driver.strips:
strip_len = strip.num_leds
ranges = []
r1 = norm_range(getattr(preset, "n1", 0), getattr(preset, "n2", -1), strip_len)
if r1:
ranges.append((r1[0], r1[1], c1))
r2 = norm_range(getattr(preset, "n3", 0), getattr(preset, "n4", -1), strip_len)
if r2:
ranges.append((r2[0], r2[1], c2))
r3 = norm_range(getattr(preset, "n5", 0), getattr(preset, "n6", -1), strip_len)
if r3:
ranges.append((r3[0], r3[1], c3))
r4 = norm_range(getattr(preset, "n7", 0), getattr(preset, "n8", -1), strip_len)
if r4:
ranges.append((r4[0], r4[1], c4))
# Static draw on this strip: last range wins on overlaps
for i in range(strip_len):
color = (0, 0, 0)
for start, end, c in ranges:
if start <= i <= end:
color = c
strip.set(i, color)
# Flush all strips
for strip in self.driver.strips:
strip.show()
while True:
yield