aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/mcu.py
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/mcu.py')
-rw-r--r--klippy/mcu.py161
1 files changed, 88 insertions, 73 deletions
diff --git a/klippy/mcu.py b/klippy/mcu.py
index ce1fee4c..fbd0b5a4 100644
--- a/klippy/mcu.py
+++ b/klippy/mcu.py
@@ -1,6 +1,6 @@
# Interface to Klipper micro-controller code
#
-# Copyright (C) 2016-2021 Kevin O'Connor <kevin@koconnor.net>
+# Copyright (C) 2016-2023 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import sys, os, zlib, logging, math
@@ -9,6 +9,90 @@ import serialhdl, msgproto, pins, chelper, clocksync
class error(Exception):
pass
+
+######################################################################
+# Command transmit helper classes
+######################################################################
+
+# Class to retry sending of a query command until a given response is received
+class RetryAsyncCommand:
+ TIMEOUT_TIME = 5.0
+ RETRY_TIME = 0.500
+ 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)
+ def handle_callback(self, params):
+ 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, cmds, cmd_queue, minclock=0, reqclock=0):
+ cmd, = cmds
+ self.serial.raw_send_wait_ack(cmd, minclock, reqclock, cmd_queue)
+ first_query_time = query_time = self.reactor.monotonic()
+ while 1:
+ params = self.completion.wait(query_time + self.RETRY_TIME)
+ if params is not None:
+ self.serial.register_response(None, self.name, self.oid)
+ return params
+ query_time = self.reactor.monotonic()
+ if query_time > first_query_time + self.TIMEOUT_TIME:
+ self.serial.register_response(None, self.name, self.oid)
+ raise serialhdl.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, is_async=False, error=serialhdl.error):
+ 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._error = error
+ self._xmit_helper = serialhdl.SerialRetryCommand
+ if is_async:
+ self._xmit_helper = RetryAsyncCommand
+ if cmd_queue is None:
+ cmd_queue = serial.get_default_command_queue()
+ self._cmd_queue = cmd_queue
+ def _do_send(self, cmds, minclock, reqclock):
+ xh = self._xmit_helper(self._serial, self._response, self._oid)
+ reqclock = max(minclock, reqclock)
+ try:
+ return xh.get_response(cmds, self._cmd_queue, minclock, reqclock)
+ except serialhdl.error as e:
+ raise self._error(str(e))
+ def send(self, data=(), minclock=0, reqclock=0):
+ return self._do_send([self._cmd.encode(data)], minclock, reqclock)
+ def send_with_preface(self, preface_cmd, preface_data=(), data=(),
+ minclock=0, reqclock=0):
+ cmds = [preface_cmd._cmd.encode(preface_data), self._cmd.encode(data)]
+ return self._do_send(cmds, minclock, reqclock)
+
+# Wrapper around command sending
+class CommandWrapper:
+ def __init__(self, serial, msgformat, cmd_queue=None):
+ self._serial = serial
+ 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)
+
+
+######################################################################
+# Wrapper classes for MCU pins
+######################################################################
+
class MCU_trsync:
REASON_ENDSTOP_HIT = 1
REASON_COMMS_TIMEOUT = 2
@@ -456,79 +540,10 @@ class MCU_adc:
if self._callback is not None:
self._callback(last_read_time, last_value)
-# Class to retry sending of a query command until a given response is received
-class RetryAsyncCommand:
- TIMEOUT_TIME = 5.0
- RETRY_TIME = 0.500
- 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)
- def handle_callback(self, params):
- 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, cmds, cmd_queue, minclock=0, reqclock=0):
- cmd, = cmds
- self.serial.raw_send_wait_ack(cmd, minclock, reqclock, cmd_queue)
- first_query_time = query_time = self.reactor.monotonic()
- while 1:
- params = self.completion.wait(query_time + self.RETRY_TIME)
- if params is not None:
- self.serial.register_response(None, self.name, self.oid)
- return params
- query_time = self.reactor.monotonic()
- if query_time > first_query_time + self.TIMEOUT_TIME:
- self.serial.register_response(None, self.name, self.oid)
- raise serialhdl.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, is_async=False, error=serialhdl.error):
- 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._error = error
- self._xmit_helper = serialhdl.SerialRetryCommand
- if is_async:
- self._xmit_helper = RetryAsyncCommand
- if cmd_queue is None:
- cmd_queue = serial.get_default_command_queue()
- self._cmd_queue = cmd_queue
- def _do_send(self, cmds, minclock, reqclock):
- xh = self._xmit_helper(self._serial, self._response, self._oid)
- reqclock = max(minclock, reqclock)
- try:
- return xh.get_response(cmds, self._cmd_queue, minclock, reqclock)
- except serialhdl.error as e:
- raise self._error(str(e))
- def send(self, data=(), minclock=0, reqclock=0):
- return self._do_send([self._cmd.encode(data)], minclock, reqclock)
- def send_with_preface(self, preface_cmd, preface_data=(), data=(),
- minclock=0, reqclock=0):
- cmds = [preface_cmd._cmd.encode(preface_data), self._cmd.encode(data)]
- return self._do_send(cmds, minclock, reqclock)
-
-# Wrapper around command sending
-class CommandWrapper:
- def __init__(self, serial, msgformat, cmd_queue=None):
- self._serial = serial
- 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)
+######################################################################
+# Main MCU class
+######################################################################
class MCU:
error = error