diff --git a/src/patterns.py b/src/patterns.py index 4f5a370..2e1a589 100644 --- a/src/patterns.py +++ b/src/patterns.py @@ -23,6 +23,7 @@ class Patterns(PatternBase): # Inherit from PatternBase "o": self.off, "on": self.on, "bl": self.blink, + "cl": self.circle_loading, } self.step = 0 self.run = True @@ -64,6 +65,79 @@ class Patterns(PatternBase): # Inherit from PatternBase self.run = False self.running = False + def circle_loading(self): + """Circle loading pattern - grows to n2, then tail moves forward at n3 until min length n4""" + self.run = True + head = 0 + tail = 0 + + # Calculate timing + head_rate = max(1, int(self.n1)) # n1 = head moves per second + tail_rate = max(1, int(self.n3)) # n3 = tail moves per second + max_length = max(1, int(self.n2)) # n2 = max length + min_length = max(0, int(self.n4)) # n4 = min length + + head_delay = 1000 // head_rate # ms between head movements + tail_delay = 1000 // tail_rate # ms between tail movements + + last_head_move = utime.ticks_ms() + last_tail_move = utime.ticks_ms() + + phase = "growing" # "growing", "shrinking", or "off" + + while self.run: + self.wdt.feed() + current_time = utime.ticks_ms() + + # Clear all LEDs + self.n.fill((0, 0, 0)) + + # Calculate segment length + segment_length = (head - tail) % self.num_leds + if segment_length == 0 and head != tail: + segment_length = self.num_leds + + # Draw segment from tail to head + color = self.apply_brightness(self.colors[0]) + for i in range(segment_length + 1): + led_pos = (tail + i) % self.num_leds + self.n[led_pos] = color + + # Move head continuously at n1 LEDs per second + if utime.ticks_diff(current_time, last_head_move) >= head_delay: + head = (head + 1) % self.num_leds + last_head_move = current_time + + # Tail behavior based on phase + if phase == "growing": + # Growing phase: tail stays at 0 until max length reached + if segment_length >= max_length: + phase = "shrinking" + elif phase == "shrinking": + # Shrinking phase: move tail forward at n3 LEDs per second + if utime.ticks_diff(current_time, last_tail_move) >= tail_delay: + tail = (tail + 1) % self.num_leds + last_tail_move = current_time + + # Check if we've reached min length + current_length = (head - tail) % self.num_leds + if current_length == 0 and head != tail: + current_length = self.num_leds + + # For min_length = 0, we need at least 1 LED (the head) + if min_length == 0 and current_length <= 1: + phase = "off" # All LEDs off for 1 step + elif min_length > 0 and current_length <= min_length: + phase = "growing" # Cycle repeats + else: # phase == "off" + # Off phase: all LEDs off for 1 step, then restart + phase = "growing" + + self.n.write() + + self.run = False + self.running = False + # def flicker(self): # current_time = utime.ticks_ms() # base_color = self.colors[0] diff --git a/test/circle_loading.py b/test/circle_loading.py new file mode 100644 index 0000000..f271cb5 --- /dev/null +++ b/test/circle_loading.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +""" +Test script for circle loading pattern with multiple test cases +Run with: mpremote run test/circle_loading.py +""" + +import patterns +import utime +from settings import Settings +from machine import WDT + +def run_test_case(p, test_name, duration_ms=5000): + """Run a test case for specified duration""" + print(f"\n--- {test_name} ---") + print(f"Parameters: n1={p.n1} head/sec, n2={p.n2} max length, n3={p.n3} tail/sec, n4={p.n4} min length") + print(f"Color: {p.colors[0]}") + print(f"Running for {duration_ms//1000} seconds...") + + # Initialize watchdog timer + wdt = WDT(timeout=10000) + wdt.feed() + + # Start pattern + p.select("cl") + + # Run for specified duration + start_time = utime.ticks_ms() + while utime.ticks_diff(utime.ticks_ms(), start_time) < duration_ms: + wdt.feed() + utime.sleep_ms(100) + + # Stop pattern + p.run = False + print(f"{test_name} completed") + + # Brief pause between tests + utime.sleep_ms(500) + +def test_circle_loading(): + print("Testing circle loading pattern with multiple configurations...") + + # Load settings + settings = Settings() + + # Initialize patterns using settings + p = patterns.Patterns( + pin=settings["led_pin"], + num_leds=settings["num_leds"], + brightness=100, + delay=2000 # Base cycle time + ) + + print(f"LED Pin: {settings['led_pin']}") + print(f"LEDs: {settings['num_leds']}") + print(f"Brightness: {p.brightness}") + + # Test Case 1: Your specified parameters + p.n1 = 50 + p.n2 = 100 + p.n3 = 200 + p.n4 = 0 + p.colors = [(255, 0, 0)] # Red + run_test_case(p, "Test 1: n1=50, n2=100, n3=200, n4=0", 15000) + + # Test Case 2: Slow head, fast tail + p.n1 = 10 # Head moves 10 LEDs/second + p.n2 = 30 # Max length 30 LEDs + p.n3 = 20 # Tail moves 20 LEDs/second + p.n4 = 5 # Min length 5 LEDs + p.colors = [(0, 255, 0)] # Green + run_test_case(p, "Test 2: n1=10, n2=30, n3=20, n4=5", 10000) + + # Test Case 3: Equal head and tail speed + p.n1 = 15 # Head moves 15 LEDs/second + p.n2 = 25 # Max length 25 LEDs + p.n3 = 15 # Tail moves 15 LEDs/second + p.n4 = 3 # Min length 3 LEDs + p.colors = [(0, 0, 255)] # Blue + run_test_case(p, "Test 3: n1=15, n2=25, n3=15, n4=3", 8000) + + # Test Case 4: Very fast head, slow tail + p.n1 = 30 # Head moves 30 LEDs/second + p.n2 = 40 # Max length 40 LEDs + p.n3 = 5 # Tail moves 5 LEDs/second + p.n4 = 8 # Min length 8 LEDs + p.colors = [(255, 255, 0)] # Yellow + run_test_case(p, "Test 4: n1=30, n2=40, n3=5, n4=8", 12000) + + # Test Case 5: Long segment, fast cycle + p.n1 = 25 # Head moves 25 LEDs/second + p.n2 = 60 # Max length 60 LEDs + p.n3 = 30 # Tail moves 30 LEDs/second + p.n4 = 2 # Min length 2 LEDs + p.colors = [(255, 0, 255)] # Magenta + run_test_case(p, "Test 5: n1=25, n2=60, n3=30, n4=2", 10000) + + # Test Case 6: Very slow head, very fast tail + p.n1 = 5 # Head moves 5 LEDs/second + p.n2 = 20 # Max length 20 LEDs + p.n3 = 40 # Tail moves 40 LEDs/second + p.n4 = 1 # Min length 1 LED + p.colors = [(0, 255, 255)] # Cyan + run_test_case(p, "Test 6: n1=5, n2=20, n3=40, n4=1", 8000) + + # Test Case 7: Medium speeds, short segment + p.n1 = 12 # Head moves 12 LEDs/second + p.n2 = 15 # Max length 15 LEDs + p.n3 = 18 # Tail moves 18 LEDs/second + p.n4 = 4 # Min length 4 LEDs + p.colors = [(255, 128, 0)] # Orange + run_test_case(p, "Test 7: n1=12, n2=15, n3=18, n4=4", 6000) + + # Test Case 8: Ultra fast everything + p.n1 = 100 # Head moves 100 LEDs/second + p.n2 = 50 # Max length 50 LEDs + p.n3 = 150 # Tail moves 150 LEDs/second + p.n4 = 10 # Min length 10 LEDs + p.colors = [(128, 0, 255)] # Purple + run_test_case(p, "Test 8: n1=100, n2=50, n3=150, n4=10", 5000) + + print("\n=== All tests completed ===") + + # Turn off LEDs + p.off() + print("LEDs turned off") + +if __name__ == "__main__": + test_circle_loading()