idf_monitor: use cancellation and Console.getkey from pyserial 3.3.0+
Between 3.1.0 and 3.3.0, pyserial had thread cancellation implemented using a select, which blocked on the stdin and an auxiliary pipe. When thread had to be cancelled, a byte would be sent into the pipe, unblocking stdin. Unfortunately, this method suffers from a problem with using select on a StreamReader (which represents the decoder wrapped around stdin). In some cases, when the TTY sends an escape sequence in response to an escape sequence received from serial, this escape sequence will not be read from stdin until some key is pressed. In https://github.com/pyserial/pyserial/commit/cab3dab, this method was replaced with an TIOCSTI ioctl. This change makes sure we use the new cancellation method even if the script is running with older pyserial.
This commit is contained in:
parent
489c523870
commit
d7d6f1e376
1 changed files with 21 additions and 5 deletions
|
@ -43,6 +43,8 @@ import serial
|
||||||
import serial.tools.miniterm as miniterm
|
import serial.tools.miniterm as miniterm
|
||||||
import threading
|
import threading
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import types
|
||||||
|
from distutils.version import StrictVersion
|
||||||
|
|
||||||
key_description = miniterm.key_description
|
key_description = miniterm.key_description
|
||||||
|
|
||||||
|
@ -157,13 +159,17 @@ class ConsoleReader(StoppableThread):
|
||||||
self.console.cleanup()
|
self.console.cleanup()
|
||||||
|
|
||||||
def _cancel(self):
|
def _cancel(self):
|
||||||
if hasattr(self.console, "cancel"):
|
if os.name == 'posix':
|
||||||
self.console.cancel()
|
# this is the way cancel() is implemented in pyserial 3.3 or newer,
|
||||||
elif os.name == 'posix':
|
# older pyserial (3.1+) has cancellation implemented via 'select',
|
||||||
# this is the way cancel() is implemented in pyserial 3.1 or newer,
|
# which does not work when console sends an escape sequence response
|
||||||
# older pyserial doesn't have this method, hence this hack.
|
#
|
||||||
|
# even older pyserial (<3.1) does not have this method
|
||||||
#
|
#
|
||||||
# on Windows there is a different (also hacky) fix, applied above.
|
# on Windows there is a different (also hacky) fix, applied above.
|
||||||
|
#
|
||||||
|
# note that TIOCSTI is not implemented in WSL / bash-on-Windows.
|
||||||
|
# TODO: introduce some workaround to make it work there.
|
||||||
import fcntl, termios
|
import fcntl, termios
|
||||||
fcntl.ioctl(self.console.fd, termios.TIOCSTI, b'\0')
|
fcntl.ioctl(self.console.fd, termios.TIOCSTI, b'\0')
|
||||||
|
|
||||||
|
@ -221,6 +227,16 @@ class Monitor(object):
|
||||||
self.console.output = ANSIColorConverter(self.console.output)
|
self.console.output = ANSIColorConverter(self.console.output)
|
||||||
self.console.byte_output = ANSIColorConverter(self.console.byte_output)
|
self.console.byte_output = ANSIColorConverter(self.console.byte_output)
|
||||||
|
|
||||||
|
if StrictVersion(serial.VERSION) < StrictVersion('3.3.0'):
|
||||||
|
# Use Console.getkey implementation from 3.3.0 (to be in sync with the ConsoleReader._cancel patch above)
|
||||||
|
def getkey_patched(self):
|
||||||
|
c = self.enc_stdin.read(1)
|
||||||
|
if c == unichr(0x7f):
|
||||||
|
c = unichr(8) # map the BS key (which yields DEL) to backspace
|
||||||
|
return c
|
||||||
|
|
||||||
|
self.console.getkey = types.MethodType(getkey_patched, self.console)
|
||||||
|
|
||||||
self.serial = serial_instance
|
self.serial = serial_instance
|
||||||
self.console_reader = ConsoleReader(self.console, self.event_queue)
|
self.console_reader = ConsoleReader(self.console, self.event_queue)
|
||||||
self.serial_reader = SerialReader(self.serial, self.event_queue)
|
self.serial_reader = SerialReader(self.serial, self.event_queue)
|
||||||
|
|
Loading…
Reference in a new issue