diff --git a/tools/otci/otci/command_handlers.py b/tools/otci/otci/command_handlers.py index ee0b5f3eb..c8982f36f 100644 --- a/tools/otci/otci/command_handlers.py +++ b/tools/otci/otci/command_handlers.py @@ -107,6 +107,7 @@ class OtCliCommandRunner(OTCommandHandler): return repr(self.__otcli) def execute_command(self, cmd, timeout=10) -> List[str]: + assert not self.__should_close.is_set(), "OT CLI is already closed." self.__otcli.writeline(cmd) if cmd in ('reset', 'factoryreset'): @@ -140,6 +141,7 @@ class OtCliCommandRunner(OTCommandHandler): def close(self): self.__should_close.set() self.__otcli.close() + self.__otcli_reader.join() def set_line_read_callback(self, callback: Optional[Callable[[str], Any]]): self.__line_read_callback = callback @@ -181,10 +183,20 @@ class OtCliCommandRunner(OTCommandHandler): return output def __otcli_read_routine(self): - while not self.__should_close.isSet(): - line = self.__otcli.readline() + while not self.__should_close.is_set(): + try: + line = self.__otcli.readline() + except Exception: + if self.__should_close.is_set(): + break + else: + raise + logging.debug('%s: %r', self.__otcli, line) + if line is None: + break + if line.startswith('> '): line = line[2:] diff --git a/tools/otci/otci/connectors.py b/tools/otci/otci/connectors.py index 1785f111f..7d8a34241 100644 --- a/tools/otci/otci/connectors.py +++ b/tools/otci/otci/connectors.py @@ -30,6 +30,7 @@ import logging import subprocess import time from abc import abstractmethod +from typing import Optional class OtCliHandler: @@ -142,14 +143,25 @@ class OtCliSerial(OtCliHandler): self.__baudrate = baudrate import serial - self.__serial = serial.Serial(self.__dev, self.__baudrate, timeout=None, exclusive=True) + self.__serial = serial.Serial(self.__dev, self.__baudrate, timeout=0.1, exclusive=True) + self.__linebuffer = b'' def __repr__(self): return self.__dev - def readline(self) -> str: - line = self.__serial.readline().decode('utf-8').rstrip('\r\n') - return line + def readline(self) -> Optional[str]: + while self.__serial.is_open: + line = self.__serial.readline() + + if not line.endswith(b'\n'): + self.__linebuffer += line + else: + line = self.__linebuffer + line + self.__linebuffer = b'' + + return line.decode('utf-8').rstrip('\r\n') + + return None def writeline(self, s: str): self.__serial.write((s + '\n').encode('utf-8'))