125 lines
4.5 KiB
Python
125 lines
4.5 KiB
Python
import utime
|
|
|
|
|
|
class Chase:
|
|
def __init__(self, driver):
|
|
self.driver = driver
|
|
|
|
def run(self, preset):
|
|
"""Chase pattern: n1 LEDs of color0, n2 LEDs of color1, repeating.
|
|
Moves by n3 on even steps, n4 on odd steps (n3/n4 can be positive or negative)"""
|
|
colors = preset.c
|
|
if len(colors) < 1:
|
|
# Need at least 1 color
|
|
return
|
|
|
|
# Access colors, delay, and n values from preset
|
|
if not colors:
|
|
return
|
|
# If only one color provided, use it for both colors
|
|
if len(colors) < 2:
|
|
color0 = colors[0]
|
|
color1 = colors[0]
|
|
else:
|
|
color0 = colors[0]
|
|
color1 = colors[1]
|
|
|
|
color0 = self.driver.apply_brightness(color0, preset.b)
|
|
color1 = self.driver.apply_brightness(color1, preset.b)
|
|
|
|
n1 = max(1, int(preset.n1)) # LEDs of color 0
|
|
n2 = max(1, int(preset.n2)) # LEDs of color 1
|
|
n3 = int(preset.n3) # Step movement on even steps (can be negative)
|
|
n4 = int(preset.n4) # Step movement on odd steps (can be negative)
|
|
|
|
segment_length = n1 + n2
|
|
|
|
# Calculate position from step_count
|
|
step_count = self.driver.step
|
|
# Position alternates: step 0 adds n3, step 1 adds n4, step 2 adds n3, etc.
|
|
if step_count % 2 == 0:
|
|
# Even steps: (step_count//2) pairs of (n3+n4) plus one extra n3
|
|
position = (step_count // 2) * (n3 + n4) + n3
|
|
else:
|
|
# Odd steps: ((step_count+1)//2) pairs of (n3+n4)
|
|
position = ((step_count + 1) // 2) * (n3 + n4)
|
|
|
|
# Wrap position to keep it reasonable
|
|
max_pos = self.driver.num_leds + segment_length
|
|
position = position % max_pos
|
|
if position < 0:
|
|
position += max_pos
|
|
|
|
# If auto is False, run a single step and then stop
|
|
if not preset.a:
|
|
# Clear all LEDs
|
|
self.driver.n.fill((0, 0, 0))
|
|
|
|
# Draw repeating pattern starting at position
|
|
for i in range(self.driver.num_leds):
|
|
# Calculate position in the repeating segment
|
|
relative_pos = (i - position) % segment_length
|
|
if relative_pos < 0:
|
|
relative_pos = (relative_pos + segment_length) % segment_length
|
|
|
|
# Determine which color based on position in segment
|
|
if relative_pos < n1:
|
|
self.driver.n[i] = color0
|
|
else:
|
|
self.driver.n[i] = color1
|
|
|
|
self.driver.n.write()
|
|
|
|
# Increment step for next beat
|
|
self.driver.step = step_count + 1
|
|
|
|
# Allow tick() to advance the generator once
|
|
yield
|
|
return
|
|
|
|
# Auto mode: continuous loop
|
|
# Use transition_duration for timing and force the first update to happen immediately
|
|
transition_duration = max(10, int(preset.d))
|
|
last_update = utime.ticks_ms() - transition_duration
|
|
|
|
while True:
|
|
current_time = utime.ticks_ms()
|
|
if utime.ticks_diff(current_time, last_update) >= transition_duration:
|
|
# Calculate current position from step_count
|
|
if step_count % 2 == 0:
|
|
position = (step_count // 2) * (n3 + n4) + n3
|
|
else:
|
|
position = ((step_count + 1) // 2) * (n3 + n4)
|
|
|
|
# Wrap position
|
|
max_pos = self.driver.num_leds + segment_length
|
|
position = position % max_pos
|
|
if position < 0:
|
|
position += max_pos
|
|
|
|
# Clear all LEDs
|
|
self.driver.n.fill((0, 0, 0))
|
|
|
|
# Draw repeating pattern starting at position
|
|
for i in range(self.driver.num_leds):
|
|
# Calculate position in the repeating segment
|
|
relative_pos = (i - position) % segment_length
|
|
if relative_pos < 0:
|
|
relative_pos = (relative_pos + segment_length) % segment_length
|
|
|
|
# Determine which color based on position in segment
|
|
if relative_pos < n1:
|
|
self.driver.n[i] = color0
|
|
else:
|
|
self.driver.n[i] = color1
|
|
|
|
self.driver.n.write()
|
|
|
|
# Increment step
|
|
step_count += 1
|
|
self.driver.step = step_count
|
|
last_update = current_time
|
|
|
|
# Yield once per tick so other logic can run
|
|
yield
|