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