Skip to content

Commit

Permalink
noncritical mcus
Browse files Browse the repository at this point in the history
  • Loading branch information
bwnance authored and pellcorp committed Nov 6, 2024
1 parent bbe30e5 commit e201ed3
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 42 deletions.
8 changes: 8 additions & 0 deletions klippy/extras/adxl345.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ def _build_config(self):
"query_adxl345 oid=%c rest_ticks=%u", cq=cmdqueue)
self.ffreader.setup_query_command("query_adxl345_status oid=%c",
oid=self.oid, cq=cmdqueue)

def check_connected(self):
if self.mcu.non_critical_disconnected:
raise self.printer.command_error(
f"ADXL: {self.name} could not connect because mcu: {self.mcu.get_name()} is non_critical_disconnected!"
)

def read_reg(self, reg):
params = self.spi.spi_transfer([reg | REG_MOD_READ, 0x00])
response = bytearray(params['response'])
Expand All @@ -237,6 +244,7 @@ def set_reg(self, reg, val, minclock=0):
"(e.g. faulty wiring) or a faulty adxl345 chip." % (
reg, val, stored_val))
def start_internal_client(self):
self.check_connected()
aqh = AccelQueryHelper(self.printer)
self.batch_bulk.add_client(aqh.handle_batch)
return aqh
Expand Down
8 changes: 8 additions & 0 deletions klippy/extras/display/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ def __init__(self, config):
raise config.error("Unknown display_data group '%s'" % (dgroup,))
# Screen updating
self.printer.register_event_handler("klippy:ready", self.handle_ready)
self.printer.register_event_handler(
self.lcd_chip.mcu.get_non_critical_reconnect_event_name(),
self.handle_reconnect,
)
self.screen_update_timer = self.reactor.register_timer(
self.screen_update_event)
self.redraw_request_pending = False
Expand All @@ -213,6 +217,10 @@ def __init__(self, config):
self.cmd_SET_DISPLAY_GROUP)
def get_dimensions(self):
return self.lcd_chip.get_dimensions()

def handle_reconnect(self):
self.lcd_chip.init()

def handle_ready(self):
self.lcd_chip.init()
# Start screen update timer
Expand Down
8 changes: 8 additions & 0 deletions klippy/extras/lis2dw.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ def _build_config(self):
"query_lis2dw oid=%c rest_ticks=%u", cq=cmdqueue)
self.ffreader.setup_query_command("query_lis2dw_status oid=%c",
oid=self.oid, cq=cmdqueue)

def check_connected(self):
if self.mcu.non_critical_disconnected:
raise self.printer.command_error(
f"LIS2DW: {self.name} could not connect because mcu: {self.mcu.get_name()} is non_critical_disconnected!"
)

def read_reg(self, reg):
params = self.spi.spi_transfer([reg | REG_MOD_READ, 0x00])
response = bytearray(params['response'])
Expand All @@ -82,6 +89,7 @@ def set_reg(self, reg, val, minclock=0):
"(e.g. faulty wiring) or a faulty lis2dw chip." % (
reg, val, stored_val))
def start_internal_client(self):
self.check_connected()
aqh = adxl345.AccelQueryHelper(self.printer)
self.batch_bulk.add_client(aqh.handle_batch)
return aqh
Expand Down
8 changes: 8 additions & 0 deletions klippy/extras/mpu9250.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,20 @@ def _build_config(self):
"query_mpu9250 oid=%c rest_ticks=%u", cq=cmdqueue)
self.ffreader.setup_query_command("query_mpu9250_status oid=%c",
oid=self.oid, cq=cmdqueue)

def check_connected(self):
if self.mcu.non_critical_disconnected:
raise self.printer.command_error(
f"MPU: {self.name} could not connect because mcu: {self.mcu.get_name()} is non_critical_disconnected!"
)

def read_reg(self, reg):
params = self.i2c.i2c_read([reg], 1)
return bytearray(params['response'])[0]
def set_reg(self, reg, val, minclock=0):
self.i2c.i2c_write([reg, val & 0xFF], minclock=minclock)
def start_internal_client(self):
self.check_connected()
aqh = adxl345.AccelQueryHelper(self.printer)
self.batch_bulk.add_client(aqh.handle_batch)
return aqh
Expand Down
3 changes: 3 additions & 0 deletions klippy/extras/neopixel.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ def __init__(self, config):
self.old_color_data = bytearray([d ^ 1 for d in self.color_data])
# Register callbacks
printer.register_event_handler("klippy:connect", self.send_data)
printer.register_event_handler(
self.mcu.get_non_critical_reconnect_event_name(), self.send_data
)
def build_config(self):
bmt = self.mcu.seconds_to_clock(BIT_MAX_TIME)
rmt = self.mcu.seconds_to_clock(RESET_MIN_TIME)
Expand Down
4 changes: 4 additions & 0 deletions klippy/extras/temperature_mcu.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def __init__(self, config):
return
self.printer.register_event_handler("klippy:mcu_identify",
self.handle_mcu_identify)
self.mcu_adc.get_mcu().register_config_callback(self._build_config)
# Temperature interface
def setup_callback(self, temperature_callback):
self.temperature_callback = temperature_callback
Expand All @@ -59,6 +60,9 @@ def calc_adc(self, temp):
def calc_base(self, temp, adc):
return temp - adc * self.slope
def handle_mcu_identify(self):
self._build_config()

def _build_config(self):
# Obtain mcu information
mcu = self.mcu_adc.get_mcu()
self.debug_read_cmd = mcu.lookup_query_command(
Expand Down
9 changes: 8 additions & 1 deletion klippy/extras/tmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,14 @@ def _handle_connect(self):
self.stepper_name)
# Send init
try:
self._init_registers()
if self.mcu_tmc.mcu.non_critical_disconnected:
logging.info(
"TMC %s failed to init - non_critical_mcu: %s is disconnected!",
self.name,
self.mcu_tmc.mcu.get_name(),
)
else:
self._init_registers()
except self.printer.command_error as e:
logging.info("TMC %s failed to init: %s", self.name, str(e))
# get_status information export
Expand Down
2 changes: 2 additions & 0 deletions klippy/extras/tmc2130.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ def __init__(self, config, name_to_reg, fields, tmc_frequency):
self.name_to_reg = name_to_reg
self.fields = fields
self.tmc_frequency = tmc_frequency
self.mcu = self.tmc_spi.spi.get_mcu()

def get_fields(self):
return self.fields
def get_register(self, reg_name):
Expand Down
2 changes: 2 additions & 0 deletions klippy/extras/tmc2660.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ def __init__(self, config, name_to_reg, fields):
self.spi = bus.MCU_SPI_from_config(config, 0, default_speed=4000000)
self.name_to_reg = name_to_reg
self.fields = fields
self.mcu = self.spi.get_mcu()

def get_fields(self):
return self.fields
def get_register(self, reg_name):
Expand Down
2 changes: 2 additions & 0 deletions klippy/extras/tmc_uart.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ def __init__(self, config, name_to_reg, fields, max_addr, tmc_frequency):
config, max_addr)
self.mutex = self.mcu_uart.mutex
self.tmc_frequency = tmc_frequency
self.mcu = self.mcu_uart.mcu

def get_fields(self):
return self.fields
def _do_get_register(self, reg_name):
Expand Down
106 changes: 71 additions & 35 deletions klippy/mcu.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ class MCU:
def __init__(self, config, clocksync):
self._config = config
self._printer = printer = config.get_printer()
self.gcode = printer.lookup_object("gcode")
self._clocksync = clocksync
self._reactor = printer.get_reactor()
self._name = config.get_name()
Expand Down Expand Up @@ -606,15 +607,31 @@ def __init__(self, config, clocksync):
self._mcu_tick_stddev = 0.
self._mcu_tick_awake = 0.

#noncritical mcus
self.non_critical_recon_timer = self._reactor.register_timer(
self.non_critical_recon_event
)
# noncritical mcus
self.is_non_critical = config.getboolean("is_non_critical", False)
self._non_critical_disconnected = False
# self.last_noncrit_recon_eventtime = None
self.reconnect_interval = config.getfloat("reconnect_interval", 2.0) + 0.12 #add small change to not collide with other events

if self.is_non_critical and self.get_name() == "mcu":
raise error("Primary MCU cannot be marked as non-critical!")
if self.is_non_critical:
self.non_critical_recon_timer = self._reactor.register_timer(
self.non_critical_recon_event
)
if canbus_uuid:
raise error("CAN MCUs can't be non-critical yet!")
self.non_critical_disconnected = False
self._non_critical_reconnect_event_name = (
f"danger:non_critical_mcu_{self.get_name()}:reconnected"
)
self._non_critical_disconnect_event_name = (
f"danger:non_critical_mcu_{self.get_name()}:disconnected"
)
self.reconnect_interval = (
config.getfloat("reconnect_interval", 2.0) + 0.12
) # add small change to not collide with other events
self._cached_init_state = False
self._oid_count_post_inits = 0
self._config_cmds_post_inits = []
self._init_cmds_post_inits = []
self._restart_cmds_post_inits = []
# Register handlers
printer.load_object(config, "error_mcu")
printer.register_event_handler("klippy:firmware_restart",
Expand Down Expand Up @@ -687,32 +704,45 @@ def dummy_estimated_print_time(eventtime):
self.estimated_print_time = dummy_estimated_print_time

def handle_non_critical_disconnect(self):
self._non_critical_disconnected = True
self.non_critical_disconnected = True
self._clocksync.disconnect()
self._disconnect()
self._reactor.update_timer(
self.non_critical_recon_timer, self._reactor.NOW
)
logging.info("mcu: %s disconnected", self._name)
self._printer.send_event(self._non_critical_disconnect_event_name)
self.gcode.respond_info(f"mcu: '{self._name}' disconnected!", log=True)

def non_critical_recon_event(self, eventtime):
self.recon_mcu()
return eventtime + self.reconnect_interval
success = self.recon_mcu()
if success:
self.gcode.respond_info(
f"mcu: '{self._name}' reconnected!", log=True
)
return self._reactor.NEVER
else:
return eventtime + self.reconnect_interval

def _send_config(self, prev_crc):
if not self._cached_init_state:
# first time config, we haven't created callback oids yet
# so save the oid count for state reset later
self._oid_count_post_inits = self._oid_count
self._config_cmds_post_inits = self._config_cmds.copy()
self._init_cmds_post_inits = self._init_cmds.copy()
self._restart_cmds_post_inits = self._restart_cmds.copy()
self._cached_init_state = True
# Build config commands
for cb in self._config_callbacks:
cb()
self._config_cmds.insert(0, "allocate_oids count=%d"
% (self._oid_count,))

# Resolve pin names
ppins = self._printer.lookup_object('pins')
pin_resolver = ppins.get_pin_resolver(self._name)
for cmdlist in (self._config_cmds, self._restart_cmds, self._init_cmds):
for i, cmd in enumerate(cmdlist):
cmdlist[i] = pin_resolver.update_command(cmd)
logging.info("command: %s", cmdlist[i])
# Calculate config CRC
encoded_config = '\n'.join(self._config_cmds).encode()
config_crc = zlib.crc32(encoded_config) & 0xffffffff
Expand Down Expand Up @@ -770,30 +800,27 @@ def _log_info(self):
def recon_mcu(self):
res = self._mcu_identify()
if not res:
return
return False
self.reset_to_initial_state()

self.non_critical_disconnected = False
self._connect()
self._reactor.update_timer(
self.non_critical_recon_timer, self._reactor.NEVER
)
self._reactor.unregister_timer(self.non_critical_recon_timer)
self.last_noncrit_recon_eventtime = None
logging.info("mcu: %s reconnected", self._name)
self._printer.send_event(self._non_critical_reconnect_event_name)
return True

def reset_to_initial_state(self):
self._oid_count = 0
self._config_cmds = []
self._restart_cmds = []
self._init_cmds = []
if self._cached_init_state:
self._oid_count = self._oid_count_post_inits
self._config_cmds = self._config_cmds_post_inits.copy()
self._init_cmds = self._init_cmds_post_inits.copy()
self._restart_cmds = self._restart_cmds_post_inits.copy()
self._reserved_move_slots = 0
self._stepqueues = []
self._steppersync = None

def _connect(self):
if self._non_critical_disconnected:
self.non_critical_recon_timer = self._reactor.register_timer(
self.non_critical_recon_event, self._reactor.NOW + self.reconnect_interval
if self.non_critical_disconnected:
self._reactor.update_timer(
self.non_critical_recon_timer,
self._reactor.NOW + self.reconnect_interval,
)
return
config_params = self._send_get_config()
Expand Down Expand Up @@ -829,15 +856,17 @@ def _connect(self):
logging.info(move_msg)
log_info = self._log_info() + "\n" + move_msg
self._printer.set_rollover_info(self._name, log_info, log=False)

def _check_serial_exists(self):
rts = self._restart_method != "cheetah"
return self._serial.check_connect(self._serialport, self._baud, rts)
return self._serial.check_connect(self._serialport, self._baud, rts)

def _mcu_identify(self):
if self.is_non_critical and not self._check_serial_exists():
self._non_critical_disconnected = True
self.non_critical_disconnected = True
return False
else:
self._non_critical_disconnected = False
self.non_critical_disconnected = False
if self.is_fileoutput():
self._connect_file()
else:
Expand Down Expand Up @@ -937,6 +966,13 @@ def get_printer(self):
return self._printer
def get_name(self):
return self._name

def get_non_critical_reconnect_event_name(self):
return self._non_critical_reconnect_event_name

def get_non_critical_disconnect_event_name(self):
return self._non_critical_disconnect_event_name

def register_response(self, cb, msg, oid=None):
self._serial.register_response(cb, msg, oid)
def alloc_command_queue(self):
Expand Down Expand Up @@ -1009,7 +1045,7 @@ def _restart_rpi_usb(self):
self._reactor.pause(self._reactor.monotonic() + 2.)
chelper.run_hub_ctrl(1)
def _firmware_restart(self, force=False):
if self._is_mcu_bridge and not force:
if (self._is_mcu_bridge and not force) or self.non_critical_disconnected:
return
if self._restart_method == 'rpi_usb':
self._restart_rpi_usb()
Expand Down Expand Up @@ -1051,10 +1087,10 @@ def check_active(self, print_time, eventtime):
if (self._clocksync.is_active() or self.is_fileoutput()
or self._is_timeout):
return
self._is_timeout = True
if self.is_non_critical:
self.handle_non_critical_disconnect()
return
self._is_timeout = True
logging.info("Timeout with MCU '%s' (eventtime=%f)",
self._name, eventtime)
self._printer.invoke_shutdown("Lost communication with MCU '%s'" % (
Expand Down
Loading

0 comments on commit e201ed3

Please sign in to comment.