2012-11-14 16:57:15 -05:00
|
|
|
#!/usr/bin/python
|
2012-11-14 19:25:46 -05:00
|
|
|
|
|
|
|
# Jim Paris <jim@jtan.com>
|
|
|
|
|
|
|
|
# Simple terminal program for serial devices. Supports setting
|
2013-07-03 17:35:04 -04:00
|
|
|
# baudrates and simple LF->CRLF mapping on input, and basic
|
|
|
|
# flow control, but nothing fancy.
|
2012-11-14 19:25:46 -05:00
|
|
|
|
|
|
|
# ^C quits. There is no escaping, so you can't currently send this
|
|
|
|
# character to the remote host. Piping input or output should work.
|
|
|
|
|
|
|
|
# Supports multiple serial devices simultaneously. When using more
|
|
|
|
# than one, each device's output is in a different color. Input
|
|
|
|
# is directed to the first device, or can be sent to all devices
|
|
|
|
# with --all.
|
2012-11-14 16:57:15 -05:00
|
|
|
|
2012-11-14 17:13:56 -05:00
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import serial
|
|
|
|
import threading
|
|
|
|
import traceback
|
|
|
|
import time
|
2012-11-14 18:14:53 -05:00
|
|
|
import signal
|
2013-07-04 18:33:38 -04:00
|
|
|
import fcntl
|
2013-07-05 13:18:11 -04:00
|
|
|
import string
|
2013-07-05 14:00:55 -04:00
|
|
|
import re
|
2012-11-14 17:13:56 -05:00
|
|
|
|
2012-11-14 19:25:46 -05:00
|
|
|
# Need OS-specific method for getting keyboard input.
|
2012-11-14 16:57:15 -05:00
|
|
|
if os.name == 'nt':
|
|
|
|
import msvcrt
|
|
|
|
class Console:
|
2013-07-05 13:18:11 -04:00
|
|
|
def __init__(self, bufsize = 1):
|
|
|
|
# Buffer size > 1 not supported on Windows
|
2013-07-04 18:33:38 -04:00
|
|
|
self.tty = True
|
2012-11-14 17:00:06 -05:00
|
|
|
def cleanup(self):
|
2012-11-14 16:57:15 -05:00
|
|
|
pass
|
|
|
|
def getkey(self):
|
2013-07-04 18:33:38 -04:00
|
|
|
start = time.time()
|
|
|
|
while True:
|
2012-11-14 16:57:15 -05:00
|
|
|
z = msvcrt.getch()
|
|
|
|
if z == '\0' or z == '\xe0': # function keys
|
|
|
|
msvcrt.getch()
|
|
|
|
else:
|
|
|
|
if z == '\r':
|
|
|
|
return '\n'
|
|
|
|
return z
|
2013-07-04 18:33:38 -04:00
|
|
|
if (time.time() - start) > 0.1:
|
|
|
|
return None
|
2013-07-05 13:18:11 -04:00
|
|
|
|
2013-07-04 23:22:18 -04:00
|
|
|
class MySerial(serial.Serial):
|
|
|
|
def nonblocking_read(self, size=1):
|
2013-07-05 13:18:11 -04:00
|
|
|
# Buffer size > 1 not supported on Windows
|
|
|
|
return self.read(1)
|
2012-11-14 16:57:15 -05:00
|
|
|
elif os.name == 'posix':
|
2013-07-04 23:22:18 -04:00
|
|
|
import termios, select, errno
|
2012-11-14 16:57:15 -05:00
|
|
|
class Console:
|
2013-07-04 22:58:15 -04:00
|
|
|
def __init__(self, bufsize = 65536):
|
|
|
|
self.bufsize = bufsize
|
2012-11-14 16:57:15 -05:00
|
|
|
self.fd = sys.stdin.fileno()
|
2013-07-04 18:33:38 -04:00
|
|
|
if os.isatty(self.fd):
|
|
|
|
self.tty = True
|
2012-11-14 17:00:06 -05:00
|
|
|
self.old = termios.tcgetattr(self.fd)
|
2012-11-14 19:25:46 -05:00
|
|
|
tc = termios.tcgetattr(self.fd)
|
|
|
|
tc[3] = tc[3] & ~termios.ICANON & ~termios.ECHO & ~termios.ISIG
|
|
|
|
tc[6][termios.VMIN] = 1
|
|
|
|
tc[6][termios.VTIME] = 0
|
|
|
|
termios.tcsetattr(self.fd, termios.TCSANOW, tc)
|
2013-07-04 18:33:38 -04:00
|
|
|
else:
|
|
|
|
self.tty = False
|
2012-11-14 17:00:06 -05:00
|
|
|
def cleanup(self):
|
2013-07-04 18:33:38 -04:00
|
|
|
if self.tty:
|
2012-11-14 17:00:06 -05:00
|
|
|
termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old)
|
2012-11-14 16:57:15 -05:00
|
|
|
def getkey(self):
|
2012-11-14 18:14:53 -05:00
|
|
|
# Return -1 if we don't get input in 0.1 seconds, so that
|
|
|
|
# the main code can check the "alive" flag and respond to SIGINT.
|
|
|
|
[r, w, x] = select.select([self.fd], [], [self.fd], 0.1)
|
|
|
|
if r:
|
2013-07-04 22:58:15 -04:00
|
|
|
return os.read(self.fd, self.bufsize)
|
2012-11-14 18:14:53 -05:00
|
|
|
elif x:
|
|
|
|
return ''
|
|
|
|
else:
|
2013-07-04 18:33:38 -04:00
|
|
|
return None
|
2013-07-05 13:18:11 -04:00
|
|
|
|
2013-07-04 23:22:18 -04:00
|
|
|
class MySerial(serial.Serial):
|
2013-07-05 13:18:11 -04:00
|
|
|
def nonblocking_read(self, size=1):
|
|
|
|
[r, w, x] = select.select([self.fd], [], [self.fd], self._timeout)
|
2013-07-04 23:22:18 -04:00
|
|
|
if r:
|
|
|
|
try:
|
|
|
|
return os.read(self.fd, size)
|
|
|
|
except OSError as e:
|
|
|
|
if e.errno == errno.EAGAIN:
|
2013-11-30 18:52:52 -05:00
|
|
|
return None
|
2013-07-04 23:22:18 -04:00
|
|
|
raise
|
|
|
|
elif x:
|
|
|
|
raise SerialException("exception (device disconnected?)")
|
|
|
|
else:
|
2013-11-30 18:52:52 -05:00
|
|
|
return None # timeout
|
2013-07-04 23:22:18 -04:00
|
|
|
|
2012-11-14 16:57:15 -05:00
|
|
|
else:
|
2012-11-14 17:00:52 -05:00
|
|
|
raise ("Sorry, no terminal implementation for your platform (%s) "
|
|
|
|
"available." % sys.platform)
|
2012-11-14 16:57:15 -05:00
|
|
|
|
2012-11-14 19:25:46 -05:00
|
|
|
class JimtermColor(object):
|
2012-11-15 13:15:11 -05:00
|
|
|
def __init__(self):
|
|
|
|
self.setup(1)
|
2012-11-14 19:25:46 -05:00
|
|
|
def setup(self, total):
|
|
|
|
if total > 1:
|
|
|
|
self.codes = [
|
|
|
|
"\x1b[1;36m", # cyan
|
|
|
|
"\x1b[1;33m", # yellow
|
|
|
|
"\x1b[1;35m", # magenta
|
|
|
|
"\x1b[1;31m", # red
|
|
|
|
"\x1b[1;32m", # green
|
|
|
|
"\x1b[1;34m", # blue
|
|
|
|
"\x1b[1;37m", # white
|
|
|
|
]
|
|
|
|
self.reset = "\x1b[0m"
|
|
|
|
else:
|
|
|
|
self.codes = [""]
|
|
|
|
self.reset = ""
|
|
|
|
def code(self, n):
|
2012-11-15 13:15:11 -05:00
|
|
|
return self.codes[n % len(self.codes)]
|
2012-11-14 19:25:46 -05:00
|
|
|
|
|
|
|
class Jimterm:
|
2012-11-14 17:13:56 -05:00
|
|
|
"""Normal interactive terminal"""
|
|
|
|
|
2012-11-14 18:48:15 -05:00
|
|
|
def __init__(self,
|
|
|
|
serials,
|
2012-11-14 18:56:33 -05:00
|
|
|
suppress_write_bytes = None,
|
|
|
|
suppress_read_firstnull = True,
|
|
|
|
transmit_all = False,
|
2012-11-14 19:25:46 -05:00
|
|
|
add_cr = False,
|
2017-04-26 16:43:28 -04:00
|
|
|
send_cr = False,
|
2013-07-04 20:51:03 -04:00
|
|
|
raw = True,
|
2013-07-04 22:58:15 -04:00
|
|
|
color = True,
|
|
|
|
bufsize = 65536):
|
2012-11-14 19:25:46 -05:00
|
|
|
|
|
|
|
self.color = JimtermColor()
|
|
|
|
if color:
|
|
|
|
self.color.setup(len(serials))
|
|
|
|
|
2012-11-14 18:35:05 -05:00
|
|
|
self.serials = serials
|
2013-07-04 18:33:38 -04:00
|
|
|
self.suppress_write_bytes = suppress_write_bytes
|
2012-11-14 18:56:33 -05:00
|
|
|
self.suppress_read_firstnull = suppress_read_firstnull
|
2012-11-14 18:35:05 -05:00
|
|
|
self.last_color = ""
|
2012-11-14 17:13:56 -05:00
|
|
|
self.threads = []
|
2012-11-14 18:48:15 -05:00
|
|
|
self.transmit_all = transmit_all
|
2012-11-14 18:56:33 -05:00
|
|
|
self.add_cr = add_cr
|
2017-04-26 16:43:28 -04:00
|
|
|
self.send_cr = send_cr
|
2012-11-15 13:16:02 -05:00
|
|
|
self.raw = raw
|
2013-07-04 22:58:15 -04:00
|
|
|
self.bufsize = bufsize
|
2013-07-05 14:00:55 -04:00
|
|
|
self.quote_re = None
|
2017-07-24 14:43:36 -04:00
|
|
|
self.output_lock = threading.Lock()
|
2012-11-14 16:57:15 -05:00
|
|
|
|
2013-07-05 12:26:39 -04:00
|
|
|
def print_header(self, nodes, bauds, output = sys.stdout):
|
2012-11-14 19:25:46 -05:00
|
|
|
for (n, (node, baud)) in enumerate(zip(nodes, bauds)):
|
2013-07-04 22:54:29 -04:00
|
|
|
output.write(self.color.code(n)
|
|
|
|
+ node + ", " + str(baud) + " baud"
|
|
|
|
+ self.color.reset + "\n")
|
2013-07-05 12:26:39 -04:00
|
|
|
if sys.stdin.isatty():
|
2013-07-04 22:54:29 -04:00
|
|
|
output.write("^C to exit\n")
|
|
|
|
output.write("----------\n")
|
|
|
|
output.flush()
|
2012-11-14 19:25:46 -05:00
|
|
|
|
2012-11-14 16:57:15 -05:00
|
|
|
def start(self):
|
|
|
|
self.alive = True
|
2012-11-14 18:35:05 -05:00
|
|
|
|
2013-07-05 12:26:39 -04:00
|
|
|
# Set up console
|
|
|
|
self.console = Console(self.bufsize)
|
|
|
|
|
2012-11-14 18:35:05 -05:00
|
|
|
# serial->console, all devices
|
|
|
|
for (n, serial) in enumerate(self.serials):
|
|
|
|
self.threads.append(threading.Thread(
|
|
|
|
target = self.reader,
|
2012-11-14 19:25:46 -05:00
|
|
|
args = (serial, self.color.code(n))
|
2012-11-14 18:35:05 -05:00
|
|
|
))
|
|
|
|
|
2012-11-14 18:48:15 -05:00
|
|
|
# console->serial
|
|
|
|
self.threads.append(threading.Thread(target = self.writer))
|
2012-11-14 18:35:05 -05:00
|
|
|
|
|
|
|
# start all threads
|
2012-11-14 17:13:56 -05:00
|
|
|
for thread in self.threads:
|
|
|
|
thread.daemon = True
|
|
|
|
thread.start()
|
2012-11-14 16:57:15 -05:00
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
self.alive = False
|
|
|
|
|
2012-11-14 17:13:56 -05:00
|
|
|
def join(self):
|
|
|
|
for thread in self.threads:
|
2012-11-14 18:14:53 -05:00
|
|
|
while thread.isAlive():
|
|
|
|
thread.join(0.1)
|
2012-11-14 16:57:15 -05:00
|
|
|
|
2013-07-05 14:00:55 -04:00
|
|
|
def quote_raw(self, data):
|
|
|
|
if self.quote_re is None:
|
2013-11-26 15:06:34 -05:00
|
|
|
matcher = '[^%s]' % re.escape(string.printable + "\b")
|
2013-07-05 14:00:55 -04:00
|
|
|
if sys.version_info < (3,):
|
|
|
|
self.quote_re = re.compile(matcher)
|
|
|
|
qf = lambda x: ("\\x%02x" % ord(x.group(0)))
|
|
|
|
else:
|
|
|
|
self.quote_re = re.compile(matcher.encode('ascii'))
|
|
|
|
qf = lambda x: ("\\x%02x" % ord(x.group(0))).encode('ascii')
|
|
|
|
self.quote_func = qf
|
|
|
|
return self.quote_re.sub(self.quote_func, data)
|
|
|
|
|
2012-11-14 18:35:05 -05:00
|
|
|
def reader(self, serial, color):
|
2012-11-14 16:57:15 -05:00
|
|
|
"""loop and copy serial->console"""
|
2012-11-14 18:56:33 -05:00
|
|
|
first = True
|
2012-11-14 17:00:06 -05:00
|
|
|
try:
|
2013-07-05 14:00:55 -04:00
|
|
|
if (sys.version_info < (3,)):
|
|
|
|
null = '\x00'
|
|
|
|
else:
|
|
|
|
null = b'\x00'
|
2012-11-14 17:00:06 -05:00
|
|
|
while self.alive:
|
2013-07-04 23:22:18 -04:00
|
|
|
data = serial.nonblocking_read(self.bufsize)
|
2013-11-30 18:52:52 -05:00
|
|
|
if data is None:
|
2012-11-14 17:13:56 -05:00
|
|
|
continue
|
2013-11-30 18:52:52 -05:00
|
|
|
if not len(data):
|
|
|
|
raise Exception("read returned EOF")
|
2012-11-14 18:56:33 -05:00
|
|
|
|
|
|
|
# don't print a NULL if it's the first character we
|
|
|
|
# read. This hides startup/port-opening glitches with
|
|
|
|
# some serial devices.
|
2013-07-05 14:00:55 -04:00
|
|
|
if self.suppress_read_firstnull and first and data[0] == null:
|
2012-11-14 18:56:33 -05:00
|
|
|
first = False
|
2013-07-04 23:22:18 -04:00
|
|
|
data = data[1:]
|
2012-11-14 18:56:33 -05:00
|
|
|
first = False
|
|
|
|
|
2017-07-24 14:43:36 -04:00
|
|
|
self.output_lock.acquire()
|
|
|
|
|
2012-11-14 18:35:05 -05:00
|
|
|
if color != self.last_color:
|
|
|
|
self.last_color = color
|
2013-07-05 14:00:55 -04:00
|
|
|
os.write(sys.stdout.fileno(), color)
|
2012-11-14 18:56:33 -05:00
|
|
|
|
2013-07-04 23:22:18 -04:00
|
|
|
if self.add_cr:
|
2013-07-05 14:00:55 -04:00
|
|
|
if sys.version_info < (3,):
|
|
|
|
data = data.replace('\n', '\r\n')
|
|
|
|
else:
|
|
|
|
data = data.replace(b'\n', b'\r\n')
|
2013-07-04 23:22:18 -04:00
|
|
|
|
|
|
|
if not self.raw:
|
2013-07-05 14:00:55 -04:00
|
|
|
data = self.quote_raw(data)
|
|
|
|
|
|
|
|
os.write(sys.stdout.fileno(), data)
|
2017-07-24 14:43:36 -04:00
|
|
|
|
|
|
|
self.output_lock.release()
|
|
|
|
|
2012-11-14 17:00:06 -05:00
|
|
|
except Exception as e:
|
2013-07-05 13:18:11 -04:00
|
|
|
self.console.cleanup()
|
2012-11-14 18:48:25 -05:00
|
|
|
sys.stdout.write(color)
|
|
|
|
sys.stdout.flush()
|
2012-11-14 17:00:06 -05:00
|
|
|
traceback.print_exc()
|
2012-11-14 19:25:46 -05:00
|
|
|
sys.stdout.write(self.color.reset)
|
2012-11-14 18:48:25 -05:00
|
|
|
sys.stdout.flush()
|
2012-11-14 17:00:06 -05:00
|
|
|
os._exit(1)
|
2012-11-14 16:57:15 -05:00
|
|
|
|
2012-11-14 18:48:15 -05:00
|
|
|
def writer(self):
|
2012-11-14 16:57:15 -05:00
|
|
|
"""loop and copy console->serial until ^C"""
|
2012-11-14 17:00:06 -05:00
|
|
|
try:
|
2013-07-05 14:00:55 -04:00
|
|
|
if (sys.version_info < (3,)):
|
|
|
|
ctrlc = '\x03'
|
|
|
|
else:
|
|
|
|
ctrlc = b'\x03'
|
2012-11-14 16:57:15 -05:00
|
|
|
while self.alive:
|
|
|
|
try:
|
2012-11-14 17:00:06 -05:00
|
|
|
c = self.console.getkey()
|
2012-11-14 16:57:15 -05:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
self.stop()
|
2012-11-14 17:00:06 -05:00
|
|
|
return
|
2013-07-04 18:33:38 -04:00
|
|
|
if c is None:
|
|
|
|
# No input, try again.
|
2012-11-14 18:14:53 -05:00
|
|
|
continue
|
2013-07-05 14:00:55 -04:00
|
|
|
elif self.console.tty and ctrlc in c:
|
2013-07-04 18:33:38 -04:00
|
|
|
# Try to catch ^C that didn't trigger KeyboardInterrupt
|
|
|
|
self.stop()
|
|
|
|
return
|
2012-11-14 17:00:06 -05:00
|
|
|
elif c == '':
|
2013-07-04 18:33:38 -04:00
|
|
|
# Probably EOF on input. Wait a tiny bit so we can
|
2012-11-14 17:00:06 -05:00
|
|
|
# flush the remaining input, then stop.
|
|
|
|
time.sleep(0.25)
|
|
|
|
self.stop()
|
|
|
|
return
|
2012-11-14 16:57:15 -05:00
|
|
|
else:
|
2013-07-04 18:33:38 -04:00
|
|
|
# Remove bytes we don't want to send
|
|
|
|
if self.suppress_write_bytes is not None:
|
|
|
|
c = c.translate(None, self.suppress_write_bytes)
|
|
|
|
|
2017-04-26 16:43:28 -04:00
|
|
|
if self.send_cr and c == '\n':
|
|
|
|
c = '\r'
|
2013-07-04 18:33:38 -04:00
|
|
|
# Send character
|
2012-11-14 18:48:15 -05:00
|
|
|
if self.transmit_all:
|
|
|
|
for serial in self.serials:
|
|
|
|
serial.write(c)
|
|
|
|
else:
|
|
|
|
self.serials[0].write(c)
|
2012-11-14 17:00:06 -05:00
|
|
|
except Exception as e:
|
2013-07-05 13:18:11 -04:00
|
|
|
self.console.cleanup()
|
2012-11-14 19:25:46 -05:00
|
|
|
sys.stdout.write(self.color.reset)
|
2012-11-14 18:48:25 -05:00
|
|
|
sys.stdout.flush()
|
2012-11-14 17:00:06 -05:00
|
|
|
traceback.print_exc()
|
|
|
|
os._exit(1)
|
2012-11-14 16:57:15 -05:00
|
|
|
|
|
|
|
def run(self):
|
2012-11-14 18:35:05 -05:00
|
|
|
# Set all serial port timeouts to 0.1 sec
|
|
|
|
saved_timeouts = []
|
2013-07-04 18:40:26 -04:00
|
|
|
for serial in self.serials:
|
2012-11-14 18:35:05 -05:00
|
|
|
saved_timeouts.append(serial.timeout)
|
|
|
|
serial.timeout = 0.1
|
|
|
|
|
2013-07-04 18:33:59 -04:00
|
|
|
# Work around https://sourceforge.net/p/pyserial/bugs/151/
|
|
|
|
saved_writeTimeouts = []
|
|
|
|
for serial in self.serials:
|
|
|
|
saved_writeTimeouts.append(serial.writeTimeout)
|
|
|
|
serial.writeTimeout = 1000000
|
|
|
|
|
2012-11-14 18:35:05 -05:00
|
|
|
# Handle SIGINT gracefully
|
2012-11-14 18:14:53 -05:00
|
|
|
signal.signal(signal.SIGINT, lambda *args: self.stop())
|
2012-11-14 18:35:05 -05:00
|
|
|
|
|
|
|
# Go
|
2012-11-14 16:57:15 -05:00
|
|
|
self.start()
|
|
|
|
self.join()
|
2012-11-14 18:35:05 -05:00
|
|
|
|
|
|
|
# Restore serial port timeouts
|
2013-07-04 18:33:59 -04:00
|
|
|
for (serial, saved) in zip(self.serials, saved_timeouts):
|
|
|
|
serial.timeout = saved
|
|
|
|
for (serial, saved) in zip(self.serials, saved_writeTimeouts):
|
|
|
|
serial.writeTimeout = saved
|
2012-11-14 18:35:05 -05:00
|
|
|
|
|
|
|
# Cleanup
|
2013-07-05 13:18:11 -04:00
|
|
|
sys.stdout.write(self.color.reset + "\n")
|
2012-11-14 18:15:07 -05:00
|
|
|
self.console.cleanup()
|
2012-11-14 16:57:15 -05:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
import argparse
|
2012-11-14 19:25:46 -05:00
|
|
|
import re
|
2012-11-14 16:57:15 -05:00
|
|
|
|
2012-11-14 17:56:54 -05:00
|
|
|
formatter = argparse.ArgumentDefaultsHelpFormatter
|
|
|
|
description = ("Simple serial terminal that supports multiple devices. "
|
|
|
|
"If more than one device is specified, device output is "
|
|
|
|
"shown in varying colors. All input goes to the "
|
|
|
|
"first device.")
|
|
|
|
parser = argparse.ArgumentParser(description = description,
|
|
|
|
formatter_class = formatter)
|
|
|
|
|
2012-11-14 18:48:15 -05:00
|
|
|
parser.add_argument("device", metavar="DEVICE", nargs="+",
|
2012-11-15 13:16:02 -05:00
|
|
|
help="Serial device. Specify DEVICE@BAUD for "
|
2012-11-14 18:48:15 -05:00
|
|
|
"per-device baudrates.")
|
|
|
|
|
2013-07-05 12:26:39 -04:00
|
|
|
parser.add_argument("--quiet", "-q", action="store_true",
|
|
|
|
help="Don't print header")
|
2013-07-04 20:51:03 -04:00
|
|
|
|
2012-11-15 13:16:02 -05:00
|
|
|
parser.add_argument("--baudrate", "-b", metavar="BAUD", type=int,
|
|
|
|
help="Default baudrate for all devices", default=115200)
|
2012-11-14 18:56:33 -05:00
|
|
|
parser.add_argument("--crlf", "-c", action="store_true",
|
2012-11-15 13:16:02 -05:00
|
|
|
help="Add CR before incoming LF")
|
2017-04-26 16:43:28 -04:00
|
|
|
parser.add_argument("--lfcr", "-C", action="store_true",
|
2017-04-27 14:12:05 -04:00
|
|
|
help="Send CR instead of LF on output")
|
2012-11-14 18:48:15 -05:00
|
|
|
parser.add_argument("--all", "-a", action="store_true",
|
|
|
|
help="Send keystrokes to all devices, not just "
|
|
|
|
"the first one")
|
2012-11-15 13:16:02 -05:00
|
|
|
parser.add_argument("--mono", "-m", action="store_true",
|
|
|
|
help="Don't use colors in output")
|
2013-07-03 17:35:04 -04:00
|
|
|
parser.add_argument("--flow", "-f", action="store_true",
|
|
|
|
help="Enable RTS/CTS flow control")
|
2020-09-25 14:35:18 -04:00
|
|
|
parser.add_argument("--esp", "-e", action="store_true",
|
|
|
|
help="Force RTS and DTR high, for ESP boards. Note that"
|
|
|
|
" the lines may still glitch low at startup.")
|
2013-07-04 22:58:15 -04:00
|
|
|
parser.add_argument("--bufsize", "-z", metavar="SIZE", type=int,
|
|
|
|
help="Buffer size for reads and writes", default=65536)
|
2012-11-14 17:56:54 -05:00
|
|
|
|
2013-07-04 20:51:03 -04:00
|
|
|
group = parser.add_mutually_exclusive_group(required = False)
|
|
|
|
group.add_argument("--raw", "-r", action="store_true",
|
|
|
|
default=argparse.SUPPRESS,
|
|
|
|
help="Output characters directly "
|
|
|
|
"(default, if stdout is not a tty)")
|
|
|
|
group.add_argument("--no-raw", "-R", action="store_true",
|
|
|
|
default=argparse.SUPPRESS,
|
|
|
|
help="Quote unprintable characters "
|
|
|
|
"(default, if stdout is a tty)")
|
|
|
|
|
2012-11-14 16:57:15 -05:00
|
|
|
args = parser.parse_args()
|
2012-11-14 17:56:54 -05:00
|
|
|
|
2013-07-04 20:51:03 -04:00
|
|
|
piped = not sys.stdout.isatty()
|
|
|
|
raw = "raw" in args or (piped and "no_raw" not in args)
|
|
|
|
|
2012-11-14 17:56:54 -05:00
|
|
|
devs = []
|
2012-11-14 19:25:46 -05:00
|
|
|
nodes = []
|
|
|
|
bauds = []
|
2012-11-14 17:56:54 -05:00
|
|
|
for (n, device) in enumerate(args.device):
|
|
|
|
m = re.search(r"^(.*)@([1-9][0-9]*)$", device)
|
|
|
|
if m is not None:
|
|
|
|
node = m.group(1)
|
|
|
|
baud = m.group(2)
|
|
|
|
else:
|
|
|
|
node = device
|
|
|
|
baud = args.baudrate
|
2012-11-14 19:25:46 -05:00
|
|
|
if node in nodes:
|
|
|
|
sys.stderr.write("error: %s specified more than once\n" % node)
|
2012-11-14 18:35:05 -05:00
|
|
|
raise SystemExit(1)
|
2012-11-14 17:56:54 -05:00
|
|
|
try:
|
2020-09-25 14:35:18 -04:00
|
|
|
dev = MySerial(None, baud, rtscts = args.flow)
|
|
|
|
dev.port = node
|
|
|
|
if args.esp:
|
|
|
|
# Force DTR and RTS high by setting to false
|
|
|
|
dev.dtr = False
|
|
|
|
dev.rts = False
|
|
|
|
dev.open()
|
2012-11-14 17:56:54 -05:00
|
|
|
except serial.serialutil.SerialException:
|
|
|
|
sys.stderr.write("error opening %s\n" % node)
|
|
|
|
raise SystemExit(1)
|
2012-11-14 19:25:46 -05:00
|
|
|
nodes.append(node)
|
|
|
|
bauds.append(baud)
|
2012-11-14 17:56:54 -05:00
|
|
|
devs.append(dev)
|
|
|
|
|
2012-11-14 19:25:46 -05:00
|
|
|
term = Jimterm(devs,
|
|
|
|
transmit_all = args.all,
|
|
|
|
add_cr = args.crlf,
|
2017-04-26 16:43:28 -04:00
|
|
|
send_cr = args.lfcr,
|
2013-07-04 20:51:03 -04:00
|
|
|
raw = raw,
|
2013-07-04 22:58:15 -04:00
|
|
|
color = (os.name == "posix" and not args.mono),
|
|
|
|
bufsize = args.bufsize)
|
2013-07-05 12:26:39 -04:00
|
|
|
if not args.quiet:
|
|
|
|
term.print_header(nodes, bauds, sys.stderr)
|
|
|
|
|
2012-11-14 16:57:15 -05:00
|
|
|
term.run()
|