| | #!/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() |
---|
| | |
---|
| | |