Is there a way to 'pause' pyserial's ReaderThread to allow a direct read of a serial port

Question:

I’ve got a gui that I’m playing with that uses pyserial. In it I’m using pyserial’s ReaderThread to monitor the serial output of my serial device and print it out on a console window.

I also am using pyserial’s Serial() implementation for sending commands to the serial device.

Usually I don’t need to grab the response to a ser.write() and just let the ReaderThread handle it.

However there are now occasions where I’d like in pause the ReaderThread do a ser.read() to a variable, act on the variable, and unpause the ReaderThread to let it continue it’s thing.

Tried ReaderThread.stop(), but it seems to be dropping the connection.

Also tried creating my own readerThread.run() function that has mutex locking and replacing the run method with it, but that’s turning out to be a bit squirrelly.

Am I missing an easy way to do this?

Asked By: zonedar

||

Answers:

Figured a way by monkey patching the ReaderThread Class:

def localinit(self, serial_instance, protocol_factory):
    """
    Initialize thread.

    Note that the serial_instance' timeout is set to one second!
    Other settings are not changed.
    """
    super(ReaderThread, self).__init__()
    self.daemon = True
    self.serial = serial_instance
    self.protocol_factory = protocol_factory
    self.alive = True
    self._lock = threading.Lock()
    self._connection_made = threading.Event()
    self.protocol = None


    self._stop_event = threading.Event()

    print("****************************************************")
    print("                 localinit                          ")
    print("****************************************************")


def localrun(self):
    """Reader loop"""
    print("****************************************************")
    print("                 localrun                           ")
    print("****************************************************")
    if not hasattr(self.serial, 'cancel_read'):
        self.serial.timeout = 1
    self.protocol = self.protocol_factory()
    try:
        self.protocol.connection_made(self)
    except Exception as e:
        self.alive = False
        self.protocol.connection_lost(e)
        self._connection_made.set()
        return
    error = None
    self._connection_made.set()

    while self.alive and self.serial.is_open:
        while self._stop_event.is_set():
            #print("local run while")
            time.sleep(1)
       try:

            data = self.serial.read(self.serial.in_waiting or 1)
            
    except serial.SerialException as e:
        # probably some I/O problem such as disconnected USB serial
        # adapters -> exit
        error = e
        break
    else:
        if data:
            # make a separated try-except for called user code
            try:
                self.protocol.data_received(data)
                
            except Exception as e:
                error = e
                break
    
self.alive = False
self.protocol.connection_lost(error)
self.protocol = None


def localpause(self):
    self._stop_event.set()

def localresume(self):
    self._stop_event.clear()

Then in my main code:

        ReaderThread.run = localrun
        ReaderThread.__init__ = localinit  
        ReaderThread.pause = localpause
        ReaderThread.resume = localresume
        self.reader = ReaderThread(serialPort, SerialReaderProtocolLine)
        self.reader.start()


    def write_read_cmd(self, cmd_str):
        if(serialPort.isOpen() == False):
            print("Serial port not yet open")
            return
    
        app.serialcom.reader.pause()
        serialPort.reset_input_buffer()  # flush the buffer
        serialPort.reset_input_buffer()  # flush the buffer
        serialPort.reset_input_buffer()  # flush the buffer
        serialPort.write(bytes(cmd_str, encoding='utf-8'))
        line = serialPort.readline()
        app.serialcom.reader.resume()
        line = line.decode("utf-8")
        return line
Answered By: zonedar
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.