Cleanups, better documentation, more modular
Rename Miniterm->Jimterm. Rename Color->JimtermColor. Move all color handling into the Jimterm class. Cleanup imports.
This commit is contained in:
parent
aa95e4f513
commit
61f5c8a3f1
134
terminal.py
134
terminal.py
|
@ -1,5 +1,18 @@
|
|||
#!/usr/bin/python
|
||||
# Based on miniterm sample in pyserial
|
||||
|
||||
# Jim Paris <jim@jtan.com>
|
||||
|
||||
# Simple terminal program for serial devices. Supports setting
|
||||
# baudrates and simple LF->CRLF mapping on input, but does not
|
||||
# configure flow control, carrier detection, etc.
|
||||
|
||||
# ^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.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
@ -7,35 +20,9 @@ import serial
|
|||
import threading
|
||||
import traceback
|
||||
import time
|
||||
import re
|
||||
import signal
|
||||
|
||||
class Color(object):
|
||||
def __init__(self):
|
||||
self.total = 1
|
||||
self.codes = [""]
|
||||
self.reset = ""
|
||||
def setup(self, total):
|
||||
self.total = total
|
||||
# Initialize colorama, if needed for the total number of devices
|
||||
# we have. We avoid even loading colorama unless we need it.
|
||||
if total > 1:
|
||||
import colorama
|
||||
colorama.init()
|
||||
self.codes = [
|
||||
colorama.Fore.CYAN + colorama.Style.BRIGHT,
|
||||
colorama.Fore.YELLOW + colorama.Style.BRIGHT,
|
||||
colorama.Fore.MAGENTA + colorama.Style.BRIGHT,
|
||||
colorama.Fore.RED + colorama.Style.BRIGHT,
|
||||
colorama.Fore.GREEN + colorama.Style.BRIGHT,
|
||||
colorama.Fore.BLUE + colorama.Style.BRIGHT,
|
||||
colorama.Fore.WHITE + colorama.Style.BRIGHT,
|
||||
]
|
||||
self.reset = colorama.Style.RESET_ALL
|
||||
def code(self, n):
|
||||
return self.codes[n % self.total]
|
||||
g_color = Color()
|
||||
|
||||
# Need OS-specific method for getting keyboard input.
|
||||
if os.name == 'nt':
|
||||
import msvcrt
|
||||
class Console:
|
||||
|
@ -59,11 +46,11 @@ elif os.name == 'posix':
|
|||
self.fd = sys.stdin.fileno()
|
||||
try:
|
||||
self.old = termios.tcgetattr(self.fd)
|
||||
new = termios.tcgetattr(self.fd)
|
||||
new[3] = new[3] & ~termios.ICANON & ~termios.ECHO & ~termios.ISIG
|
||||
new[6][termios.VMIN] = 1
|
||||
new[6][termios.VTIME] = 0
|
||||
termios.tcsetattr(self.fd, termios.TCSANOW, new)
|
||||
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)
|
||||
except termios.error:
|
||||
# ignore errors, so we can pipe stuff to this script
|
||||
pass
|
||||
|
@ -87,7 +74,28 @@ else:
|
|||
raise ("Sorry, no terminal implementation for your platform (%s) "
|
||||
"available." % sys.platform)
|
||||
|
||||
class Miniterm:
|
||||
class JimtermColor(object):
|
||||
def setup(self, total):
|
||||
self.total = 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 = ""
|
||||
total = 1
|
||||
def code(self, n):
|
||||
return self.codes[n % self.total]
|
||||
|
||||
class Jimterm:
|
||||
"""Normal interactive terminal"""
|
||||
|
||||
def __init__(self,
|
||||
|
@ -95,7 +103,13 @@ class Miniterm:
|
|||
suppress_write_bytes = None,
|
||||
suppress_read_firstnull = True,
|
||||
transmit_all = False,
|
||||
add_cr = False):
|
||||
add_cr = False,
|
||||
color = True):
|
||||
|
||||
self.color = JimtermColor()
|
||||
if color:
|
||||
self.color.setup(len(serials))
|
||||
|
||||
self.serials = serials
|
||||
self.suppress_write_bytes = suppress_write_bytes or ""
|
||||
self.suppress_read_firstnull = suppress_read_firstnull
|
||||
|
@ -104,6 +118,14 @@ class Miniterm:
|
|||
self.transmit_all = transmit_all
|
||||
self.add_cr = add_cr
|
||||
|
||||
def print_header(self, nodes, bauds):
|
||||
for (n, (node, baud)) in enumerate(zip(nodes, bauds)):
|
||||
print (self.color.code(n)
|
||||
+ node + ", " + str(baud) + " baud"
|
||||
+ self.color.reset)
|
||||
print "^C to exit"
|
||||
print "----------"
|
||||
|
||||
def start(self):
|
||||
self.alive = True
|
||||
|
||||
|
@ -111,7 +133,7 @@ class Miniterm:
|
|||
for (n, serial) in enumerate(self.serials):
|
||||
self.threads.append(threading.Thread(
|
||||
target = self.reader,
|
||||
args = (serial, g_color.code(n))
|
||||
args = (serial, self.color.code(n))
|
||||
))
|
||||
|
||||
# console->serial
|
||||
|
@ -154,9 +176,10 @@ class Miniterm:
|
|||
|
||||
if ((ord(data) >= 32 and ord(data) < 128) or
|
||||
data == '\r' or data == '\n' or data == '\t'):
|
||||
sys.stdout.write(data)
|
||||
if self.add_cr and data == '\n':
|
||||
sys.stdout.write('\r')
|
||||
sys.stdout.write('\r' + data)
|
||||
else:
|
||||
sys.stdout.write(data)
|
||||
else:
|
||||
sys.stdout.write('\\x'+("0"+hex(ord(data))[2:])[-2:])
|
||||
|
||||
|
@ -165,7 +188,7 @@ class Miniterm:
|
|||
sys.stdout.write(color)
|
||||
sys.stdout.flush()
|
||||
traceback.print_exc()
|
||||
sys.stdout.write(g_color.reset)
|
||||
sys.stdout.write(self.color.reset)
|
||||
sys.stdout.flush()
|
||||
self.console.cleanup()
|
||||
os._exit(1)
|
||||
|
@ -201,7 +224,7 @@ class Miniterm:
|
|||
else:
|
||||
self.serials[0].write(c)
|
||||
except Exception as e:
|
||||
sys.stdout.write(g_color.reset)
|
||||
sys.stdout.write(self.color.reset)
|
||||
sys.stdout.flush()
|
||||
traceback.print_exc()
|
||||
self.console.cleanup()
|
||||
|
@ -226,11 +249,12 @@ class Miniterm:
|
|||
serial.timeout = saved_timeouts[n]
|
||||
|
||||
# Cleanup
|
||||
print ""
|
||||
print self.color.reset # and a newline
|
||||
self.console.cleanup()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
import re
|
||||
|
||||
formatter = argparse.ArgumentDefaultsHelpFormatter
|
||||
description = ("Simple serial terminal that supports multiple devices. "
|
||||
|
@ -245,7 +269,7 @@ if __name__ == "__main__":
|
|||
"per-device baudrates.")
|
||||
|
||||
parser.add_argument("--crlf", "-c", action="store_true",
|
||||
help="add CR after incoming LF")
|
||||
help="add CR before incoming LF")
|
||||
parser.add_argument("--all", "-a", action="store_true",
|
||||
help="Send keystrokes to all devices, not just "
|
||||
"the first one")
|
||||
|
@ -257,8 +281,8 @@ if __name__ == "__main__":
|
|||
args = parser.parse_args()
|
||||
|
||||
devs = []
|
||||
used_nodes = []
|
||||
g_color.setup(len(args.device))
|
||||
nodes = []
|
||||
bauds = []
|
||||
for (n, device) in enumerate(args.device):
|
||||
m = re.search(r"^(.*)@([1-9][0-9]*)$", device)
|
||||
if m is not None:
|
||||
|
@ -267,26 +291,22 @@ if __name__ == "__main__":
|
|||
else:
|
||||
node = device
|
||||
baud = args.baudrate
|
||||
if node in used_nodes:
|
||||
sys.stderr.write("error: %s already open!\n" % node)
|
||||
if node in nodes:
|
||||
sys.stderr.write("error: %s specified more than once\n" % node)
|
||||
raise SystemExit(1)
|
||||
try:
|
||||
dev = serial.Serial(node, baud)
|
||||
except serial.serialutil.SerialException:
|
||||
sys.stderr.write("error opening %s\n" % node)
|
||||
raise SystemExit(1)
|
||||
if not args.quiet:
|
||||
print (g_color.code(n)
|
||||
+ node + ", " + str(args.baudrate) + " baud"
|
||||
+ g_color.reset)
|
||||
used_nodes.append(node)
|
||||
nodes.append(node)
|
||||
bauds.append(baud)
|
||||
devs.append(dev)
|
||||
|
||||
term = Jimterm(devs,
|
||||
transmit_all = args.all,
|
||||
add_cr = args.crlf,
|
||||
color = (os.name == "posix"))
|
||||
if not args.quiet:
|
||||
print "^C to exit"
|
||||
print "----------"
|
||||
term = Miniterm(devs,
|
||||
transmit_all = args.all,
|
||||
add_cr = args.crlf)
|
||||
term.print_header(nodes, bauds)
|
||||
term.run()
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user