Add mpremote tests for scaling, roll, and point
Made-with: Cursor
This commit is contained in:
52
pico/test/test_fill_n.py
Normal file
52
pico/test/test_fill_n.py
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
"""
|
||||||
|
On-device test for Presets.fill_n() using mpremote.
|
||||||
|
|
||||||
|
Usage (from pico/ dir or project root with adjusted paths):
|
||||||
|
|
||||||
|
mpremote connect <device> cp src/*.py :
|
||||||
|
mpremote connect <device> cp src/patterns/*.py :patterns
|
||||||
|
mpremote connect <device> cp lib/*.py :
|
||||||
|
mpremote connect <device> cp test/test_fill_n.py :
|
||||||
|
mpremote connect <device> run test_fill_n.py
|
||||||
|
|
||||||
|
This script:
|
||||||
|
- Instantiates Presets
|
||||||
|
- Calls fill_n() with a simple range
|
||||||
|
- Lets you visually confirm that all strips show the same proportional segment
|
||||||
|
and that equal-length strip pairs have identical lit indices.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from presets import Presets
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
presets = Presets()
|
||||||
|
presets.load()
|
||||||
|
|
||||||
|
# Choose a simple test range on the reference strip (strip 0).
|
||||||
|
ref_len = presets.strip_length(0)
|
||||||
|
if ref_len <= 0:
|
||||||
|
print("No strips or invalid length; aborting fill_n test.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Use a central segment so it's easy to see.
|
||||||
|
start = ref_len // 4
|
||||||
|
end = 3 * ref_len // 4
|
||||||
|
print("Running fill_n test from", start, "to", end, "on reference strip 0.")
|
||||||
|
|
||||||
|
color = (0, 50, 0) # dim green
|
||||||
|
|
||||||
|
# First, clear everything
|
||||||
|
for strip in presets.strips:
|
||||||
|
strip.fill((0, 0, 0))
|
||||||
|
strip.show()
|
||||||
|
|
||||||
|
# Apply fill_n, which will use scale() internally.
|
||||||
|
presets.fill_n(color, start, end)
|
||||||
|
|
||||||
|
print("fill_n test applied; visually inspect strips.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
130
pico/test/test_point.py
Normal file
130
pico/test/test_point.py
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
"""
|
||||||
|
On-device test for the Point pattern using mpremote.
|
||||||
|
|
||||||
|
Usage (from pico/ dir or project root with adjusted paths):
|
||||||
|
|
||||||
|
mpremote connect <device> cp src/*.py :
|
||||||
|
mpremote connect <device> cp src/patterns/*.py :patterns
|
||||||
|
mpremote connect <device> cp lib/*.py :
|
||||||
|
mpremote connect <device> cp test/test_point.py :
|
||||||
|
mpremote connect <device> run test_point.py
|
||||||
|
|
||||||
|
This script:
|
||||||
|
- Instantiates Presets
|
||||||
|
- Creates a few in-memory 'point' presets with different ranges/colors
|
||||||
|
- Selects each one so you can visually confirm the segments
|
||||||
|
"""
|
||||||
|
|
||||||
|
from presets import Presets, Preset
|
||||||
|
|
||||||
|
|
||||||
|
def make_point_preset(name, colors, n_values, brightness=255):
|
||||||
|
"""
|
||||||
|
Helper to build a Preset for the 'point' pattern.
|
||||||
|
|
||||||
|
colors: list of up to 4 (r,g,b) tuples
|
||||||
|
n_values: list/tuple of 8 ints [n1..n8]
|
||||||
|
"""
|
||||||
|
# Pad or trim colors to 4 entries
|
||||||
|
cs = list(colors)[:4]
|
||||||
|
while len(cs) < 4:
|
||||||
|
cs.append((0, 0, 0))
|
||||||
|
|
||||||
|
n1, n2, n3, n4, n5, n6, n7, n8 = n_values
|
||||||
|
data = {
|
||||||
|
"p": "point",
|
||||||
|
"c": cs,
|
||||||
|
"b": brightness,
|
||||||
|
"n1": n1,
|
||||||
|
"n2": n2,
|
||||||
|
"n3": n3,
|
||||||
|
"n4": n4,
|
||||||
|
"n5": n5,
|
||||||
|
"n6": n6,
|
||||||
|
"n7": n7,
|
||||||
|
"n8": n8,
|
||||||
|
# 'a' is not used by point; it's static
|
||||||
|
}
|
||||||
|
return name, Preset(data)
|
||||||
|
|
||||||
|
|
||||||
|
def show_and_wait(presets, name, preset_obj, wait_ms):
|
||||||
|
"""Select a static 'point' preset and hold it for wait_ms."""
|
||||||
|
presets.presets[name] = preset_obj
|
||||||
|
presets.select(name)
|
||||||
|
# Point draws immediately in run(), then just yields; one tick is enough.
|
||||||
|
presets.tick()
|
||||||
|
|
||||||
|
import utime
|
||||||
|
|
||||||
|
start = utime.ticks_ms()
|
||||||
|
while utime.ticks_diff(utime.ticks_ms(), start) < wait_ms:
|
||||||
|
# Keep ticking in case other logic ever depends on it
|
||||||
|
presets.tick()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
presets = Presets()
|
||||||
|
presets.load()
|
||||||
|
|
||||||
|
num_leds = presets.strip_length(0)
|
||||||
|
if num_leds <= 0:
|
||||||
|
print("No strips; aborting point test.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("Starting point pattern test...")
|
||||||
|
|
||||||
|
quarter = num_leds // 4
|
||||||
|
half = num_leds // 2
|
||||||
|
|
||||||
|
point_presets = []
|
||||||
|
|
||||||
|
# 1. Single band: first quarter, red
|
||||||
|
point_presets.append(
|
||||||
|
make_point_preset(
|
||||||
|
"point_red_q1",
|
||||||
|
colors=[(255, 0, 0)],
|
||||||
|
n_values=[0, quarter - 1, 0, -1, 0, -1, 0, -1],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2. Two bands: red first half, green second half
|
||||||
|
point_presets.append(
|
||||||
|
make_point_preset(
|
||||||
|
"point_red_green_halves",
|
||||||
|
colors=[(255, 0, 0), (0, 255, 0)],
|
||||||
|
n_values=[0, half - 1, half, num_leds - 1, 0, -1, 0, -1],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. Three bands: R, G, B quarters
|
||||||
|
point_presets.append(
|
||||||
|
make_point_preset(
|
||||||
|
"point_rgb_quarters",
|
||||||
|
colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)],
|
||||||
|
n_values=[
|
||||||
|
0,
|
||||||
|
quarter - 1, # red
|
||||||
|
quarter,
|
||||||
|
2 * quarter - 1, # green
|
||||||
|
2 * quarter,
|
||||||
|
3 * quarter - 1, # blue
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show each for ~4 seconds
|
||||||
|
for name, preset_obj in point_presets:
|
||||||
|
print("Showing point preset:", name)
|
||||||
|
show_and_wait(presets, name, preset_obj, wait_ms=4000)
|
||||||
|
|
||||||
|
print("Point pattern test finished. Turning off LEDs.")
|
||||||
|
presets.select("off")
|
||||||
|
presets.tick()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
118
pico/test/test_roll.py
Normal file
118
pico/test/test_roll.py
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
"""
|
||||||
|
On-device test for the Roll pattern using mpremote.
|
||||||
|
|
||||||
|
Usage (from pico/ dir or project root with adjusted paths):
|
||||||
|
|
||||||
|
mpremote connect <device> cp src/*.py :
|
||||||
|
mpremote connect <device> cp src/patterns/*.py :patterns
|
||||||
|
mpremote connect <device> cp lib/*.py :
|
||||||
|
mpremote connect <device> cp test/test_roll.py :
|
||||||
|
mpremote connect <device> run test_roll.py
|
||||||
|
|
||||||
|
This script:
|
||||||
|
- Instantiates Presets
|
||||||
|
- Creates a few in-memory roll presets with different parameters
|
||||||
|
- Runs each one for a short time so you can visually compare behaviour
|
||||||
|
"""
|
||||||
|
|
||||||
|
import utime
|
||||||
|
from presets import Presets, Preset
|
||||||
|
|
||||||
|
|
||||||
|
def make_roll_preset(name, color1, color2, n1=0, n2=0, n3=0, n4=0, delay_ms=50, brightness=255):
|
||||||
|
"""Helper to build a Preset dict for the roll pattern."""
|
||||||
|
data = {
|
||||||
|
"p": "roll",
|
||||||
|
"c": [color1, color2],
|
||||||
|
"b": brightness,
|
||||||
|
"d": delay_ms,
|
||||||
|
"n1": n1,
|
||||||
|
"n2": n2,
|
||||||
|
"n3": n3,
|
||||||
|
"n4": n4,
|
||||||
|
"a": True, # animated
|
||||||
|
}
|
||||||
|
return name, Preset(data)
|
||||||
|
|
||||||
|
|
||||||
|
def run_preset(presets, name, preset_obj, duration_ms):
|
||||||
|
"""Run a given roll preset for duration_ms using the existing tick loop."""
|
||||||
|
presets.presets[name] = preset_obj
|
||||||
|
presets.select(name)
|
||||||
|
|
||||||
|
start = utime.ticks_ms()
|
||||||
|
while utime.ticks_diff(utime.ticks_ms(), start) < duration_ms:
|
||||||
|
presets.tick()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
presets = Presets()
|
||||||
|
presets.load()
|
||||||
|
|
||||||
|
print("Starting roll pattern test...")
|
||||||
|
|
||||||
|
ref_len = presets.strip_length(0)
|
||||||
|
# Use some margins based on strip length to show different bands.
|
||||||
|
quarter = ref_len // 4
|
||||||
|
|
||||||
|
# Define a few different roll presets:
|
||||||
|
roll_presets = []
|
||||||
|
|
||||||
|
# 1. Full-strip, white -> off, clockwise, medium speed
|
||||||
|
roll_presets.append(
|
||||||
|
make_roll_preset(
|
||||||
|
"roll_full_cw",
|
||||||
|
color1=(255, 255, 255),
|
||||||
|
color2=(0, 0, 0),
|
||||||
|
n1=0,
|
||||||
|
n2=0,
|
||||||
|
n3=2, # 2 rotations then stop
|
||||||
|
n4=0, # clockwise
|
||||||
|
delay_ms=40,
|
||||||
|
brightness=255,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2. Inner band only, red -> blue, clockwise, slower
|
||||||
|
roll_presets.append(
|
||||||
|
make_roll_preset(
|
||||||
|
"roll_inner_band",
|
||||||
|
color1=(255, 0, 0),
|
||||||
|
color2=(0, 0, 255),
|
||||||
|
n1=quarter, # start margin
|
||||||
|
n2=quarter, # end margin
|
||||||
|
n3=2,
|
||||||
|
n4=0,
|
||||||
|
delay_ms=60,
|
||||||
|
brightness=255,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. Full-strip, green -> off, counter-clockwise, faster
|
||||||
|
roll_presets.append(
|
||||||
|
make_roll_preset(
|
||||||
|
"roll_full_ccw",
|
||||||
|
color1=(0, 255, 0),
|
||||||
|
color2=(0, 0, 0),
|
||||||
|
n1=0,
|
||||||
|
n2=0,
|
||||||
|
n3=2,
|
||||||
|
n4=1, # counter-clockwise
|
||||||
|
delay_ms=30,
|
||||||
|
brightness=255,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run each roll preset for about 5 seconds
|
||||||
|
for name, preset_obj in roll_presets:
|
||||||
|
print("Running roll preset:", name)
|
||||||
|
run_preset(presets, name, preset_obj, duration_ms=5000)
|
||||||
|
|
||||||
|
print("Roll pattern test finished. Turning off LEDs.")
|
||||||
|
presets.select("off")
|
||||||
|
presets.tick()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
100
pico/test/test_scale.py
Normal file
100
pico/test/test_scale.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
"""
|
||||||
|
Test the Presets.scale() helper on-device with mpremote.
|
||||||
|
|
||||||
|
Usage (from project root):
|
||||||
|
|
||||||
|
mpremote connect <device> cp pico/src/*.py : &&
|
||||||
|
mpremote connect <device> cp pico/src/patterns/*.py :patterns &&
|
||||||
|
mpremote connect <device> cp pico/lib/*.py : &&
|
||||||
|
mpremote connect <device> cp tests/test_scale.py : &&
|
||||||
|
mpremote connect <device> run test_scale.py
|
||||||
|
|
||||||
|
This script:
|
||||||
|
- Creates a minimal Presets instance
|
||||||
|
- Runs a few numeric test cases for scale()
|
||||||
|
- Optionally displays a short visual check on the LEDs
|
||||||
|
"""
|
||||||
|
|
||||||
|
from presets import Presets
|
||||||
|
|
||||||
|
|
||||||
|
def numeric_tests(presets):
|
||||||
|
"""
|
||||||
|
Numeric sanity checks for scale() using the actual strip config.
|
||||||
|
|
||||||
|
We treat strip 0 as the reference and print the mapped indices for
|
||||||
|
a few positions on each other strip.
|
||||||
|
"""
|
||||||
|
print("Numeric scale() tests (from strip 0):")
|
||||||
|
ref_len = presets.strip_length(0)
|
||||||
|
if ref_len <= 0:
|
||||||
|
print(" strip 0 length <= 0; skipping numeric tests.")
|
||||||
|
return
|
||||||
|
|
||||||
|
test_positions = [0, ref_len // 2, ref_len - 1]
|
||||||
|
for pos in test_positions:
|
||||||
|
print(" pos on strip 0:", pos)
|
||||||
|
for dst_idx in range(len(presets.strips)):
|
||||||
|
dst_len = presets.strip_length(dst_idx)
|
||||||
|
if dst_len <= 0:
|
||||||
|
continue
|
||||||
|
n2 = presets.scale(dst_idx, pos)
|
||||||
|
print(" -> strip", dst_idx, "len", dst_len, "pos", n2)
|
||||||
|
|
||||||
|
|
||||||
|
def visual_test(presets):
|
||||||
|
"""
|
||||||
|
Simple visual test:
|
||||||
|
- Use strip 0 as reference
|
||||||
|
- Move a pixel along strip 0
|
||||||
|
- Map position to all other strips with scale()
|
||||||
|
"""
|
||||||
|
import utime
|
||||||
|
|
||||||
|
strips = presets.strips
|
||||||
|
if not strips:
|
||||||
|
print("No strips available for visual test.")
|
||||||
|
return
|
||||||
|
|
||||||
|
src_strip_idx = 0
|
||||||
|
l1 = presets.strip_length(src_strip_idx)
|
||||||
|
if l1 <= 0:
|
||||||
|
print("strip_length(0) <= 0; aborting visual test.")
|
||||||
|
return
|
||||||
|
|
||||||
|
color = (50, 0, 0) # dim red so it doesn't blind you
|
||||||
|
|
||||||
|
# Run once across the full length of the reference strip,
|
||||||
|
# jumping 10 LEDs at a time.
|
||||||
|
step_size = 10
|
||||||
|
steps = (l1 + step_size - 1) // step_size
|
||||||
|
print("Starting visual scale() test with 10-LED jumps:", steps, "steps...")
|
||||||
|
for step in range(steps):
|
||||||
|
n1 = (step * step_size) % l1
|
||||||
|
|
||||||
|
# Clear all strips
|
||||||
|
for strip in strips:
|
||||||
|
strip.fill((0, 0, 0))
|
||||||
|
|
||||||
|
# Light mapped position on each strip using Presets.set/show
|
||||||
|
for dst_strip_idx, _ in enumerate(strips):
|
||||||
|
presets.set(dst_strip_idx, n1, color)
|
||||||
|
presets.show(dst_strip_idx)
|
||||||
|
|
||||||
|
print("Visual test finished.")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
presets = Presets()
|
||||||
|
presets.load()
|
||||||
|
numeric_tests(presets)
|
||||||
|
# Comment this in/out depending on whether you want the LEDs to run:
|
||||||
|
try:
|
||||||
|
visual_test(presets)
|
||||||
|
except Exception as e:
|
||||||
|
print("Visual test error:", e)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
Reference in New Issue
Block a user