From 245917bf034804acfa3039ac308c7d4308e79e86 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Wed, 19 Feb 2020 16:46:06 -0500 Subject: [PATCH] mcu: Introduce new lookup_query_command() command wrapper Use new mcu.lookup_query_command() for all commands that query information from the micro-controller. Signed-off-by: Kevin O'Connor --- klippy/extras/bus.py | 18 ++++---- klippy/extras/tmc_uart.py | 13 +++--- klippy/mcu.py | 88 +++++++++++++++++++++++---------------- klippy/serialhdl.py | 2 + klippy/stepper.py | 8 ++-- 5 files changed, 73 insertions(+), 56 deletions(-) diff --git a/klippy/extras/bus.py b/klippy/extras/bus.py index 0b50efc7..7c6ae440 100644 --- a/klippy/extras/bus.py +++ b/klippy/extras/bus.py @@ -79,8 +79,10 @@ class MCU_SPI: self.mcu.add_config_cmd(self.config_fmt) self.spi_send_cmd = self.mcu.lookup_command( "spi_send oid=%c data=%*s", cq=self.cmd_queue) - self.spi_transfer_cmd = self.mcu.lookup_command( - "spi_transfer oid=%c data=%*s", cq=self.cmd_queue) + self.spi_transfer_cmd = self.mcu.lookup_query_command( + "spi_transfer oid=%c data=%*s", + "spi_transfer_response oid=%c response=%*s", oid=self.oid, + cq=self.cmd_queue) def spi_send(self, data, minclock=0, reqclock=0): if self.spi_send_cmd is None: # Send setup message via mcu initialization @@ -91,8 +93,7 @@ class MCU_SPI: self.spi_send_cmd.send([self.oid, data], minclock=minclock, reqclock=reqclock) def spi_transfer(self, data): - return self.spi_transfer_cmd.send_with_response( - [self.oid, data], 'spi_transfer_response', self.oid) + return self.spi_transfer_cmd.send([self.oid, data]) # Helper to setup an spi bus from settings in a config section def MCU_SPI_from_config(config, mode, pin_option="cs_pin", @@ -155,8 +156,10 @@ class MCU_I2C: self.mcu.add_config_cmd(self.config_fmt % (bus,)) self.i2c_write_cmd = self.mcu.lookup_command( "i2c_write oid=%c data=%*s", cq=self.cmd_queue) - self.i2c_read_cmd = self.mcu.lookup_command( - "i2c_read oid=%c reg=%*s read_len=%u", cq=self.cmd_queue) + self.i2c_read_cmd = self.mcu.lookup_query_command( + "i2c_read oid=%c reg=%*s read_len=%u", + "i2c_read_response oid=%c response=%*s", oid=self.oid, + cq=self.cmd_queue) self.i2c_modify_bits_cmd = self.mcu.lookup_command( "i2c_modify_bits oid=%c reg=%*s clear_set_bits=%*s", cq=self.cmd_queue) @@ -170,8 +173,7 @@ class MCU_I2C: self.i2c_write_cmd.send([self.oid, data], minclock=minclock, reqclock=reqclock) def i2c_read(self, write, read_len): - return self.i2c_read_cmd.send_with_response( - [self.oid, write, read_len], 'i2c_read_response', self.oid) + return self.i2c_read_cmd.send([self.oid, write, read_len]) def i2c_modify_bits(self, reg, clear_bits, set_bits, minclock=0, reqclock=0): clearset = clear_bits + set_bits diff --git a/klippy/extras/tmc_uart.py b/klippy/extras/tmc_uart.py index 7191c9b5..edcaab97 100644 --- a/klippy/extras/tmc_uart.py +++ b/klippy/extras/tmc_uart.py @@ -75,8 +75,10 @@ class MCU_TMC_uart_bitbang: 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)) - self.tmcuart_send_cmd = self.mcu.lookup_command( - "tmcuart_send oid=%c write=%*s read=%c", cq=self.cmd_queue) + 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, + cq=self.cmd_queue, async=True) def register_instance(self, rx_pin_params, tx_pin_params, select_pins_desc, addr): if (rx_pin_params['pin'] != self.rx_pin @@ -148,8 +150,7 @@ class MCU_TMC_uart_bitbang: if self.analog_mux is not None: self.analog_mux.activate(instance_id) msg = self._encode_read(0xf5, addr, reg) - params = self.tmcuart_send_cmd.send_with_async_response( - [self.oid, msg, 10], 'tmcuart_response', self.oid) + params = self.tmcuart_send_cmd.send([self.oid, msg, 10]) return self._decode_read(reg, params['read']) def reg_write(self, instance_id, addr, reg, val, print_time=None): minclock = 0 @@ -158,9 +159,7 @@ class MCU_TMC_uart_bitbang: if self.analog_mux is not None: self.analog_mux.activate(instance_id) msg = self._encode_write(0xf5, addr, reg | 0x80, val) - self.tmcuart_send_cmd.send_with_async_response( - [self.oid, msg, 0], 'tmcuart_response', self.oid, - minclock=minclock) + self.tmcuart_send_cmd.send([self.oid, msg, 0], minclock=minclock) # Lookup a (possibly shared) tmc uart def lookup_tmc_uart_bitbang(config, max_addr): diff --git a/klippy/mcu.py b/klippy/mcu.py index 4be952f2..4064b8e0 100644 --- a/klippy/mcu.py +++ b/klippy/mcu.py @@ -1,6 +1,6 @@ # Interface to Klipper micro-controller code # -# Copyright (C) 2016-2019 Kevin O'Connor +# Copyright (C) 2016-2020 Kevin O'Connor # # This file may be distributed under the terms of the GNU GPLv3 license. import sys, os, zlib, logging, math @@ -18,7 +18,7 @@ class MCU_endstop: self._pullup = pin_params['pullup'] self._invert = pin_params['invert'] self._reactor = mcu.get_printer().get_reactor() - self._oid = self._home_cmd = self._query_cmd = None + self._oid = self._home_cmd = self._requery_cmd = self._query_cmd = None self._mcu.register_config_callback(self._build_config) self._min_query_time = self._last_sent_time = 0. self._next_query_print_time = self._end_home_time = 0. @@ -49,8 +49,12 @@ class MCU_endstop: self._home_cmd = self._mcu.lookup_command( "endstop_home oid=%c clock=%u sample_ticks=%u sample_count=%c" " rest_ticks=%u pin_value=%c", cq=cmd_queue) - self._query_cmd = self._mcu.lookup_command( + self._requery_cmd = self._mcu.lookup_command( "endstop_query_state oid=%c", cq=cmd_queue) + self._query_cmd = self._mcu.lookup_query_command( + "endstop_query_state oid=%c", + "endstop_state oid=%c homing=%c pin_value=%c", oid=self._oid, + cq=cmd_queue) def home_start(self, print_time, sample_time, sample_count, rest_time, triggered=True): clock = self._mcu.print_time_to_clock(print_time) @@ -94,7 +98,7 @@ class MCU_endstop: est_print_time = self._mcu.estimated_print_time(eventtime) if est_print_time >= self._next_query_print_time: self._next_query_print_time = est_print_time + self.RETRY_QUERY - self._query_cmd.send([self._oid]) + self._requery_cmd.send([self._oid]) def home_wait(self, home_end_time): self._home_end_time = home_end_time did_trigger = self._home_completion.wait() @@ -109,8 +113,7 @@ class MCU_endstop: clock = self._mcu.print_time_to_clock(print_time) if self._mcu.is_fileoutput(): return 0 - params = self._query_cmd.send_with_response( - [self._oid], "endstop_state", self._oid, minclock=clock) + params = self._query_cmd.send([self._oid], minclock=clock) return params['pin_value'] ^ self._invert class MCU_digital_out: @@ -305,11 +308,11 @@ class MCU_adc: class RetryAsyncCommand: TIMEOUT_TIME = 5.0 RETRY_TIME = 0.500 - def __init__(self, mcu, serial, name, oid=None): - self.reactor = mcu.get_printer().get_reactor() + def __init__(self, serial, name, oid=None): self.serial = serial self.name = name self.oid = oid + self.reactor = serial.get_reactor() self.completion = self.reactor.completion() self.min_query_time = self.reactor.monotonic() self.serial.register_response(self.handle_callback, name, oid) @@ -317,10 +320,10 @@ class RetryAsyncCommand: if params['#sent_time'] >= self.min_query_time: self.min_query_time = self.reactor.NEVER self.reactor.async_complete(self.completion, params) - def get_response(self, cmd, cmd_queue, minclock=0, minsystime=0.): - first_query_time = query_time = max(self.min_query_time, minsystime) + def get_response(self, cmd, cmd_queue, minclock=0): + self.serial.raw_send_wait_ack(cmd, minclock, minclock, cmd_queue) + first_query_time = query_time = self.reactor.monotonic() while 1: - self.serial.raw_send(cmd, minclock, minclock, cmd_queue) params = self.completion.wait(query_time + self.RETRY_TIME) if params is not None: self.serial.register_response(None, self.name, self.oid) @@ -329,34 +332,42 @@ class RetryAsyncCommand: if query_time > first_query_time + self.TIMEOUT_TIME: self.serial.register_response(None, self.name, self.oid) raise error("Timeout on wait for '%s' response" % (self.name,)) + self.serial.raw_send(cmd, minclock, minclock, cmd_queue) + +# Wrapper around query commands +class CommandQueryWrapper: + def __init__(self, serial, msgformat, respformat, oid=None, + cmd_queue=None, async=False): + self._serial = serial + self._cmd = serial.get_msgparser().lookup_command(msgformat) + serial.get_msgparser().lookup_command(respformat) + self._response = respformat.split()[0] + self._oid = oid + self._xmit_helper = serialhdl.SerialRetryCommand + if async: + self._xmit_helper = RetryAsyncCommand + if cmd_queue is None: + cmd_queue = serial.get_default_command_queue() + self._cmd_queue = cmd_queue + def send(self, data=(), minclock=0): + cmd = self._cmd.encode(data) + xh = self._xmit_helper(self._serial, self._response, self._oid) + try: + return xh.get_response(cmd, self._cmd_queue, minclock=minclock) + except serialhdl.error as e: + raise error(str(e)) # Wrapper around command sending class CommandWrapper: - def __init__(self, mcu, serial, clocksync, cmd, cmd_queue): - self._mcu = mcu + def __init__(self, serial, msgformat, cmd_queue=None): self._serial = serial - self._clocksync = clocksync - self._cmd = cmd + self._cmd = serial.get_msgparser().lookup_command(msgformat) + if cmd_queue is None: + cmd_queue = serial.get_default_command_queue() self._cmd_queue = cmd_queue def send(self, data=(), minclock=0, reqclock=0): cmd = self._cmd.encode(data) self._serial.raw_send(cmd, minclock, reqclock, self._cmd_queue) - def send_with_response(self, data=(), response=None, response_oid=None, - minclock=0): - cmd = self._cmd.encode(data) - src = serialhdl.SerialRetryCommand(self._serial, response, response_oid) - try: - return src.get_response(cmd, self._cmd_queue, minclock=minclock) - except serialhdl.error as e: - raise error(str(e)) - def send_with_async_response(self, data=(), - response=None, response_oid=None, minclock=0): - minsystime = 0. - if minclock: - minsystime = self._clocksync.estimate_clock_systime(minclock) - cmd = self._cmd.encode(data) - src = RetryAsyncCommand(self._mcu, self._serial, response, response_oid) - return src.get_response(cmd, self._cmd_queue, minclock, minsystime) class MCU: error = error @@ -505,10 +516,12 @@ class MCU: for c in self._init_cmds: self._serial.send(c) def _send_get_config(self): - get_config_cmd = self.lookup_command("get_config") + get_config_cmd = self.lookup_query_command( + "get_config", + "config is_config=%c crc=%u move_count=%hu is_shutdown=%c") if self.is_fileoutput(): return { 'is_config': 0, 'move_count': 500, 'crc': 0 } - config_params = get_config_cmd.send_with_response(response='config') + config_params = get_config_cmd.send() if self._is_shutdown: raise error("MCU '%s' error during config: %s" % ( self._name, self._shutdown_msg)) @@ -624,10 +637,11 @@ class MCU: def alloc_command_queue(self): return self._serial.alloc_command_queue() def lookup_command(self, msgformat, cq=None): - if cq is None: - cq = self._serial.get_default_command_queue() - cmd = self._serial.get_msgparser().lookup_command(msgformat) - return CommandWrapper(self, self._serial, self._clocksync, cmd, cq) + return CommandWrapper(self._serial, msgformat, cq) + def lookup_query_command(self, msgformat, respformat, oid=None, + cq=None, async=False): + return CommandQueryWrapper(self._serial, msgformat, respformat, oid, + cq, async) def try_lookup_command(self, msgformat): try: return self.lookup_command(msgformat) diff --git a/klippy/serialhdl.py b/klippy/serialhdl.py index c7c6e4d2..98bef943 100644 --- a/klippy/serialhdl.py +++ b/klippy/serialhdl.py @@ -145,6 +145,8 @@ class SerialReader: self.ffi_lib.serialqueue_get_stats( self.serialqueue, self.stats_buf, len(self.stats_buf)) return self.ffi_main.string(self.stats_buf) + def get_reactor(self): + return self.reactor def get_msgparser(self): return self.msgparser def get_default_command_queue(self): diff --git a/klippy/stepper.py b/klippy/stepper.py index 8b3f943b..1ec59974 100644 --- a/klippy/stepper.py +++ b/klippy/stepper.py @@ -84,8 +84,9 @@ class MCU_stepper: "set_next_step_dir oid=%c dir=%c") self._reset_cmd_id = self._mcu.lookup_command_id( "reset_step_clock oid=%c clock=%u") - self._get_position_cmd = self._mcu.lookup_command( - "stepper_get_position oid=%c") + self._get_position_cmd = self._mcu.lookup_query_command( + "stepper_get_position oid=%c", + "stepper_position oid=%c pos=%i", oid=self._oid) self._ffi_lib.stepcompress_fill( self._stepqueue, self._mcu.seconds_to_clock(max_error), self._invert_dir, step_cmd_id, dir_cmd_id) @@ -134,8 +135,7 @@ class MCU_stepper: raise error("Internal error in stepcompress") if not did_trigger or self._mcu.is_fileoutput(): return - params = self._get_position_cmd.send_with_response( - [self._oid], response='stepper_position', response_oid=self._oid) + params = self._get_position_cmd.send([self._oid]) mcu_pos_dist = params['pos'] * self._step_dist if self._invert_dir: mcu_pos_dist = -mcu_pos_dist