diff --git a/src/patterns.py b/src/patterns.py index 7961391..f218593 100644 --- a/src/patterns.py +++ b/src/patterns.py @@ -295,48 +295,7 @@ class Patterns(PatternBase): # Inherit from PatternBase self.run = False self.running = False - def n_chase(self): - """Chase pattern - n1 LEDs on, n2 LEDs off, moving forward""" - self.run = True - - # n1 = on width, n2 = off width - on_width = max(1, int(self.n1)) - off_width = max(0, int(self.n2)) - segment_length = on_width + off_width - - if segment_length == 0: - segment_length = 1 - - # Calculate timing from delay - step_delay = max(10, int(self.delay)) # At least 10ms - - step = 0 - last_update = utime.ticks_ms() - color = self.apply_brightness(self.colors[0]) - - while self.run: - self.wdt.feed() - current_time = utime.ticks_ms() - - # Move forward every step_delay ms - if utime.ticks_diff(current_time, last_update) >= step_delay: - # Clear all LEDs - self.n.fill((0, 0, 0)) - - # Draw the chase pattern - repeating segments across all LEDs - for i in range(self.num_leds): - pos_in_segment = (i + step) % segment_length - if pos_in_segment < on_width: - self.n[i] = color - - self.n.write() - step = (step + 1) % segment_length - last_update = current_time - - utime.sleep_ms(1) - - self.run = False - self.running = False + # def flicker(self): # current_time = utime.ticks_ms() @@ -372,34 +331,74 @@ class Patterns(PatternBase): # Inherit from PatternBase # self.last_update = current_time # return self.delay -# def n_chase(self): -# """ -# A theater chase pattern using n1 for on-width and n2 for off-width. -# """ -# current_time = utime.ticks_ms() -# step_rate = max(1, int(self.n3)) -# segment_length = self.n1 + self.n2 -# if segment_length == 0: # Avoid division by zero -# self.fill((0,0,0)) -# self.n.write() -# self.last_update = current_time -# return self.delay + def n_chase(self): + """Chase pattern - n1 LEDs on, n2 LEDs off, bidirectional movement""" + self.run = True -# # Use controller's step for synchronization, but scale it for chasing -# chase_step = (self.step * step_rate) % self.num_leds + # n1 = on width, n2 = off width + on_width = max(1, int(self.n1)) + off_width = max(0, int(self.n2)) + segment_length = on_width + off_width + + if segment_length == 0: + segment_length = 1 + + # n3 = forward steps per move, n4 = backward steps per move + forward_steps = max(1, abs(int(self.n3))) + backward_steps = max(1, abs(int(self.n4))) + + # Calculate timing from delay + step_delay = max(10, int(self.delay)) # At least 10ms + + position = 0 # Current position of the chase head + phase = "forward" # "forward" or "backward" + steps_remaining = forward_steps + total_steps = 0 # Track total steps for wrapping + + last_update = utime.ticks_ms() + color = self.apply_brightness(self.colors[0]) + + while self.run: + self.wdt.feed() + current_time = utime.ticks_ms() -# for i in range(self.num_leds): -# # Calculate position relative to the chase head -# pos_from_head = (i - chase_step) % self.num_leds -# if pos_from_head < self.n1: -# self.n[i] = self.apply_brightness(self.colors[0]) -# else: -# self.n[i] = (0, 0, 0) -# self.n.write() + # Check if it's time to move + if utime.ticks_diff(current_time, last_update) >= step_delay: + # Move position based on current phase + if phase == "forward": + total_steps = (total_steps + 1) % (self.num_leds * segment_length) + position = total_steps % segment_length + steps_remaining -= 1 + if steps_remaining == 0: + phase = "backward" + steps_remaining = backward_steps + else: # backward + total_steps = (total_steps - 1) % (self.num_leds * segment_length) + position = total_steps % segment_length + steps_remaining -= 1 + if steps_remaining == 0: + phase = "forward" + steps_remaining = forward_steps + + # Clear all LEDs + self.n.fill((0, 0, 0)) + + # Draw the chase pattern - repeating segments across all LEDs + # Position determines where to start drawing on the strip + for i in range(self.num_leds): + # Create repeating pattern of on_width on, off_width off + pos_in_segment = ((i + position) % segment_length) + if pos_in_segment < on_width: + self.n[i] = color + + self.n.write() + last_update = current_time + + utime.sleep_ms(1) -# # Don't update internal step - use controller's step for sync -# self.last_update = current_time -# return self.delay + self.run = False + self.running = False + # def alternating(self): # # Use n1 as ON width and n2 as OFF width diff --git a/test/n_chase/9.py b/test/n_chase/9.py new file mode 100644 index 0000000..07826d5 --- /dev/null +++ b/test/n_chase/9.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +""" +N-chase test 9: Cyan, on=20, off=20, delay=200ms +Runs forever +Run with: mpremote run test/n_chase/9.py +""" + +import patterns +import utime +from settings import Settings +from machine import WDT + +print("Starting N-Chase Test 9: Cyan, on=20, off=20, delay=200ms") +print("Press Ctrl+C to stop") + +# Load settings +settings = Settings() + +# Initialize patterns using settings +p = patterns.Patterns( + pin=settings["led_pin"], + num_leds=settings["num_leds"], + brightness=255, + delay=200 +) + +# Configure test parameters +p.n1 = 20 # On width 20 +p.n2 = 20 # Off width 20 +p.n3 = 20 # Reserved for future use +p.n4 = -5 # Reserved for future use +p.colors = [(0, 255, 255)] # Cyan + +print(f"LED Pin: {settings['led_pin']}") +print(f"LEDs: {settings['num_leds']}") +print(f"Brightness: {p.brightness}") +print(f"Delay: {p.delay}ms") +print(f"On width: {p.n1}") +print(f"Off width: {p.n2}") +print(f"n3: {p.n3}") +print(f"n4: {p.n4}") +print(f"Color: {p.colors[0]}") + +# Initialize watchdog timer +wdt = WDT(timeout=10000) +wdt.feed() + +# Start pattern +p.select("nc") +print("Pattern started. Running forever...") + +# Run forever +try: + while True: + wdt.feed() + utime.sleep_ms(100) +except KeyboardInterrupt: + print("\nStopping...") + p.run = False + p.off() + print("LEDs turned off") +