From c148f17ea3391e3720961270a12eb0645f688e12 Mon Sep 17 00:00:00 2001 From: Paul McGowan Date: Wed, 2 Jun 2021 10:51:45 -0400 Subject: [PATCH] neopixel: add sync parameter to prevent waking toolhead (#4339) neopixel: add sync param to prevent waking toolhead dotstar: refactor to match neopixel methods and add sync parameter Signed-off-by: Paul McGowan --- docs/G-Codes.md | 9 +++++-- klippy/extras/dotstar.py | 50 ++++++++++++++++++++++++++------------- klippy/extras/neopixel.py | 10 ++++++-- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/docs/G-Codes.md b/docs/G-Codes.md index 273870d5..38e7e389 100644 --- a/docs/G-Codes.md +++ b/docs/G-Codes.md @@ -272,7 +272,7 @@ The following command is available when a [neopixel config section](Config_Reference.md#neopixel) or [dotstar config section](Config_Reference.md#dotstar) is enabled: - `SET_LED LED= RED= GREEN= BLUE= - WHITE= [INDEX=] [TRANSMIT=0]`: This sets the LED + WHITE= [INDEX=] [TRANSMIT=0] [SYNC=1]`: This sets the LED output. Each color `` must be between 0.0 and 1.0. The WHITE option is only valid on RGBW LEDs. If multiple LED chips are daisy-chained then one may specify INDEX to alter the color of just @@ -281,7 +281,12 @@ The following command is available when a to the provided color. If TRANSMIT=0 is specified then the color change will only be made on the next SET_LED command that does not specify TRANSMIT=0; this may be useful in combination with the INDEX - parameter to batch multiple updates in a daisy-chain. + parameter to batch multiple updates in a daisy-chain. By default, the + SET_LED command will sync it's changes with other ongoing gcode commands. + This can lead to undesirable behavior if LEDs are being set while the + printer is not printing as it will reset the idle timeout. If careful + timing is not needed, the optional SYNC=0 parameter can be specified to + apply the changes instantly and not reset the idle timeout. ## Servo Commands diff --git a/klippy/extras/dotstar.py b/klippy/extras/dotstar.py index 08c370fa..6c7182a2 100644 --- a/klippy/extras/dotstar.py +++ b/klippy/extras/dotstar.py @@ -11,6 +11,7 @@ class PrinterDotstar: def __init__(self, config): self.printer = config.get_printer() name = config.get_name().split()[1] + self.mutex = self.printer.get_reactor().mutex() # Configure a software spi bus ppins = self.printer.lookup_object('pins') data_pin_params = ppins.lookup_pin(config.get('data_pin')) @@ -26,17 +27,29 @@ class PrinterDotstar: red = config.getfloat('initial_RED', 0., minval=0., maxval=1.) green = config.getfloat('initial_GREEN', 0., minval=0., maxval=1.) blue = config.getfloat('initial_BLUE', 0., minval=0., maxval=1.) - red = int(red * 255. + .5) - blue = int(blue * 255. + .5) - green = int(green * 255. + .5) color_data = [0xff, blue, green, red] * self.chain_count self.color_data = [0, 0, 0, 0] + color_data + [0xff, 0xff, 0xff, 0xff] - self.printer.register_event_handler("klippy:connect", self.send_data) + self.update_color_data(red, green, blue) + self.old_color_data = bytearray([d ^ 1 for d in self.color_data]) # Register commands + self.printer.register_event_handler("klippy:connect", self.send_data) gcode = self.printer.lookup_object('gcode') gcode.register_mux_command("SET_LED", "LED", name, self.cmd_SET_LED, desc=self.cmd_SET_LED_help) + def update_color_data(self, red, green, blue, white=None, index=None): + red = int(red * 255. + .5) + blue = int(blue * 255. + .5) + green = int(green * 255. + .5) + color_data = [0xff, blue, green, red] + if index is not None: + self.color_data[index*4:(index+1)*4] = color_data + else: + self.color_data[4:-4] = color_data * self.chain_count def send_data(self, print_time=None): + old_data, new_data = self.old_color_data, self.color_data + if new_data == old_data: + return + minclock = 0 if print_time is not None: minclock = self.spi.get_mcu().print_time_to_clock(print_time) @@ -50,20 +63,25 @@ class PrinterDotstar: red = gcmd.get_float('RED', 0., minval=0., maxval=1.) green = gcmd.get_float('GREEN', 0., minval=0., maxval=1.) blue = gcmd.get_float('BLUE', 0., minval=0., maxval=1.) - transmit = gcmd.get_int('TRANSMIT', 1) - red = int(red * 255. + .5) - blue = int(blue * 255. + .5) - green = int(green * 255. + .5) - color_data = [0xff, blue, green, red] + white = 0.0 #dotstar's dont have white yet index = gcmd.get_int('INDEX', None, minval=1, maxval=self.chain_count) - if index is not None: - self.color_data[index*4:(index+1)*4] = color_data - else: - self.color_data[4:-4] = color_data * self.chain_count - # Send command - if transmit: + transmit = gcmd.get_int('TRANSMIT', 1) + sync = gcmd.get_int('SYNC', 1) + def reactor_bgfunc(print_time): + with self.mutex: + self.update_color_data(red, green, blue, index=index) + if transmit: + self.send_data(print_time) + def lookahead_bgfunc(print_time): + reactor = self.printer.get_reactor() + reactor.register_callback(lambda et: reactor_bgfunc(print_time)) + if sync: + #Sync LED Update with print time and send toolhead = self.printer.lookup_object('toolhead') - toolhead.register_lookahead_callback(self.send_data) + toolhead.register_lookahead_callback(lookahead_bgfunc) + else: + #Send update now (so as not to wake toolhead and reset idle_timeout) + lookahead_bgfunc(None) def load_config_prefix(config): return PrinterDotstar(config) diff --git a/klippy/extras/neopixel.py b/klippy/extras/neopixel.py index e7785d97..1af0def4 100644 --- a/klippy/extras/neopixel.py +++ b/klippy/extras/neopixel.py @@ -119,6 +119,7 @@ class PrinterNeoPixel: white = gcmd.get_float('WHITE', 0., minval=0., maxval=1.) index = gcmd.get_int('INDEX', None, minval=1, maxval=self.chain_count) transmit = gcmd.get_int('TRANSMIT', 1) + sync = gcmd.get_int('SYNC', 1) # Update and transmit data def reactor_bgfunc(print_time): with self.mutex: @@ -128,8 +129,13 @@ class PrinterNeoPixel: def lookahead_bgfunc(print_time): reactor = self.printer.get_reactor() reactor.register_callback(lambda et: reactor_bgfunc(print_time)) - toolhead = self.printer.lookup_object('toolhead') - toolhead.register_lookahead_callback(lookahead_bgfunc) + if sync: + #Sync LED Update with print time and send + toolhead = self.printer.lookup_object('toolhead') + toolhead.register_lookahead_callback(lookahead_bgfunc) + else: + #Send update now (so as not to wake toolhead and reset idle_timeout) + lookahead_bgfunc(None) def load_config_prefix(config): return PrinterNeoPixel(config)