serialhdl: Update callers to decide serial fd type
Don't try to detect a "real serial port" in serialhdl.py. Instead, have the callers invoke either connect_uart(), connect_file(), or connect_pipe(). Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
bc2096f543
commit
9d3a3f3f30
|
@ -30,8 +30,10 @@ help_txt = """
|
||||||
re_eval = re.compile(r'\{(?P<eval>[^}]*)\}')
|
re_eval = re.compile(r'\{(?P<eval>[^}]*)\}')
|
||||||
|
|
||||||
class KeyboardReader:
|
class KeyboardReader:
|
||||||
def __init__(self, ser, reactor):
|
def __init__(self, reactor, serialport, baud):
|
||||||
self.ser = ser
|
self.serialport = serialport
|
||||||
|
self.baud = baud
|
||||||
|
self.ser = serialhdl.SerialReader(reactor)
|
||||||
self.reactor = reactor
|
self.reactor = reactor
|
||||||
self.start_time = reactor.monotonic()
|
self.start_time = reactor.monotonic()
|
||||||
self.clocksync = clocksync.ClockSync(self.reactor)
|
self.clocksync = clocksync.ClockSync(self.reactor)
|
||||||
|
@ -52,7 +54,10 @@ class KeyboardReader:
|
||||||
def connect(self, eventtime):
|
def connect(self, eventtime):
|
||||||
self.output(help_txt)
|
self.output(help_txt)
|
||||||
self.output("="*20 + " attempting to connect " + "="*20)
|
self.output("="*20 + " attempting to connect " + "="*20)
|
||||||
self.ser.connect()
|
if self.baud:
|
||||||
|
self.ser.connect_uart(self.serialport, self.baud)
|
||||||
|
else:
|
||||||
|
self.ser.connect_pipe(self.serialport)
|
||||||
msgparser = self.ser.get_msgparser()
|
msgparser = self.ser.get_msgparser()
|
||||||
message_count = len(msgparser.get_messages())
|
message_count = len(msgparser.get_messages())
|
||||||
version, build_versions = msgparser.get_version_info()
|
version, build_versions = msgparser.get_version_info()
|
||||||
|
@ -205,8 +210,7 @@ def main():
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
r = reactor.Reactor()
|
r = reactor.Reactor()
|
||||||
ser = serialhdl.SerialReader(r, serialport, baud)
|
kbd = KeyboardReader(r, serialport, baud)
|
||||||
kbd = KeyboardReader(ser, r)
|
|
||||||
try:
|
try:
|
||||||
r.run()
|
r.run()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|
|
@ -410,24 +410,18 @@ class MCU:
|
||||||
self._name = self._name[4:]
|
self._name = self._name[4:]
|
||||||
# Serial port
|
# Serial port
|
||||||
self._serialport = config.get('serial')
|
self._serialport = config.get('serial')
|
||||||
serial_rts = True
|
self._baud = 0
|
||||||
if config.get('restart_method', None) == "cheetah":
|
|
||||||
# Special case: Cheetah boards require RTS to be deasserted, else
|
|
||||||
# a reset will trigger the built-in bootloader.
|
|
||||||
serial_rts = False
|
|
||||||
baud = 0
|
|
||||||
if not (self._serialport.startswith("/dev/rpmsg_")
|
if not (self._serialport.startswith("/dev/rpmsg_")
|
||||||
or self._serialport.startswith("/tmp/klipper_host_")):
|
or self._serialport.startswith("/tmp/klipper_host_")):
|
||||||
baud = config.getint('baud', 250000, minval=2400)
|
self._baud = config.getint('baud', 250000, minval=2400)
|
||||||
self._serial = serialhdl.SerialReader(
|
self._serial = serialhdl.SerialReader(self._reactor)
|
||||||
self._reactor, self._serialport, baud, serial_rts)
|
|
||||||
# Restarts
|
# Restarts
|
||||||
|
restart_methods = [None, 'arduino', 'cheetah', 'command', 'rpi_usb']
|
||||||
self._restart_method = 'command'
|
self._restart_method = 'command'
|
||||||
if baud:
|
if self._baud:
|
||||||
rmethods = {m: m for m in [None, 'arduino', 'cheetah', 'command',
|
rmethods = {m: m for m in restart_methods}
|
||||||
'rpi_usb']}
|
self._restart_method = config.getchoice('restart_method',
|
||||||
self._restart_method = config.getchoice(
|
rmethods, None)
|
||||||
'restart_method', rmethods, None)
|
|
||||||
self._reset_cmd = self._config_reset_cmd = None
|
self._reset_cmd = self._config_reset_cmd = None
|
||||||
self._emergency_stop_cmd = None
|
self._emergency_stop_cmd = None
|
||||||
self._is_shutdown = self._is_timeout = False
|
self._is_shutdown = self._is_timeout = False
|
||||||
|
@ -612,12 +606,18 @@ class MCU:
|
||||||
if self.is_fileoutput():
|
if self.is_fileoutput():
|
||||||
self._connect_file()
|
self._connect_file()
|
||||||
else:
|
else:
|
||||||
if (self._restart_method == 'rpi_usb'
|
resmeth = self._restart_method
|
||||||
and not os.path.exists(self._serialport)):
|
if resmeth == 'rpi_usb' and not os.path.exists(self._serialport):
|
||||||
# Try toggling usb power
|
# Try toggling usb power
|
||||||
self._check_restart("enable power")
|
self._check_restart("enable power")
|
||||||
try:
|
try:
|
||||||
self._serial.connect()
|
if self._baud:
|
||||||
|
# Cheetah boards require RTS to be deasserted
|
||||||
|
# else a reset will trigger the built-in bootloader.
|
||||||
|
rts = (resmeth != "cheetah")
|
||||||
|
self._serial.connect_uart(self._serialport, self._baud, rts)
|
||||||
|
else:
|
||||||
|
self._serial.connect_pipe(self._serialport)
|
||||||
self._clocksync.connect(self._serial)
|
self._clocksync.connect(self._serial)
|
||||||
except serialhdl.error as e:
|
except serialhdl.error as e:
|
||||||
raise error(str(e))
|
raise error(str(e))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Serial port management for firmware communication
|
# Serial port management for firmware communication
|
||||||
#
|
#
|
||||||
# Copyright (C) 2016-2020 Kevin O'Connor <kevin@koconnor.net>
|
# Copyright (C) 2016-2021 Kevin O'Connor <kevin@koconnor.net>
|
||||||
#
|
#
|
||||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
import logging, threading, os
|
import logging, threading, os
|
||||||
|
@ -13,13 +13,10 @@ class error(Exception):
|
||||||
|
|
||||||
class SerialReader:
|
class SerialReader:
|
||||||
BITS_PER_BYTE = 10.
|
BITS_PER_BYTE = 10.
|
||||||
def __init__(self, reactor, serialport, baud, rts=True):
|
def __init__(self, reactor):
|
||||||
self.reactor = reactor
|
self.reactor = reactor
|
||||||
self.serialport = serialport
|
|
||||||
self.baud = baud
|
|
||||||
# Serial port
|
# Serial port
|
||||||
self.ser = None
|
self.serial_dev = None
|
||||||
self.rts = rts
|
|
||||||
self.msgparser = msgproto.MessageParser()
|
self.msgparser = msgproto.MessageParser()
|
||||||
# C interface
|
# C interface
|
||||||
self.ffi_main, self.ffi_lib = chelper.get_ffi()
|
self.ffi_main, self.ffi_lib = chelper.get_ffi()
|
||||||
|
@ -75,42 +72,20 @@ class SerialReader:
|
||||||
# Done
|
# Done
|
||||||
return identify_data
|
return identify_data
|
||||||
identify_data += msgdata
|
identify_data += msgdata
|
||||||
def connect(self):
|
def _start_session(self, serial_dev):
|
||||||
# Initial connection
|
self.serial_dev = serial_dev
|
||||||
logging.info("Starting serial connect")
|
self.serialqueue = self.ffi_main.gc(
|
||||||
start_time = self.reactor.monotonic()
|
self.ffi_lib.serialqueue_alloc(serial_dev.fileno(), 0),
|
||||||
while 1:
|
self.ffi_lib.serialqueue_free)
|
||||||
connect_time = self.reactor.monotonic()
|
self.background_thread = threading.Thread(target=self._bg_thread)
|
||||||
if connect_time > start_time + 90.:
|
self.background_thread.start()
|
||||||
raise error("Unable to connect")
|
# Obtain and load the data dictionary from the firmware
|
||||||
try:
|
completion = self.reactor.register_callback(self._get_identify_data)
|
||||||
if self.baud:
|
identify_data = completion.wait(self.reactor.monotonic() + 5.)
|
||||||
self.ser = serial.Serial(
|
if identify_data is None:
|
||||||
baudrate=self.baud, timeout=0, exclusive=True)
|
logging.info("Timeout on connect")
|
||||||
self.ser.port = self.serialport
|
|
||||||
self.ser.rts = self.rts
|
|
||||||
self.ser.open()
|
|
||||||
else:
|
|
||||||
fd = os.open(self.serialport, os.O_RDWR | os.O_NOCTTY)
|
|
||||||
self.ser = os.fdopen(fd, 'rb+', 0)
|
|
||||||
except (OSError, IOError, serial.SerialException) as e:
|
|
||||||
logging.warn("Unable to open port: %s", e)
|
|
||||||
self.reactor.pause(connect_time + 5.)
|
|
||||||
continue
|
|
||||||
if self.baud:
|
|
||||||
stk500v2_leave(self.ser, self.reactor)
|
|
||||||
self.serialqueue = self.ffi_main.gc(
|
|
||||||
self.ffi_lib.serialqueue_alloc(self.ser.fileno(), 0),
|
|
||||||
self.ffi_lib.serialqueue_free)
|
|
||||||
self.background_thread = threading.Thread(target=self._bg_thread)
|
|
||||||
self.background_thread.start()
|
|
||||||
# Obtain and load the data dictionary from the firmware
|
|
||||||
completion = self.reactor.register_callback(self._get_identify_data)
|
|
||||||
identify_data = completion.wait(connect_time + 5.)
|
|
||||||
if identify_data is not None:
|
|
||||||
break
|
|
||||||
logging.info("Timeout on serial connect")
|
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
|
return False
|
||||||
msgparser = msgproto.MessageParser()
|
msgparser = msgproto.MessageParser()
|
||||||
msgparser.process_identify(identify_data)
|
msgparser.process_identify(identify_data)
|
||||||
self.msgparser = msgparser
|
self.msgparser = msgparser
|
||||||
|
@ -125,11 +100,49 @@ class SerialReader:
|
||||||
if receive_window is not None:
|
if receive_window is not None:
|
||||||
self.ffi_lib.serialqueue_set_receive_window(
|
self.ffi_lib.serialqueue_set_receive_window(
|
||||||
self.serialqueue, receive_window)
|
self.serialqueue, receive_window)
|
||||||
|
return True
|
||||||
|
def connect_pipe(self, filename):
|
||||||
|
logging.info("Starting connect")
|
||||||
|
start_time = self.reactor.monotonic()
|
||||||
|
while 1:
|
||||||
|
if self.reactor.monotonic() > start_time + 90.:
|
||||||
|
raise 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)
|
||||||
|
self.reactor.pause(self.reactor.monotonic() + 5.)
|
||||||
|
continue
|
||||||
|
serial_dev = os.fdopen(fd, 'rb+', 0)
|
||||||
|
ret = self._start_session(serial_dev)
|
||||||
|
if ret:
|
||||||
|
break
|
||||||
|
def connect_uart(self, serialport, baud, rts=True):
|
||||||
|
# Initial connection
|
||||||
|
logging.info("Starting serial connect")
|
||||||
|
start_time = self.reactor.monotonic()
|
||||||
|
while 1:
|
||||||
|
if self.reactor.monotonic() > start_time + 90.:
|
||||||
|
raise error("Unable to connect")
|
||||||
|
try:
|
||||||
|
serial_dev = serial.Serial(baudrate=baud, timeout=0,
|
||||||
|
exclusive=True)
|
||||||
|
serial_dev.port = serialport
|
||||||
|
serial_dev.rts = rts
|
||||||
|
serial_dev.open()
|
||||||
|
except (OSError, IOError, serial.SerialException) as e:
|
||||||
|
logging.warn("Unable to open serial port: %s", e)
|
||||||
|
self.reactor.pause(self.reactor.monotonic() + 5.)
|
||||||
|
continue
|
||||||
|
stk500v2_leave(serial_dev, self.reactor)
|
||||||
|
ret = self._start_session(serial_dev)
|
||||||
|
if ret:
|
||||||
|
break
|
||||||
def connect_file(self, debugoutput, dictionary, pace=False):
|
def connect_file(self, debugoutput, dictionary, pace=False):
|
||||||
self.ser = debugoutput
|
self.serial_dev = debugoutput
|
||||||
self.msgparser.process_identify(dictionary, decompress=False)
|
self.msgparser.process_identify(dictionary, decompress=False)
|
||||||
self.serialqueue = self.ffi_main.gc(
|
self.serialqueue = self.ffi_main.gc(
|
||||||
self.ffi_lib.serialqueue_alloc(self.ser.fileno(), 1),
|
self.ffi_lib.serialqueue_alloc(self.serial_dev.fileno(), 1),
|
||||||
self.ffi_lib.serialqueue_free)
|
self.ffi_lib.serialqueue_free)
|
||||||
def set_clock_est(self, freq, last_time, last_clock):
|
def set_clock_est(self, freq, last_time, last_clock):
|
||||||
self.ffi_lib.serialqueue_set_clock_est(
|
self.ffi_lib.serialqueue_set_clock_est(
|
||||||
|
@ -140,9 +153,9 @@ class SerialReader:
|
||||||
if self.background_thread is not None:
|
if self.background_thread is not None:
|
||||||
self.background_thread.join()
|
self.background_thread.join()
|
||||||
self.background_thread = self.serialqueue = None
|
self.background_thread = self.serialqueue = None
|
||||||
if self.ser is not None:
|
if self.serial_dev is not None:
|
||||||
self.ser.close()
|
self.serial_dev.close()
|
||||||
self.ser = None
|
self.serial_dev = None
|
||||||
for pn in self.pending_notifications.values():
|
for pn in self.pending_notifications.values():
|
||||||
pn.complete(None)
|
pn.complete(None)
|
||||||
self.pending_notifications.clear()
|
self.pending_notifications.clear()
|
||||||
|
|
|
@ -777,9 +777,11 @@ class SDCardSPI:
|
||||||
class MCUConnection:
|
class MCUConnection:
|
||||||
def __init__(self, k_reactor, device, baud, board_cfg):
|
def __init__(self, k_reactor, device, baud, board_cfg):
|
||||||
self.reactor = k_reactor
|
self.reactor = k_reactor
|
||||||
|
self.serial_device = device
|
||||||
|
self.baud = baud
|
||||||
# TODO: a change in baudrate will cause an issue, come up
|
# TODO: a change in baudrate will cause an issue, come up
|
||||||
# with a method for handling it gracefully
|
# with a method for handling it gracefully
|
||||||
self._serial = serialhdl.SerialReader(self.reactor, device, baud)
|
self._serial = serialhdl.SerialReader(self.reactor)
|
||||||
self.clocksync = clocksync.ClockSync(self.reactor)
|
self.clocksync = clocksync.ClockSync(self.reactor)
|
||||||
self.board_config = board_cfg
|
self.board_config = board_cfg
|
||||||
self.fatfs = None
|
self.fatfs = None
|
||||||
|
@ -817,7 +819,7 @@ class MCUConnection:
|
||||||
endtime = eventtime + 60.
|
endtime = eventtime + 60.
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
self._serial.connect()
|
self._serial.connect_uart(self.serial_device, self.baud)
|
||||||
self.clocksync.connect(self._serial)
|
self.clocksync.connect(self._serial)
|
||||||
except Exception:
|
except Exception:
|
||||||
curtime = self.reactor.monotonic()
|
curtime = self.reactor.monotonic()
|
||||||
|
|
Loading…
Reference in New Issue