From b45823c479122c9ef996a9e812e8320405e031e4 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 28 Feb 2026 08:58:55 +1300 Subject: [PATCH] Update STRIP_CONFIG --- pico/src/main.py | 195 +++++++++++++++++++++++------------------------ 1 file changed, 94 insertions(+), 101 deletions(-) diff --git a/pico/src/main.py b/pico/src/main.py index 7fddb6f..2d8ed6c 100644 --- a/pico/src/main.py +++ b/pico/src/main.py @@ -1,106 +1,99 @@ -# """ -# Pico: receive led-driver JSON from UART (one message per line). Runs Presets + patterns. -# UART RX on D7 (GPIO1). Non-blocking so presets.tick() runs every loop. -# """ -# from settings import Settings -# from machine import UART, Pin -# import utime -# from presets import Presets -# from utils import convert_and_reorder_colors -# import json - -# # UART (Pico XIAO: D7 = GPIO1) -# UART_RX_PIN = 1 -# UART_BAUD = 115200 -# UART_ID = 0 - -# settings = Settings() -# print(settings) - -# presets = Presets(settings["led_pin"], settings["num_leds"]) -# presets.load() -# presets.b = settings.get("brightness", 255) -# startup_preset = settings.get("startup_preset") -# if startup_preset: -# presets.select(startup_preset) -# print("Selected startup preset:", startup_preset) - -# last_brightness_save = 0 - -# # Non-blocking UART -# uart = UART(UART_ID, baudrate=UART_BAUD, rx=Pin(UART_RX_PIN), rxbuf=512, timeout=0) -# uart_buf = bytearray() - -# print("UART RX on pin %s, %s baud (one JSON object per line)" % (UART_RX_PIN, UART_BAUD)) - - -# def process_message(data): -# """Handle one JSON message (led-driver protocol: v, b, presets, select, default, save).""" -# if data.get("v") != "1": -# return -# global last_brightness_save -# if "b" in data: -# try: -# presets.b = max(0, min(255, int(data["b"]))) -# settings["brightness"] = presets.b -# now = utime.ticks_ms() -# if utime.ticks_diff(now, last_brightness_save) >= 500: -# settings.save() -# last_brightness_save = now -# except (TypeError, ValueError): -# pass -# if "presets" in data: -# for id, preset_data in data["presets"].items(): -# if "c" in preset_data: -# preset_data["c"] = convert_and_reorder_colors(preset_data["c"], settings) -# presets.edit(id, preset_data) -# print("Edited preset", id, preset_data.get("name", "")) -# if settings.get("name") in data.get("select", {}): -# select_list = data["select"][settings.get("name")] -# if select_list: -# preset_name = select_list[0] -# step = select_list[1] if len(select_list) > 1 else None -# presets.select(preset_name, step=step) -# if "default" in data: -# settings["startup_preset"] = data["default"] -# print("Set startup preset to", data["default"]) -# settings.save() -# if "save" in data: -# presets.save() - - -# while True: -# presets.tick() -# n = uart.any() -# if n: -# data_in = uart.read(n) -# if data_in: -# for b in data_in: -# if b in (0x0A, 0x0D): # LF or CR -# if uart_buf: -# try: -# msg = uart_buf.decode("utf-8").strip() -# if msg: -# data = json.loads(msg) -# process_message(data) -# except (ValueError, UnicodeError): -# pass -# uart_buf = bytearray() -# else: -# if len(uart_buf) < 1024: -# uart_buf.append(b) -# utime.sleep_ms(1) - -from neopixel import NeoPixel -from machine import Pin - +import sys +# So "from ws2812 import WS2812B" finds pico/lib when run from device / or test/ +if "lib" not in sys.path: + sys.path.insert(0, "lib") +if "../lib" not in sys.path: + sys.path.insert(0, "../lib") from ws2812 import WS2812B +import time +# --- Rainbow pattern (outside ws2812): pregen double buffer, show via head offset --- + +def hue_to_rgb(hue): + """Hue 0..360 -> (r, g, b). Simple HSV with S=V=1.""" + h = hue % 360 + x = 1 - abs((h / 60) % 2 - 1) + if h < 60: + r, g, b = 1, x, 0 + elif h < 120: + r, g, b = x, 1, 0 + elif h < 180: + r, g, b = 0, 1, x + elif h < 240: + r, g, b = 0, x, 1 + elif h < 300: + r, g, b = x, 0, 1 + else: + r, g, b = 1, 0, x + return (int(r * 255), int(g * 255), int(b * 255)) + + +def make_rainbow_double(num_leds, brightness=1.0): + """Build 2 full rainbow cycles (2*num_leds pixels, GRB). Returns (double_buf, strip_len). + head must be in 0..strip_len-1 so DMA reads double_buf[head:head+strip_len] with no copy.""" + n = 2 * num_leds + double_buf = bytearray(n * 3) + for i in range(n): + hue = (i / n) * 360 * 2 + r, g, b = hue_to_rgb(hue) + g = int(g * brightness) & 0xFF + r = int(r * brightness) & 0xFF + b = int(b * brightness) & 0xFF + o = i * 3 + double_buf[o] = g + double_buf[o + 1] = r + double_buf[o + 2] = b + strip_len = num_leds * 3 + return (double_buf, strip_len) + + +def show_rainbow(strip, double_buf, strip_len, head): + """DMA reads directly from double_buf at head; no copy. head in 0..strip_len-1.""" + strip.show(double_buf, head) + + +# --- Strips + rainbow buffers per strip --- +# Each strip can have a different length; buffers and phase are per-strip. +# Strip config must match pico/src/main.py pins. +STRIP_CONFIG = ( + (7, 291), + (3, 290), + (6, 283), + (28, 278), + (29, 275), + (4, 270), + (0, 283), + (2, 290), +) + +strips = [] sm = 0 -pins = ((2,270), (3,271), (4,272), (0,273), (7,274), (6,275), (29,276), (28,277)) -for pin, num_leds in pins: +for pin, num_leds in STRIP_CONFIG: print(pin, num_leds) - np = WS2812B(num_leds, pin, sm, 0.1) + ws = WS2812B(num_leds, pin, sm, brightness=0.2) # 1.0 so fill() is visible + strips.append(ws) sm += 1 - np.fill((8, 0, 0)) - np.show() + +# Cumulative LED count before each strip; total ring size +cumulative_leds = [0] +for ws in strips[:-1]: + cumulative_leds.append(cumulative_leds[-1] + ws.num_leds) +total_ring_leds = cumulative_leds[-1] + strips[-1].num_leds +bytes_per_cycle = total_ring_leds * 3 + +# One rainbow double buffer per strip (length = 2 * num_leds for that strip) +now = time.ticks_ms() +rainbow_data = [make_rainbow_double(ws.num_leds, ws.brightness) for ws in strips] +# Global phase in bytes; each strip: head = (phase + cumulative_leds[i]*3) % strip_len[i] +print(time.ticks_diff(time.ticks_ms(), now), "ms") +rainbow_head = 0 +step = 3 + +while True: + now = time.ticks_ms() + for i, (strip, (double_buf, strip_len)) in enumerate(zip(strips, rainbow_data)): + head = (rainbow_head + cumulative_leds[i] * 3) % strip_len + show_rainbow(strip, double_buf, strip_len, head) + rainbow_head = (rainbow_head + step) % bytes_per_cycle + #print(time.ticks_diff(time.ticks_ms(), now), "ms") + time.sleep_ms(10)