From 31fcd491fd9fd99f81599558b5256cfaaa078da0 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Wed, 9 Jun 2021 14:46:56 -0400 Subject: [PATCH] serialhdl: Support prepending a warn_prefix to error and log messages Signed-off-by: Kevin O'Connor --- klippy/mcu.py | 3 ++- klippy/msgproto.py | 33 +++++++++++++------------ klippy/serialhdl.py | 60 ++++++++++++++++++++++++++------------------- 3 files changed, 55 insertions(+), 41 deletions(-) diff --git a/klippy/mcu.py b/klippy/mcu.py index 6fb66247..f03fd16d 100644 --- a/klippy/mcu.py +++ b/klippy/mcu.py @@ -415,7 +415,8 @@ class MCU: if self._name.startswith('mcu '): self._name = self._name[4:] # Serial port - self._serial = serialhdl.SerialReader(self._reactor) + wp = "mcu '%s': " % (self._name) + self._serial = serialhdl.SerialReader(self._reactor, warn_prefix=wp) self._baud = 0 self._canbus_iface = None canbus_uuid = config.get('canbus_uuid', None) diff --git a/klippy/msgproto.py b/klippy/msgproto.py index c3c0cda9..cdecd8e7 100644 --- a/klippy/msgproto.py +++ b/klippy/msgproto.py @@ -105,8 +105,8 @@ class Enumeration: def encode(self, out, v): tv = self.enums.get(v) if tv is None: - raise error("Unknown value '%s' in enumeration '%s'" % ( - v, self.enum_name)) + raise error("Unknown value '%s' in enumeration '%s'" + % (v, self.enum_name)) self.pt.encode(out, tv) def parse(self, s, pos): v, pos = self.pt.parse(s, pos) @@ -221,7 +221,8 @@ class UnknownFormat: class MessageParser: error = error - def __init__(self): + def __init__(self, warn_prefix=""): + self.warn_prefix = warn_prefix self.unknown = UnknownFormat() self.enumerations = {} self.messages = [] @@ -231,6 +232,8 @@ class MessageParser: self.version = self.build_versions = "" self.raw_identify_data = "" self._init_messages(DefaultMessages) + def _error(self, msg, *params): + raise error(self.warn_prefix + (msg % params)) def check_packet(self, s): if len(s) < MESSAGE_MIN: return 0 @@ -277,7 +280,7 @@ class MessageParser: mid = self.messages_by_id.get(msgid, self.unknown) params, pos = mid.parse(s, MESSAGE_HEADER_SIZE) if pos != len(s)-MESSAGE_TRAILER_SIZE: - raise error("Extra data at end of message") + self._error("Extra data at end of message") params['#name'] = mid.name return params def encode(self, seq, cmd): @@ -302,10 +305,10 @@ class MessageParser: msgname = parts[0] mp = self.messages_by_name.get(msgname) if mp is None: - raise error("Unknown command: %s" % (msgname,)) + self._error("Unknown command: %s", msgname) if msgformat != mp.msgformat: - raise error("Command format mismatch: %s vs %s" % ( - msgformat, mp.msgformat)) + self._error("Command format mismatch: %s vs %s", + msgformat, mp.msgformat) return mp def create_command(self, msg): parts = msg.strip().split() @@ -314,7 +317,7 @@ class MessageParser: msgname = parts[0] mp = self.messages_by_name.get(msgname) if mp is None: - raise error("Unknown command: %s" % (msgname,)) + self._error("Unknown command: %s", msgname) try: argparts = dict(arg.split('=', 1) for arg in parts[1:]) for name, value in argparts.items(): @@ -330,14 +333,14 @@ class MessageParser: raise except: #logging.exception("Unable to extract params") - raise error("Unable to extract params from: %s" % (msgname,)) + self._error("Unable to extract params from: %s", msgname) try: cmd = mp.encode_by_name(**argparts) except error as e: raise except: #logging.exception("Unable to encode") - raise error("Unable to encode: %s" % (msgname,)) + self._error("Unable to encode: %s", msgname) return cmd def fill_enumerations(self, enumerations): for add_name, add_enums in enumerations.items(): @@ -366,7 +369,7 @@ class MessageParser: msgtype = 'output' self.messages.append((msgtag, msgtype, msgformat)) if msgtag < -32 or msgtag > 95: - raise error("Multi-byte msgtag not supported") + self._error("Multi-byte msgtag not supported") msgid = msgtag & 0x7f if msgtype == 'output': self.messages_by_id[msgid] = OutputFormat(msgid, msgformat) @@ -396,7 +399,7 @@ class MessageParser: raise except Exception as e: logging.exception("process_identify error") - raise error("Error during identify: %s" % (str(e),)) + self._error("Error during identify: %s", str(e)) def get_version_info(self): return self.version, self.build_versions def get_messages(self): @@ -410,12 +413,12 @@ class MessageParser: if name not in self.config: if default is not self.sentinel: return default - raise error("Firmware constant '%s' not found" % (name,)) + self._error("Firmware constant '%s' not found", name) try: value = parser(self.config[name]) except: - raise error("Unable to parse firmware constant %s: %s" % ( - name, self.config[name])) + self._error("Unable to parse firmware constant %s: %s", + name, self.config[name]) return value def get_constant_float(self, name, default=sentinel): return self.get_constant(name, default, parser=float) diff --git a/klippy/serialhdl.py b/klippy/serialhdl.py index 9294b120..59482a41 100644 --- a/klippy/serialhdl.py +++ b/klippy/serialhdl.py @@ -13,11 +13,12 @@ class error(Exception): class SerialReader: BITS_PER_BYTE = 10. - def __init__(self, reactor): + def __init__(self, reactor, warn_prefix=""): self.reactor = reactor + self.warn_prefix = warn_prefix # Serial port self.serial_dev = None - self.msgparser = msgproto.MessageParser() + self.msgparser = msgproto.MessageParser(warn_prefix=warn_prefix) # C interface self.ffi_main, self.ffi_lib = chelper.get_ffi() self.serialqueue = None @@ -55,7 +56,10 @@ class SerialReader: hdl = self.handlers.get(hdl, self.handle_default) hdl(params) except: - logging.exception("Exception in serial callback") + logging.exception("%sException in serial callback", + self.warn_prefix) + def _error(self, msg, *params): + raise error(self.warn_prefix + (msg % params)) def _get_identify_data(self, eventtime): # Query the "data dictionary" from the micro-controller identify_data = "" @@ -64,7 +68,8 @@ class SerialReader: try: params = self.send_with_response(msg, 'identify_response') except error as e: - logging.exception("Wait for identify_response") + logging.exception("%sWait for identify_response", + self.warn_prefix) return None if params['offset'] == len(identify_data): msgdata = params['data'] @@ -84,10 +89,10 @@ class SerialReader: completion = self.reactor.register_callback(self._get_identify_data) identify_data = completion.wait(self.reactor.monotonic() + 5.) if identify_data is None: - logging.info("Timeout on connect") + logging.info("%sTimeout on connect", self.warn_prefix) self.disconnect() return False - msgparser = msgproto.MessageParser() + msgparser = msgproto.MessageParser(warn_prefix=self.warn_prefix) msgparser.process_identify(identify_data) self.msgparser = msgparser self.register_response(self.handle_unknown, '#unknown') @@ -112,7 +117,7 @@ class SerialReader: except ValueError: uuid = -1 if uuid < 0 or uuid > 0xffffffffffff: - raise error("Invalid CAN uuid") + self._error("Invalid CAN uuid") uuid = [(uuid >> (40 - i*8)) & 0xff for i in range(6)] CANBUS_ID_ADMIN = 0x3f0 CMD_SET_NODEID = 0x01 @@ -120,18 +125,19 @@ class SerialReader: set_id_msg = can.Message(arbitration_id=CANBUS_ID_ADMIN, data=set_id_cmd, is_extended_id=False) # Start connection attempt - logging.info("Starting CAN connect") + logging.info("%sStarting CAN connect", self.warn_prefix) start_time = self.reactor.monotonic() while 1: if self.reactor.monotonic() > start_time + 90.: - raise error("Unable to connect") + self._error("Unable to connect") try: bus = can.interface.Bus(channel=canbus_iface, can_filters=filters, bustype='socketcan') bus.send(set_id_msg) except can.CanError as e: - logging.warn("Unable to open CAN port: %s", e) + logging.warn("%sUnable to open CAN port: %s", + self.warn_prefix, e) self.reactor.pause(self.reactor.monotonic() + 5.) continue bus.close = bus.shutdown # XXX @@ -145,19 +151,21 @@ class SerialReader: if got_uuid == bytearray(uuid): break except: - logging.exception("Error in canbus_uuid check") - logging.info("Failed to match canbus_uuid - retrying..") + logging.exception("%sError in canbus_uuid check", + self.warn_prefix) + logging.info("%sFailed to match canbus_uuid - retrying..", + self.warn_prefix) self.disconnect() def connect_pipe(self, filename): - logging.info("Starting connect") + logging.info("%sStarting connect", self.warn_prefix) start_time = self.reactor.monotonic() while 1: if self.reactor.monotonic() > start_time + 90.: - raise error("Unable to connect") + self._error("Unable to connect") try: fd = os.open(filename, os.O_RDWR | os.O_NOCTTY) except OSError as e: - logging.warn("Unable to open port: %s", e) + logging.warn("%sUnable to open port: %s", self.warn_prefix, e) self.reactor.pause(self.reactor.monotonic() + 5.) continue serial_dev = os.fdopen(fd, 'rb+', 0) @@ -166,11 +174,11 @@ class SerialReader: break def connect_uart(self, serialport, baud, rts=True): # Initial connection - logging.info("Starting serial connect") + logging.info("%sStarting serial connect", self.warn_prefix) start_time = self.reactor.monotonic() while 1: if self.reactor.monotonic() > start_time + 90.: - raise error("Unable to connect") + self._error("Unable to connect") try: serial_dev = serial.Serial(baudrate=baud, timeout=0, exclusive=True) @@ -178,7 +186,8 @@ class SerialReader: serial_dev.rts = rts serial_dev.open() except (OSError, IOError, serial.SerialException) as e: - logging.warn("Unable to open serial port: %s", e) + logging.warn("%sUnable to open serial port: %s", + self.warn_prefix, e) self.reactor.pause(self.reactor.monotonic() + 5.) continue stk500v2_leave(serial_dev, self.reactor) @@ -238,7 +247,7 @@ class SerialReader: cmd, len(cmd), minclock, reqclock, nid) params = completion.wait() if params is None: - raise error("Serial connection closed") + self._error("Serial connection closed") return params def send(self, msg, minclock=0, reqclock=0): cmd = self.msgparser.create_command(msg) @@ -276,15 +285,16 @@ class SerialReader: return '\n'.join(out) # Default message handlers def _handle_unknown_init(self, params): - logging.debug("Unknown message %d (len %d) while identifying", - params['#msgid'], len(params['#msg'])) + logging.debug("%sUnknown message %d (len %d) while identifying", + self.warn_prefix, params['#msgid'], len(params['#msg'])) def handle_unknown(self, params): - logging.warn("Unknown message type %d: %s", - params['#msgid'], repr(params['#msg'])) + logging.warn("%sUnknown message type %d: %s", + self.warn_prefix, params['#msgid'], repr(params['#msg'])) def handle_output(self, params): - logging.info("%s: %s", params['#name'], params['#msg']) + logging.info("%s%s: %s", self.warn_prefix, + params['#name'], params['#msg']) def handle_default(self, params): - logging.warn("got %s", params) + logging.warn("%sgot %s", self.warn_prefix, params) # Class to send a query command and return the received response class SerialRetryCommand: