cliechti | 576de25 | 2002-02-28 23:54:44 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | #very simple serial terminal |
| 4 | #input characters are sent directly, received characters are displays as is |
| 5 | #baudrate and echo configuartion is done through globals: |
cliechti | 576de25 | 2002-02-28 23:54:44 +0000 | [diff] [blame] | 6 | |
| 7 | |
cliechti | 8b3ad39 | 2002-03-03 20:12:21 +0000 | [diff] [blame^] | 8 | import sys, os, serial, threading, getopt |
| 9 | #EXITCHARCTER = '\x1b' #ESC |
| 10 | EXITCHARCTER = '\x04' #ctrl+d |
cliechti | 576de25 | 2002-02-28 23:54:44 +0000 | [diff] [blame] | 11 | |
| 12 | #first choosea platform dependant way to read single characters from the console |
| 13 | if os.name == 'nt': #sys.platform == 'win32': |
| 14 | import msvcrt |
| 15 | def getkey(): |
| 16 | while 1: |
| 17 | if echo: |
| 18 | z = msvcrt.getche() |
| 19 | else: |
| 20 | z = msvcrt.getch() |
| 21 | if z == '\0' or z == '\xe0': #functions keys |
| 22 | msvcrt.getch() |
| 23 | else: |
| 24 | return z |
| 25 | |
| 26 | elif os.name == 'posix': |
| 27 | #XXX: Untested code drrived from the Python FAQ.... |
| 28 | import termios, TERMIOS, sys, os |
| 29 | fd = sys.stdin.fileno() |
| 30 | old = termios.tcgetattr(fd) |
| 31 | new = termios.tcgetattr(fd) |
| 32 | new[3] = new[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO |
| 33 | new[6][TERMIOS.VMIN] = 1 |
| 34 | new[6][TERMIOS.VTIME] = 0 |
| 35 | termios.tcsetattr(fd, TERMIOS.TCSANOW, new) |
| 36 | s = '' # We'll save the characters typed and add them to the pool. |
| 37 | def getkey(): |
| 38 | c = os.read(fd, 1) |
| 39 | if echo: sys.stdout.write(c) |
| 40 | return c |
| 41 | def clenaup_console(): |
| 42 | termios.tcsetattr(fd, TERMIOS.TCSAFLUSH, old) |
| 43 | sys.exitfunc = clenaup_console #terminal modes have to be restored on exit... |
| 44 | |
| 45 | else: |
| 46 | raise "Sorry no implementation for your platform (%s) available." % sys.platform |
| 47 | |
| 48 | |
cliechti | 576de25 | 2002-02-28 23:54:44 +0000 | [diff] [blame] | 49 | def reader(): |
| 50 | """loop forever and copy serial->console""" |
| 51 | while 1: |
| 52 | sys.stdout.write(s.read()) |
| 53 | |
| 54 | def writer(): |
| 55 | """loop forever and copy console->serial""" |
| 56 | while 1: |
| 57 | c = getkey() |
cliechti | 8b3ad39 | 2002-03-03 20:12:21 +0000 | [diff] [blame^] | 58 | if c == EXITCHARCTER: break #exit on esc |
cliechti | 576de25 | 2002-02-28 23:54:44 +0000 | [diff] [blame] | 59 | s.write(c) #send character |
| 60 | if convert_outgoing_cr and c == '\r': |
| 61 | s.write('\n') |
| 62 | if echo: sys.stdout.write('\n') |
| 63 | |
cliechti | 576de25 | 2002-02-28 23:54:44 +0000 | [diff] [blame] | 64 | |
cliechti | 8b3ad39 | 2002-03-03 20:12:21 +0000 | [diff] [blame^] | 65 | #print a short help message |
| 66 | def usage(): |
| 67 | print >>sys.stderr, """USAGE: %s [options] |
| 68 | Simple Terminal Programm for the serial port. |
| 69 | |
| 70 | options: |
| 71 | -p, --port=PORT: port, a number, defualt = 0 or a device name |
| 72 | -b, --baud=BAUD: baudrate, default 9600 |
| 73 | -r, --rtscts: enable RTS/CTS flow control (default off) |
| 74 | -x, --xonxoff: enable software flow control (default off) |
| 75 | -e, --echo: enable local echo (default off) |
| 76 | -c, --cr: disable CR -> CR+LF translation |
| 77 | |
| 78 | """ % sys.argv[0] |
| 79 | |
| 80 | if __name__ == '__main__': |
| 81 | #parse command line options |
| 82 | try: |
| 83 | opts, args = getopt.getopt(sys.argv[1:], |
| 84 | "hp:b:rxec", |
| 85 | ["help", "port=", "baud=", "rtscts", "xonxoff", "echo", "cr"]) |
| 86 | except getopt.GetoptError: |
| 87 | # print help information and exit: |
| 88 | usage() |
| 89 | sys.exit(2) |
| 90 | |
| 91 | port = 0 |
| 92 | baudrate = 9600 |
| 93 | echo = 0 |
| 94 | convert_outgoing_cr = 1 |
| 95 | rtscts = 0 |
| 96 | xonxoff = 0 |
| 97 | for o, a in opts: |
| 98 | if o in ("-h", "--help"): #help text |
| 99 | usage() |
| 100 | sys.exit() |
| 101 | elif o in ("-p", "--port"): #specified port |
| 102 | try: |
| 103 | port = int(a) |
| 104 | except ValueError: |
| 105 | port = a |
| 106 | elif o in ("-b", "--baud"): #specified baudrate |
| 107 | try: |
| 108 | baudrate = int(a) |
| 109 | except ValueError: |
| 110 | raise ValueError, "Baudrate must be a integer number" |
| 111 | elif o in ("-r", "--rtscts"): |
| 112 | rtscts = 1 |
| 113 | elif o in ("-x", "--xonxoff"): |
| 114 | xonxoff = 1 |
| 115 | elif o in ("-e", "--echo"): |
| 116 | echo = 1 |
| 117 | elif o in ("-c", "--cr"): |
| 118 | convert_outgoing_cr = 0 |
| 119 | |
| 120 | try: |
| 121 | s = serial.Serial(port, baudrate, rtscts=rtscts, xonxoff=xonxoff) |
| 122 | except: |
| 123 | print "could not open port" |
| 124 | sys.exit(1) |
| 125 | print "--- Miniterm --- type Ctrl-D to quit" |
| 126 | #start serial->console thread |
| 127 | r = threading.Thread(target=reader) |
| 128 | r.setDaemon(1) |
| 129 | r.start() |
| 130 | #enter console->serial loop |
| 131 | writer() |
| 132 | |
| 133 | print "\n--- exit ---" |