From 6a8b823a4534f5a205f2ae6f0ca8a9a014b5da69 Mon Sep 17 00:00:00 2001 From: Timofey Titovets Date: Sat, 11 Oct 2025 15:10:13 +0200 Subject: [PATCH] led: run update function as reactor callback Update functions could be called within the flush/lookahead context If the update function internally does pause() That would lead to the unpredictable execution of time-critical functions Signed-off-by: Timofey Titovets --- klippy/extras/led.py | 14 ++++++++++---- klippy/extras/neopixel.py | 8 ++------ klippy/extras/pca9533.py | 2 +- klippy/extras/pca9632.py | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/klippy/extras/led.py b/klippy/extras/led.py index 37b58de36..4dc71f3cc 100644 --- a/klippy/extras/led.py +++ b/klippy/extras/led.py @@ -10,6 +10,7 @@ from . import output_pin class LEDHelper: def __init__(self, config, update_func, led_count=1): self.printer = config.get_printer() + self.mutex = self.printer.get_reactor().mutex() self.update_func = update_func self.led_count = led_count self.need_transmit = False @@ -59,11 +60,16 @@ class LEDHelper: def _check_transmit(self, print_time=None): if not self.need_transmit: return + # Just avoid any race conditions + led_state = self.led_state self.need_transmit = False - try: - self.update_func(self.led_state, print_time) - except self.printer.command_error as e: - logging.exception("led update transmit error") + def reactor_cb(eventtime): + try: + with self.mutex: + self.update_func(led_state, print_time) + except self.printer.command_error as e: + logging.exception("led update transmit error") + self.printer.get_reactor().register_callback(reactor_cb) cmd_SET_LED_help = "Set the color of an LED" def cmd_SET_LED(self, gcmd): # Parse parameters diff --git a/klippy/extras/neopixel.py b/klippy/extras/neopixel.py index e72b8a91a..b160fc2f4 100644 --- a/klippy/extras/neopixel.py +++ b/klippy/extras/neopixel.py @@ -16,7 +16,6 @@ MAX_MCU_SIZE = 500 # Sanity check on LED chain length class PrinterNeoPixel: def __init__(self, config): self.printer = printer = config.get_printer() - self.mutex = printer.get_reactor().mutex() # Configure neopixel ppins = printer.lookup_object('pins') pin_params = ppins.lookup_pin(config.get('pin')) @@ -99,11 +98,8 @@ class PrinterNeoPixel: else: logging.info("Neopixel update did not succeed") def update_leds(self, led_state, print_time): - def reactor_bgfunc(eventtime): - with self.mutex: - self.update_color_data(led_state) - self.send_data(print_time) - self.printer.get_reactor().register_callback(reactor_bgfunc) + self.update_color_data(led_state) + self.send_data(print_time) def get_status(self, eventtime=None): return self.led_helper.get_status(eventtime) diff --git a/klippy/extras/pca9533.py b/klippy/extras/pca9533.py index 20f1a6ca9..8f06e1c1a 100644 --- a/klippy/extras/pca9533.py +++ b/klippy/extras/pca9533.py @@ -27,7 +27,7 @@ class PCA9533: minclock = 0 if print_time is not None: minclock = self.i2c.get_mcu().print_time_to_clock(print_time) - self.i2c.i2c_write_noack([PCA9533_PLS0, ls0], minclock=minclock, + self.i2c.i2c_write([PCA9533_PLS0, ls0], minclock=minclock, reqclock=BACKGROUND_PRIORITY_CLOCK) def get_status(self, eventtime): return self.led_helper.get_status(eventtime) diff --git a/klippy/extras/pca9632.py b/klippy/extras/pca9632.py index 099676e0f..af7c241b1 100644 --- a/klippy/extras/pca9632.py +++ b/klippy/extras/pca9632.py @@ -37,7 +37,7 @@ class PCA9632: if self.prev_regs.get(reg) == val: return self.prev_regs[reg] = val - self.i2c.i2c_write_noack([reg, val], minclock=minclock, + self.i2c.i2c_write([reg, val], minclock=minclock, reqclock=BACKGROUND_PRIORITY_CLOCK) def handle_connect(self): #Configure MODE1