2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# Helper code for communicating with TMC stepper drivers via UART
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# Copyright (C) 2018-2019  Kevin O'Connor <kevin@koconnor.net>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# This file may be distributed under the terms of the GNU GPLv3 license.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import logging
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								######################################################################
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# TMC uart analog mux support
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								######################################################################
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class MCU_analog_mux:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, mcu, cmd_queue, select_pins_desc):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.mcu = mcu
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.cmd_queue = cmd_queue
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ppins = mcu.get_printer().lookup_object("pins")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        select_pin_params = [ppins.lookup_pin(spd, can_invert=True)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                             for spd in select_pins_desc.split(',')]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.oids = [self.mcu.create_oid() for pp in select_pin_params]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.pins = [pp['pin'] for pp in select_pin_params]
							 | 
						
					
						
							
								
									
										
										
										
											2019-10-24 22:00:58 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.pin_values = tuple([-1 for pp in select_pin_params])
							 | 
						
					
						
							
								
									
										
										
										
											2019-10-26 11:33:30 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        for oid, pin in zip(self.oids, self.pins):
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.mcu.add_config_cmd("config_digital_out oid=%d pin=%s"
							 | 
						
					
						
							
								
									
										
										
										
											2019-10-26 11:33:30 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                    " value=0 default_value=0 max_duration=0"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                    % (oid, pin))
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.update_pin_cmd = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.mcu.register_config_callback(self.build_config)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def build_config(self):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.update_pin_cmd = self.mcu.lookup_command(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            "update_digital_out oid=%c value=%c", cq=self.cmd_queue)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def get_instance_id(self, select_pins_desc):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ppins = self.mcu.get_printer().lookup_object("pins")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        select_pin_params = [ppins.parse_pin(spd, can_invert=True)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                             for spd in select_pins_desc.split(',')]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for pin_params in select_pin_params:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if pin_params['chip'] != self.mcu:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                raise self.mcu.get_printer().config_error(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    "TMC mux pins must be on the same mcu")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pins = [pp['pin'] for pp in select_pin_params]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if pins != self.pins:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            raise self.mcu.get_printer().config_error(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                "All TMC mux instances must use identical pins")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return tuple([not pp['invert'] for pp in select_pin_params])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def activate(self, instance_id):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for oid, old, new in zip(self.oids, self.pin_values, instance_id):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if old != new:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                self.update_pin_cmd.send([oid, new])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.pin_values = instance_id
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								######################################################################
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-21 09:39:07 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								# TMC uart communication
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								######################################################################
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-12 20:51:11 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								# Share mutexes so only one active tmc_uart command on a single mcu at
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# a time. This helps limit cpu usage on slower micro-controllers.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class PrinterTMCUartMutexes:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def __init__(self):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.mcu_to_mutex = {}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def lookup_tmc_uart_mutex(mcu):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    printer = mcu.get_printer()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pmutexes = printer.lookup_object('tmc_uart', None)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if pmutexes is None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pmutexes = PrinterTMCUartMutexes()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        printer.add_object('tmc_uart', pmutexes)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    mutex = pmutexes.mcu_to_mutex.get(mcu)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if mutex is None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        mutex = printer.get_reactor().mutex()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pmutexes.mcu_to_mutex[mcu] = mutex
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return mutex
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-27 10:58:01 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								TMC_BAUD_RATE = 9000
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# Code for sending messages on a TMC uart
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class MCU_TMC_uart_bitbang:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, rx_pin_params, tx_pin_params, select_pins_desc):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.mcu = rx_pin_params['chip']
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-12 20:51:11 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.mutex = lookup_tmc_uart_mutex(self.mcu)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.pullup = rx_pin_params['pullup']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.rx_pin = rx_pin_params['pin']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.tx_pin = tx_pin_params['pin']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.oid = self.mcu.create_oid()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.cmd_queue = self.mcu.alloc_command_queue()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.analog_mux = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if select_pins_desc is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.analog_mux = MCU_analog_mux(self.mcu, self.cmd_queue,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                             select_pins_desc)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.instances = {}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.tmcuart_send_cmd = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.mcu.register_config_callback(self.build_config)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def build_config(self):
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-27 10:58:01 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        bit_ticks = self.mcu.seconds_to_clock(1. / TMC_BAUD_RATE)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.mcu.add_config_cmd(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            "config_tmcuart oid=%d rx_pin=%s pull_up=%d tx_pin=%s bit_time=%d"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            % (self.oid, self.rx_pin, self.pullup, self.tx_pin, bit_ticks))
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-19 16:46:06 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.tmcuart_send_cmd = self.mcu.lookup_query_command(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            "tmcuart_send oid=%c write=%*s read=%c",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            "tmcuart_response oid=%c read=%*s", oid=self.oid,
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-11 21:39:27 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            cq=self.cmd_queue, is_async=True)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def register_instance(self, rx_pin_params, tx_pin_params,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                          select_pins_desc, addr):
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (rx_pin_params['pin'] != self.rx_pin
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            or tx_pin_params['pin'] != self.tx_pin
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            or (select_pins_desc is None) != (self.analog_mux is None)):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            raise self.mcu.get_printer().config_error(
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                "Shared TMC uarts must use the same pins")
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        instance_id = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if self.analog_mux is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            instance_id = self.analog_mux.get_instance_id(select_pins_desc)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if (instance_id, addr) in self.instances:
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            raise self.mcu.get_printer().config_error(
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                "Shared TMC uarts need unique address or select_pins polarity")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.instances[(instance_id, addr)] = True
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return instance_id
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _calc_crc8(self, data):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Generate a CRC8-ATM value for a bytearray
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        crc = 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for b in data:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            for i in range(8):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if (crc >> 7) ^ (b & 0x01):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    crc = (crc << 1) ^ 0x07
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    crc = (crc << 1)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                crc &= 0xff
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                b >>= 1
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return crc
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _add_serial_bits(self, data):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Add serial start and stop bits to a message in a bytearray
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        out = 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pos = 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for d in data:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            b = (d << 1) | 0x200
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            out |= (b << pos)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pos += 10
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        res = bytearray()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for i in range((pos+7)//8):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            res.append((out >> (i*8)) & 0xff)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return res
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _encode_read(self, sync, addr, reg):
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-21 09:39:07 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Generate a uart read register message
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        msg = bytearray([sync, addr, reg])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        msg.append(self._calc_crc8(msg))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return self._add_serial_bits(msg)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _encode_write(self, sync, addr, reg, val):
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-21 09:39:07 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Generate a uart write register message
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        msg = bytearray([sync, addr, reg, (val >> 24) & 0xff,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                         (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        msg.append(self._calc_crc8(msg))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return self._add_serial_bits(msg)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _decode_read(self, reg, data):
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-21 09:39:07 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Extract a uart read response message
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if len(data) != 10:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Convert data into a long integer for easy manipulation
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        mval = pos = 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for d in bytearray(data):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            mval |= d << pos
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pos += 8
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Extract register value
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        val = ((((mval >> 31) & 0xff) << 24) | (((mval >> 41) & 0xff) << 16)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               | (((mval >> 51) & 0xff) << 8) | ((mval >> 61) & 0xff))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Verify start/stop bits and crc
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        encoded_data = self._encode_write(0x05, 0xff, reg, val)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if data != encoded_data:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return val
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def reg_read(self, instance_id, addr, reg):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if self.analog_mux is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.analog_mux.activate(instance_id)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        msg = self._encode_read(0xf5, addr, reg)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-19 16:46:06 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        params = self.tmcuart_send_cmd.send([self.oid, msg, 10])
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return self._decode_read(reg, params['read'])
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-25 18:15:17 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def reg_write(self, instance_id, addr, reg, val, print_time=None):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        minclock = 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if print_time is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            minclock = self.mcu.print_time_to_clock(print_time)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if self.analog_mux is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.analog_mux.activate(instance_id)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        msg = self._encode_write(0xf5, addr, reg | 0x80, val)
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-19 16:46:06 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.tmcuart_send_cmd.send([self.oid, msg, 0], minclock=minclock)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# Lookup a (possibly shared) tmc uart
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def lookup_tmc_uart_bitbang(config, max_addr):
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ppins = config.get_printer().lookup_object("pins")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    rx_pin_params = ppins.lookup_pin(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        config.get('uart_pin'), can_pullup=True, share_type="tmc_uart_rx")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    tx_pin_desc = config.get('tx_pin', None)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if tx_pin_desc is None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        tx_pin_params = rx_pin_params
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        tx_pin_params = ppins.lookup_pin(tx_pin_desc, share_type="tmc_uart_tx")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if rx_pin_params['chip'] is not tx_pin_params['chip']:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        raise ppins.error("TMC uart rx and tx pins must be on the same mcu")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    select_pins_desc = config.get('select_pins', None)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 13:13:27 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    addr = config.getint('uart_address', 0, minval=0, maxval=max_addr)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    mcu_uart = rx_pin_params.get('class')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if mcu_uart is None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        mcu_uart = MCU_TMC_uart_bitbang(rx_pin_params, tx_pin_params,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                        select_pins_desc)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        rx_pin_params['class'] = mcu_uart
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    instance_id = mcu_uart.register_instance(rx_pin_params, tx_pin_params,
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                             select_pins_desc, addr)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return instance_id, addr, mcu_uart
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# Helper code for communicating via TMC uart
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class MCU_TMC_uart:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, config, name_to_reg, fields, max_addr=0):
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.printer = config.get_printer()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.name = config.get_name().split()[-1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.name_to_reg = name_to_reg
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.fields = fields
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.ifcnt = None
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-31 12:08:11 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.instance_id, self.addr, self.mcu_uart = lookup_tmc_uart_bitbang(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            config, max_addr)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-10 09:55:52 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.mutex = self.mcu_uart.mutex
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def get_fields(self):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return self.fields
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-10 09:55:52 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def _do_get_register(self, reg_name):
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        reg = self.name_to_reg[reg_name]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if self.printer.get_start_args().get('debugoutput') is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for retry in range(5):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            val = self.mcu_uart.reg_read(self.instance_id, self.addr, reg)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if val is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                return val
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        raise self.printer.command_error(
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-21 09:39:07 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            "Unable to read tmc uart '%s' register %s" % (self.name, reg_name))
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-10 09:55:52 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def get_register(self, reg_name):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        with self.mutex:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return self._do_get_register(reg_name)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-25 18:27:59 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def set_register(self, reg_name, val, print_time=None):
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        reg = self.name_to_reg[reg_name]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if self.printer.get_start_args().get('debugoutput') is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-10 09:55:52 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        with self.mutex:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            for retry in range(5):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                ifcnt = self.ifcnt
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if ifcnt is None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    self.ifcnt = ifcnt = self._do_get_register("IFCNT")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                self.mcu_uart.reg_write(self.instance_id, self.addr, reg, val,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                        print_time)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                self.ifcnt = self._do_get_register("IFCNT")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if self.ifcnt == (ifcnt + 1) & 0xff:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    return
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-18 18:06:05 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        raise self.printer.command_error(
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-21 09:39:07 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            "Unable to write tmc uart '%s' register %s" % (self.name, reg_name))
							 |