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 <mental405@gmail.com>
This commit is contained in:
Paul McGowan 2021-06-02 10:51:45 -04:00 committed by GitHub
parent 9f4a0dc77f
commit c148f17ea3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 20 deletions

View File

@ -272,7 +272,7 @@ The following command is available when a
[neopixel config section](Config_Reference.md#neopixel) or [neopixel config section](Config_Reference.md#neopixel) or
[dotstar config section](Config_Reference.md#dotstar) is enabled: [dotstar config section](Config_Reference.md#dotstar) is enabled:
- `SET_LED LED=<config_name> RED=<value> GREEN=<value> BLUE=<value> - `SET_LED LED=<config_name> RED=<value> GREEN=<value> BLUE=<value>
WHITE=<value> [INDEX=<index>] [TRANSMIT=0]`: This sets the LED WHITE=<value> [INDEX=<index>] [TRANSMIT=0] [SYNC=1]`: This sets the LED
output. Each color `<value>` must be between 0.0 and 1.0. The WHITE output. Each color `<value>` must be between 0.0 and 1.0. The WHITE
option is only valid on RGBW LEDs. If multiple LED chips are 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 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 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 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 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 ## Servo Commands

View File

@ -11,6 +11,7 @@ class PrinterDotstar:
def __init__(self, config): def __init__(self, config):
self.printer = config.get_printer() self.printer = config.get_printer()
name = config.get_name().split()[1] name = config.get_name().split()[1]
self.mutex = self.printer.get_reactor().mutex()
# Configure a software spi bus # Configure a software spi bus
ppins = self.printer.lookup_object('pins') ppins = self.printer.lookup_object('pins')
data_pin_params = ppins.lookup_pin(config.get('data_pin')) 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.) red = config.getfloat('initial_RED', 0., minval=0., maxval=1.)
green = config.getfloat('initial_GREEN', 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.) 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 color_data = [0xff, blue, green, red] * self.chain_count
self.color_data = [0, 0, 0, 0] + color_data + [0xff, 0xff, 0xff, 0xff] 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 # Register commands
self.printer.register_event_handler("klippy:connect", self.send_data)
gcode = self.printer.lookup_object('gcode') gcode = self.printer.lookup_object('gcode')
gcode.register_mux_command("SET_LED", "LED", name, self.cmd_SET_LED, gcode.register_mux_command("SET_LED", "LED", name, self.cmd_SET_LED,
desc=self.cmd_SET_LED_help) 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): 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 minclock = 0
if print_time is not None: if print_time is not None:
minclock = self.spi.get_mcu().print_time_to_clock(print_time) 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.) red = gcmd.get_float('RED', 0., minval=0., maxval=1.)
green = gcmd.get_float('GREEN', 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.) blue = gcmd.get_float('BLUE', 0., minval=0., maxval=1.)
transmit = gcmd.get_int('TRANSMIT', 1) white = 0.0 #dotstar's dont have white yet
red = int(red * 255. + .5)
blue = int(blue * 255. + .5)
green = int(green * 255. + .5)
color_data = [0xff, blue, green, red]
index = gcmd.get_int('INDEX', None, minval=1, maxval=self.chain_count) index = gcmd.get_int('INDEX', None, minval=1, maxval=self.chain_count)
if index is not None: transmit = gcmd.get_int('TRANSMIT', 1)
self.color_data[index*4:(index+1)*4] = color_data sync = gcmd.get_int('SYNC', 1)
else: def reactor_bgfunc(print_time):
self.color_data[4:-4] = color_data * self.chain_count with self.mutex:
# Send command self.update_color_data(red, green, blue, index=index)
if transmit: 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 = 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): def load_config_prefix(config):
return PrinterDotstar(config) return PrinterDotstar(config)

View File

@ -119,6 +119,7 @@ class PrinterNeoPixel:
white = gcmd.get_float('WHITE', 0., minval=0., maxval=1.) white = gcmd.get_float('WHITE', 0., minval=0., maxval=1.)
index = gcmd.get_int('INDEX', None, minval=1, maxval=self.chain_count) index = gcmd.get_int('INDEX', None, minval=1, maxval=self.chain_count)
transmit = gcmd.get_int('TRANSMIT', 1) transmit = gcmd.get_int('TRANSMIT', 1)
sync = gcmd.get_int('SYNC', 1)
# Update and transmit data # Update and transmit data
def reactor_bgfunc(print_time): def reactor_bgfunc(print_time):
with self.mutex: with self.mutex:
@ -128,8 +129,13 @@ class PrinterNeoPixel:
def lookahead_bgfunc(print_time): def lookahead_bgfunc(print_time):
reactor = self.printer.get_reactor() reactor = self.printer.get_reactor()
reactor.register_callback(lambda et: reactor_bgfunc(print_time)) reactor.register_callback(lambda et: reactor_bgfunc(print_time))
toolhead = self.printer.lookup_object('toolhead') if sync:
toolhead.register_lookahead_callback(lookahead_bgfunc) #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): def load_config_prefix(config):
return PrinterNeoPixel(config) return PrinterNeoPixel(config)