diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index c7a2a3dbfbdd..e51065e3034d 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -3141,6 +3141,7 @@ pin: # The pin to configure as an output. This parameter must be provided. #value: #shutdown_value: +#maximum_mcu_duration: #cycle_time: 0.100 #hardware_pwm: False #scale: diff --git a/klippy/extras/pwm_tool.py b/klippy/extras/pwm_tool.py index c4047cf4e4a6..198fb44374bb 100644 --- a/klippy/extras/pwm_tool.py +++ b/klippy/extras/pwm_tool.py @@ -6,6 +6,7 @@ import chelper PIN_MIN_TIME = 0.100 +RESEND_HOST_TIME = 0.300 + PIN_MIN_TIME MAX_SCHEDULE_TIME = 5.0 class error(Exception): @@ -121,7 +122,16 @@ def __init__(self, config): self.mcu_pin.setup_cycle_time(cycle_time, hardware_pwm) self.scale = config.getfloat('scale', 1., above=0.) self.last_print_time = 0. - self.mcu_pin.setup_max_duration(0.) + # Support mcu checking for maximum duration + self.reactor = self.printer.get_reactor() + self.resend_timer = None + self.resend_interval = 0. + max_mcu_duration = config.getfloat('maximum_mcu_duration', 0., + minval=0.500, + maxval=MAX_SCHEDULE_TIME) + self.mcu_pin.setup_max_duration(max_mcu_duration) + if max_mcu_duration: + self.resend_interval = max_mcu_duration - RESEND_HOST_TIME # Determine start and shutdown values self.last_value = config.getfloat( 'value', 0., minval=0., maxval=self.scale) / self.scale @@ -136,13 +146,18 @@ def __init__(self, config): desc=self.cmd_SET_PIN_help) def get_status(self, eventtime): return {'value': self.last_value} - def _set_pin(self, print_time, value): - if value == self.last_value: + def _set_pin(self, print_time, value, is_resend=False): + if value == self.last_value and not is_resend: return print_time = max(print_time, self.last_print_time) self.mcu_pin.set_pwm(print_time, value) self.last_value = value self.last_print_time = print_time + if self.resend_interval and self.resend_timer is None: + self.resend_timer = self.reactor.register_timer( + self._resend_current_val, self.reactor.NOW) + toolhead = self.printer.lookup_object('toolhead') + toolhead.note_move_queue_activity(print_time) cmd_SET_PIN_help = "Set the value of an output pin" def cmd_SET_PIN(self, gcmd): # Read requested value @@ -152,6 +167,20 @@ def cmd_SET_PIN(self, gcmd): toolhead = self.printer.lookup_object('toolhead') toolhead.register_lookahead_callback( lambda print_time: self._set_pin(print_time, value)) + def _resend_current_val(self, eventtime): + if self.last_value == self.shutdown_value: + self.reactor.unregister_timer(self.resend_timer) + self.resend_timer = None + return self.reactor.NEVER + + systime = self.reactor.monotonic() + print_time = self.mcu_pin.get_mcu().estimated_print_time(systime) + time_diff = (self.last_print_time + self.resend_interval) - print_time + if time_diff > 0.: + # Reschedule for resend time + return systime + time_diff + self._set_pin(print_time + PIN_MIN_TIME, self.last_value, True) + return systime + self.resend_interval def load_config_prefix(config): return PrinterOutputPin(config) diff --git a/klippy/toolhead.py b/klippy/toolhead.py index d8b9382570b6..0bb7bf1919b0 100644 --- a/klippy/toolhead.py +++ b/klippy/toolhead.py @@ -543,6 +543,14 @@ def register_lookahead_callback(self, callback): last_move.timing_callbacks.append(callback) def note_kinematic_activity(self, kin_time): self.last_kin_move_time = max(self.last_kin_move_time, kin_time) + def note_move_queue_activity(self, mq_time): + if self.special_queuing_state == "Flushed": + # Must manually flush move queue buffers + for m in self.all_mcus: + m.flush_moves(mq_time) + else: + # Move queue will get flushed via regular toolhead flushing + self.last_kin_move_time = max(self.last_kin_move_time, mq_time) def get_max_velocity(self): return self.max_velocity, self.max_accel def _calc_junction_deviation(self):