Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
0xD34D committed Sep 16, 2024
2 parents 1a6c66a + 900bf2b commit 159a739
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 97 deletions.
13 changes: 13 additions & 0 deletions docs/Config_Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ All dates in this document are approximate.

## Changes

20240912: `SET_PIN`, `SET_SERVO`, `SET_FAN_SPEED`, `M106`, and `M107`
commands are now collated. Previously, if many updates to the same
object were issued faster than the minimum scheduling time (typically
100ms) then actual updates could be queued far into the future. Now if
many updates are issued in rapid succession then it is possible that
only the latest request will be applied. If the previous behavior is
requried then consider adding explicit `G4` delay commands between
updates.

20240912: Support for `maximum_mcu_duration` and `static_value`
parameters in `[output_pin]` config sections have been removed. These
options have been deprecated since 20240123.

20240415: The `on_error_gcode` parameter in the `[virtual_sdcard]`
config section now has a default. If this parameter is not specified
it now defaults to `TURN_OFF_HEATERS`. If the previous behavior is
Expand Down
2 changes: 1 addition & 1 deletion klippy/extras/ads1220.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def hexify(byte_array):
return "[%s]" % (", ".join([hex(b) for b in byte_array]))


class ADS1220():
class ADS1220:
def __init__(self, config):
self.printer = printer = config.get_printer()
self.name = config.get_name().split()[-1]
Expand Down
30 changes: 14 additions & 16 deletions klippy/extras/hx71x.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
SAMPLE_ERROR_LONG_READ = 0x40000000

# Implementation of HX711 and HX717
class HX71xBase():
class HX71xBase:
def __init__(self, config, sensor_type,
sample_rate_options, default_sample_rate,
gain_options, default_gain):
Expand Down Expand Up @@ -145,23 +145,21 @@ def _process_batch(self, eventtime):
'overflows': self.ffreader.get_last_overflows()}


class HX711(HX71xBase):
def __init__(self, config):
super(HX711, self).__init__(config, "hx711",
# HX711 sps options
{80: 80, 10: 10}, 80,
# HX711 gain/channel options
{'A-128': 1, 'B-32': 2, 'A-64': 3}, 'A-128')
def HX711(config):
return HX71xBase(config, "hx711",
# HX711 sps options
{80: 80, 10: 10}, 80,
# HX711 gain/channel options
{'A-128': 1, 'B-32': 2, 'A-64': 3}, 'A-128')


class HX717(HX71xBase):
def __init__(self, config):
super(HX717, self).__init__(config, "hx717",
# HX717 sps options
{320: 320, 80: 80, 20: 20, 10: 10}, 320,
# HX717 gain/channel options
{'A-128': 1, 'B-64': 2, 'A-64': 3,
'B-8': 4}, 'A-128')
def HX717(config):
return HX71xBase(config, "hx717",
# HX717 sps options
{320: 320, 80: 80, 20: 20, 10: 10}, 320,
# HX717 gain/channel options
{'A-128': 1, 'B-64': 2, 'A-64': 3,
'B-8': 4}, 'A-128')


HX71X_SENSOR_TYPES = {
Expand Down
113 changes: 58 additions & 55 deletions klippy/extras/output_pin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,48 @@
# This file may be distributed under the terms of the GNU GPLv3 license.

PIN_MIN_TIME = 0.100
RESEND_HOST_TIME = 0.300 + PIN_MIN_TIME
MAX_SCHEDULE_TIME = 5.0

# Helper code to queue g-code requests
class GCodeRequestQueue:
def __init__(self, config, mcu, callback):
self.printer = printer = config.get_printer()
self.mcu = mcu
self.callback = callback
self.rqueue = []
self.next_min_flush_time = 0.
self.toolhead = None
mcu.register_flush_callback(self._flush_notification)
printer.register_event_handler("klippy:connect", self._handle_connect)
def _handle_connect(self):
self.toolhead = self.printer.lookup_object('toolhead')
def _flush_notification(self, print_time, clock):
rqueue = self.rqueue
while rqueue:
next_time = max(rqueue[0][0], self.next_min_flush_time)
if next_time > print_time:
return
# Skip requests that have been overridden with a following request
pos = 0
while pos + 1 < len(rqueue) and rqueue[pos + 1][0] <= next_time:
pos += 1
req_pt, req_val = rqueue[pos]
# Invoke callback for the request
want_dequeue, min_wait_time = self.callback(next_time, req_val)
self.next_min_flush_time = next_time + max(min_wait_time,
PIN_MIN_TIME)
if want_dequeue:
pos += 1
del rqueue[:pos]
# Ensure following queue items are flushed
self.toolhead.note_mcu_movequeue_activity(self.next_min_flush_time)
def queue_request(self, print_time, value):
self.rqueue.append((print_time, value))
self.toolhead.note_mcu_movequeue_activity(print_time)
def queue_gcode_request(self, value):
self.toolhead.register_lookahead_callback(
(lambda pt: self.queue_request(pt, value)))

class PrinterOutputPin:
def __init__(self, config):
self.printer = config.get_printer()
Expand All @@ -24,30 +63,16 @@ def __init__(self, config):
else:
self.mcu_pin = ppins.setup_pin('digital_out', config.get('pin'))
self.scale = 1.
self.last_print_time = 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:
config.deprecate('maximum_mcu_duration')
self.resend_interval = max_mcu_duration - RESEND_HOST_TIME
self.mcu_pin.setup_max_duration(0.)
# Determine start and shutdown values
static_value = config.getfloat('static_value', None,
minval=0., maxval=self.scale)
if static_value is not None:
config.deprecate('static_value')
self.last_value = self.shutdown_value = static_value / self.scale
else:
self.last_value = config.getfloat(
'value', 0., minval=0., maxval=self.scale) / self.scale
self.shutdown_value = config.getfloat(
'shutdown_value', 0., minval=0., maxval=self.scale) / self.scale
self.last_value = config.getfloat(
'value', 0., minval=0., maxval=self.scale) / self.scale
self.shutdown_value = config.getfloat(
'shutdown_value', 0., minval=0., maxval=self.scale) / self.scale
self.mcu_pin.setup_start_value(self.last_value, self.shutdown_value)
# Create gcode request queue
self.gcrq = GCodeRequestQueue(config, self.mcu_pin.get_mcu(),
self._set_pin)
# Register commands
pin_name = config.get_name().split()[1]
gcode = self.printer.lookup_object('gcode')
Expand All @@ -56,45 +81,23 @@ 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, is_resend=False):
if value == self.last_value and not is_resend:
return
print_time = max(print_time, self.last_print_time + PIN_MIN_TIME)
if self.is_pwm:
self.mcu_pin.set_pwm(print_time, value)
else:
self.mcu_pin.set_digital(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)
def _set_pin(self, print_time, value):
if value != self.last_value:
self.last_value = value
if self.is_pwm:
self.mcu_pin.set_pwm(print_time, value)
else:
self.mcu_pin.set_digital(print_time, value)
return (True, 0.)
cmd_SET_PIN_help = "Set the value of an output pin"
def cmd_SET_PIN(self, gcmd):
# Read requested value
value = gcmd.get_float('VALUE', minval=0., maxval=self.scale)
value /= self.scale
if not self.is_pwm and value not in [0., 1.]:
raise gcmd.error("Invalid pin value")
# Obtain print_time and apply requested settings
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
# Queue requested value
self.gcrq.queue_gcode_request(value)

def load_config_prefix(config):
return PrinterOutputPin(config)
23 changes: 11 additions & 12 deletions klippy/extras/servo.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Support for servos
#
# Copyright (C) 2017-2020 Kevin O'Connor <[email protected]>
# Copyright (C) 2017-2024 Kevin O'Connor <[email protected]>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
from . import output_pin

SERVO_SIGNAL_PERIOD = 0.020
PIN_MIN_TIME = 0.100

class PrinterServo:
def __init__(self, config):
Expand All @@ -18,7 +18,7 @@ def __init__(self, config):
self.max_angle = config.getfloat('maximum_servo_angle', 180.)
self.angle_to_width = (self.max_width - self.min_width) / self.max_angle
self.width_to_value = 1. / SERVO_SIGNAL_PERIOD
self.last_value = self.last_value_time = 0.
self.last_value = 0.
initial_pwm = 0.
iangle = config.getfloat('initial_angle', None, minval=0., maxval=360.)
if iangle is not None:
Expand All @@ -33,6 +33,9 @@ def __init__(self, config):
self.mcu_servo.setup_max_duration(0.)
self.mcu_servo.setup_cycle_time(SERVO_SIGNAL_PERIOD)
self.mcu_servo.setup_start_value(initial_pwm, 0.)
# Create gcode request queue
self.gcrq = output_pin.GCodeRequestQueue(
config, self.mcu_servo.get_mcu(), self._set_pwm)
# Register commands
servo_name = config.get_name().split()[1]
gcode = self.printer.lookup_object('gcode')
Expand All @@ -42,12 +45,10 @@ def __init__(self, config):
def get_status(self, eventtime):
return {'value': self.last_value}
def _set_pwm(self, print_time, value):
if value == self.last_value:
return
print_time = max(print_time, self.last_value_time + PIN_MIN_TIME)
self.mcu_servo.set_pwm(print_time, value)
self.last_value = value
self.last_value_time = print_time
if value != self.last_value:
self.last_value = value
self.mcu_servo.set_pwm(print_time, value)
return (True, 0.)
def _get_pwm_from_angle(self, angle):
angle = max(0., min(self.max_angle, angle))
width = self.min_width + angle * self.angle_to_width
Expand All @@ -64,9 +65,7 @@ def cmd_SET_SERVO(self, gcmd):
else:
angle = gcmd.get_float('ANGLE')
value = self._get_pwm_from_angle(angle)
toolhead = self.printer.lookup_object('toolhead')
toolhead.register_lookahead_callback((lambda pt:
self._set_pwm(pt, value)))
self.gcrq.queue_gcode_request(value)

def load_config_prefix(config):
return PrinterServo(config)
14 changes: 13 additions & 1 deletion scripts/spi_flash/board_defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
'mcu': "stm32f103xe",
'spi_bus': "spi2",
"cs_pin": "PA15",
"conversion_script": "scripts/update_mks_robin.py",
"firmware_path": "Robin_e3.bin",
"current_firmware_path": "Robin_e3.cur"
},
Expand Down Expand Up @@ -133,6 +134,16 @@
'mcu': "stm32g0b1xx",
'spi_bus': "spi1",
"cs_pin": "PB8"
},
'chitu-v6': {
'mcu': "stm32f103xe",
'spi_bus': "swspi",
'spi_pins': "PC8,PD2,PC12",
"cs_pin": "PC11",
#'sdio_bus': 'sdio',
"conversion_script": "scripts/update_chitu.py",
"firmware_path": "update.cbd",
'skip_verify': True
}
}

Expand Down Expand Up @@ -182,7 +193,8 @@
'fysetc-s6-v1.2': BOARD_DEFS['fysetc-spider'],
'fysetc-s6-v2': BOARD_DEFS['fysetc-spider'],
'robin_v3': BOARD_DEFS['monster8'],
'btt-skrat-v1.0': BOARD_DEFS['btt-skrat']
'btt-skrat-v1.0': BOARD_DEFS['btt-skrat'],
'chitu-v6': BOARD_DEFS['chitu-v6']
}

def list_boards():
Expand Down
23 changes: 11 additions & 12 deletions scripts/spi_flash/spi_flash.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,19 @@ def translate_serial_to_tty(device):
return ttyname, ttyname

def check_need_convert(board_name, config):
if board_name.lower().startswith('mks-robin-e3'):
# we need to convert this file
robin_util = os.path.join(
fatfs_lib.KLIPPER_DIR, "scripts/update_mks_robin.py")
klipper_bin = config['klipper_bin_path']
robin_bin = os.path.join(
conv_script = config.get("conversion_script")
if conv_script is None:
return
conv_util = os.path.join(fatfs_lib.KLIPPER_DIR, conv_script)
klipper_bin = config['klipper_bin_path']
dest_bin = os.path.join(
os.path.dirname(klipper_bin),
os.path.basename(config['firmware_path']))
cmd = "%s %s %s %s" % (sys.executable, robin_util, klipper_bin,
robin_bin)
output("Converting Klipper binary to MKS Robin format...")
os.system(cmd)
output_line("Done")
config['klipper_bin_path'] = robin_bin
cmd = "%s %s %s %s" % (sys.executable, conv_util, klipper_bin, dest_bin)
output("Converting Klipper binary to custom format...")
os.system(cmd)
output_line("Done")
config['klipper_bin_path'] = dest_bin


###########################################################
Expand Down
23 changes: 23 additions & 0 deletions test/klippy/load_cell.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Test config for load_cell
[mcu]
serial: /dev/ttyACM0

[printer]
kinematics: none
max_velocity: 300
max_accel: 3000

[load_cell my_ads1220]
sensor_type: ads1220
cs_pin: PA0
data_ready_pin: PA1

[load_cell my_hx711]
sensor_type: hx711
sclk_pin: PA2
dout_pin: PA3

[load_cell my_hx717]
sensor_type: hx717
sclk_pin: PA4
dout_pin: PA5
5 changes: 5 additions & 0 deletions test/klippy/load_cell.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Tests for loadcell sensors
DICTIONARY atmega2560.dict
CONFIG load_cell.cfg

G4 P1000

0 comments on commit 159a739

Please sign in to comment.