serialhdl: Support prepending a warn_prefix to error and log messages

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2021-06-09 14:46:56 -04:00
parent f00281d1e6
commit 31fcd491fd
3 changed files with 55 additions and 41 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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: