Permalink
Cannot retrieve contributors at this time
#!/usr/bin/env python | |
import sys | |
import time | |
import serial | |
from threading import Thread | |
class RawInput: | |
"""Gets a single character from standard input. Does not echo to the screen.""" | |
def __init__(self): | |
try: | |
self.impl = RawInputWindows() | |
except ImportError: | |
self.impl = RawInputUnix() | |
def __call__(self): return self.impl() | |
class RawInputUnix: | |
def __init__(self): | |
import tty, sys | |
def __call__(self): | |
import sys, tty, termios | |
fd = sys.stdin.fileno() | |
old_settings = termios.tcgetattr(fd) | |
try: | |
tty.setraw(sys.stdin.fileno()) | |
ch = sys.stdin.read(1) | |
finally: | |
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) | |
return ch | |
class RawInputWindows: | |
def __init__(self): | |
import msvcrt | |
def __call__(self): | |
import msvcrt | |
return msvcrt.getch() | |
class Baudrate: | |
VERSION = '1.0' | |
READ_TIMEOUT = 5 | |
BAUDRATES = [ | |
# "1200", | |
# "1800", | |
# "2400", | |
# "4800", | |
"9600", | |
"38400", | |
"19200", | |
"57600", | |
"115200", | |
] | |
UPKEYS = ['u', 'U', 'A'] | |
DOWNKEYS = ['d', 'D', 'B'] | |
MIN_CHAR_COUNT = 25 | |
WHITESPACE = [' ', '\t', '\r', '\n'] | |
PUNCTUATION = ['.', ',', ':', ';', '?', '!'] | |
VOWELS = ['a', 'A', 'e', 'E', 'i', 'I', 'o', 'O', 'u', 'U'] | |
def __init__(self, port=None, threshold=MIN_CHAR_COUNT, timeout=READ_TIMEOUT, name=None, auto=True, verbose=False): | |
self.port = port | |
self.threshold = threshold | |
self.timeout = timeout | |
self.name = name | |
self.auto_detect = auto | |
self.verbose = verbose | |
self.index = len(self.BAUDRATES) - 1 | |
self.valid_characters = [] | |
self.ctlc = False | |
self.thread = None | |
self._gen_char_list() | |
def _gen_char_list(self): | |
c = ' ' | |
while c <= '~': | |
self.valid_characters.append(c) | |
c = chr(ord(c) + 1) | |
for c in self.WHITESPACE: | |
if c not in self.valid_characters: | |
self.valid_characters.append(c) | |
def _print(self, data): | |
if self.verbose: | |
sys.stderr.write(data) | |
def Open(self): | |
self.serial = serial.Serial(self.port, timeout=self.timeout) | |
self.NextBaudrate(0) | |
def NextBaudrate(self, updn): | |
self.index += updn | |
if self.index >= len(self.BAUDRATES): | |
self.index = 0 | |
elif self.index < 0: | |
self.index = len(self.BAUDRATES) - 1 | |
sys.stderr.write('\n\n@@@@@@@@@@@@@@@@@@@@@ Baudrate: %s @@@@@@@@@@@@@@@@@@@@@\n\n' % self.BAUDRATES[self.index]) | |
self.serial.flush() | |
self.serial.baudrate = self.BAUDRATES[self.index] | |
self.serial.flush() | |
def Detect(self): | |
count = 0 | |
whitespace = 0 | |
punctuation = 0 | |
vowels = 0 | |
start_time = 0 | |
timed_out = False | |
clear_counters = False | |
if not self.auto_detect: | |
self.thread = Thread(None, self.HandleKeypress, None, (self, 1)) | |
self.thread.start() | |
while True: | |
if start_time == 0: | |
start_time = time.time() | |
byte = self.serial.read(1) | |
if byte: | |
if self.auto_detect and byte in self.valid_characters: | |
if byte in self.WHITESPACE: | |
whitespace += 1 | |
elif byte in self.PUNCTUATION: | |
punctuation += 1 | |
elif byte in self.VOWELS: | |
vowels += 1 | |
count += 1 | |
else: | |
clear_counters = True | |
self._print(byte) | |
if count >= self.threshold and whitespace > 0 and punctuation > 0 and vowels > 0: | |
break | |
elif (time.time() - start_time) >= self.timeout: | |
timed_out = True | |
else: | |
timed_out = True | |
if timed_out and self.auto_detect: | |
start_time = 0 | |
self.NextBaudrate(-1) | |
clear_counters = True | |
timed_out = False | |
if clear_counters: | |
whitespace = 0 | |
punctuation = 0 | |
vowels = 0 | |
count = 0 | |
clear_counters = False | |
if self.ctlc: | |
break | |
self._print("\n") | |
return self.BAUDRATES[self.index] | |
def HandleKeypress(self, *args): | |
userinput = RawInput() | |
while not self.ctlc: | |
c = userinput() | |
if c in self.UPKEYS: | |
self.NextBaudrate(1) | |
elif c in self.DOWNKEYS: | |
self.NextBaudrate(-1) | |
elif c == '\x03': | |
self.ctlc = True | |
def MinicomConfig(self, name=None): | |
success = True | |
if name is None: | |
name = self.name | |
config = "########################################################################\n" | |
config += "# Minicom configuration file - use \"minicom -s\" to change parameters.\n" | |
config += "pu port %s\n" % self.port | |
config += "pu baudrate %s\n" % self.BAUDRATES[self.index] | |
config += "pu bits 8\n" | |
config += "pu parity N\n" | |
config += "pu stopbits 1\n" | |
config += "pu rtscts No\n" | |
config += "########################################################################\n" | |
if name is not None and name: | |
try: | |
open("/etc/minicom/minirc.%s" % name, "w").write(config) | |
except Exception, e: | |
print "Error saving minicom config file:", str(e) | |
success = False | |
return (success, config) | |
def Close(self): | |
self.ctlc = True | |
self.serial.close() | |
if __name__ == '__main__': | |
import subprocess | |
from getopt import getopt as GetOpt, GetoptError | |
def usage(): | |
baud = Baudrate() | |
print "" | |
print "Baudrate v%s" % baud.VERSION | |
print "Craig Heffner, http://www.devttys0.com" | |
print "" | |
print "Usage: %s [OPTIONS]" % sys.argv[0] | |
print "" | |
print "\t-p <serial port> Specify the serial port to use [/dev/ttyUSB0]" | |
print "\t-t <seconds> Set the timeout period used when switching baudrates in auto detect mode [%d]" % baud.READ_TIMEOUT | |
print "\t-c <num> Set the minimum ASCII character threshold used during auto detect mode [%d]" % baud.MIN_CHAR_COUNT | |
print "\t-n <name> Save the resulting serial configuration as <name> and automatically invoke minicom (implies -a)" | |
print "\t-a Enable auto detect mode" | |
print "\t-b Display supported baud rates and exit" | |
print "\t-q Do not display data read from the serial port" | |
print "\t-h Display help" | |
print "" | |
sys.exit(1) | |
def main(): | |
display = False | |
verbose = True | |
auto = False | |
run = False | |
threshold = 25 | |
timeout = 5 | |
name = None | |
port = '/dev/ttyUSB0' | |
try: | |
(opts, args) = GetOpt(sys.argv[1:], 'p:t:c:n:abqh') | |
except GetoptError, e: | |
print e | |
usage() | |
for opt, arg in opts: | |
if opt == '-t': | |
timeout = int(arg) | |
elif opt == '-c': | |
threshold = int(arg) | |
elif opt == '-p': | |
port = arg | |
elif opt == '-n': | |
name = arg | |
auto = True | |
run = True | |
elif opt == '-a': | |
auto = True | |
elif opt == '-b': | |
display = True | |
elif opt == '-q': | |
verbose = False | |
else: | |
usage() | |
baud = Baudrate(port, threshold=threshold, timeout=timeout, name=name, verbose=verbose, auto=auto) | |
if display: | |
print "" | |
for rate in baud.BAUDRATES: | |
print "\t%s" % rate | |
print "" | |
else: | |
print "" | |
print "Starting baudrate detection on %s, turn on your serial device now." % port | |
print "Press Ctl+C to quit." | |
print "" | |
baud.Open() | |
try: | |
rate = baud.Detect() | |
print "\nDetected baudrate: %s" % rate | |
if name is None: | |
print "\nSave minicom configuration as: ", | |
name = sys.stdin.readline().strip() | |
print "" | |
(ok, config) = baud.MinicomConfig(name) | |
if name and name is not None: | |
if ok: | |
if not run: | |
print "Configuration saved. Run minicom now [n/Y]? ", | |
yn = sys.stdin.readline().strip() | |
print "" | |
if yn == "" or yn.lower().startswith('y'): | |
run = True | |
if run: | |
subprocess.call(["minicom", name]) | |
else: | |
print config | |
else: | |
print config | |
except KeyboardInterrupt: | |
pass | |
baud.Close() | |
main() |