diff --git a/baudrate.py b/baudrate.py new file mode 100755 index 0000000..e8f7667 --- /dev/null +++ b/baudrate.py @@ -0,0 +1,324 @@ +#!/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 Specify the serial port to use [/dev/ttyUSB0]" + print "\t-t Set the timeout period used when switching baudrates in auto detect mode [%d]" % baud.READ_TIMEOUT + print "\t-c Set the minimum ASCII character threshold used during auto detect mode [%d]" % baud.MIN_CHAR_COUNT + print "\t-n Save the resulting serial configuration as 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()