grml...
[seabios.git] / tools / readserial.py
1 #!/usr/bin/env python
2 # Script that can read from a serial device and show timestamps.
3 #
4 # Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
5 #
6 # This file may be distributed under the terms of the GNU GPLv3 license.
7
8 # Usage:
9 #   tools/readserial.py /dev/ttyUSB0 115200
10
11 import sys
12 import time
13 import select
14 import optparse
15
16 # Reset time counter after this much idle time.
17 RESTARTINTERVAL = 60
18 # Number of bits in a transmitted byte - 8N1 is 1 start bit + 8 data
19 # bits + 1 stop bit.
20 BITSPERBYTE = 10
21
22 def calibrateserialwrite(outfile, byteadjust):
23     # Build 4000 bytes of dummy data.
24     data = "0123456789" * 4 + "012345678" + "\n"
25     data = data * 80
26     while 1:
27         st = time.time()
28         outfile.write(data)
29         outfile.flush()
30         et = time.time()
31         sys.stdout.write(
32             "Wrote %d - %.1fus per char (theory states %.1fus)\n" % (
33                 len(data), (et-st) / len(data) * 1000000, byteadjust * 1000000))
34         sys.stdout.flush()
35         time.sleep(3)
36
37 def calibrateserialread(infile, byteadjust):
38     starttime = lasttime = 0
39     totalchars = 0
40     while 1:
41         select.select([infile], [], [])
42         d = infile.read(4096)
43         curtime = time.time()
44         if curtime - lasttime > 1.0:
45             if starttime and totalchars:
46                 sys.stdout.write(
47                     "Calibrating on %d bytes - %.1fus per char"
48                     " (theory states %.1fus)\n" % (
49                         totalchars,
50                         float(lasttime - starttime) * 1000000 / totalchars,
51                         byteadjust * 1000000))
52             totalchars = 0
53             starttime = curtime
54         else:
55             totalchars += len(d)
56         lasttime = curtime
57
58 def readserial(infile, logfile, byteadjust):
59     lasttime = 0
60     while 1:
61         # Read data
62         try:
63             res = select.select([infile, sys.stdin], [], [])
64         except KeyboardInterrupt:
65             sys.stdout.write("\n")
66             break
67         if sys.stdin in res[0]:
68             # Got keyboard input - force reset on next serial input
69             sys.stdin.read(1)
70             lasttime = 0
71             if len(res[0]) == 1:
72                 continue
73         d = infile.read(4096)
74         if not d:
75             break
76         datatime = time.time()
77
78         datatime -= len(d) * byteadjust
79
80         # Reset start time if no data for some time
81         if datatime - lasttime > RESTARTINTERVAL:
82             starttime = datatime
83             charcount = 0
84             isnewline = 1
85             msg = "\n\n======= %s (adjust=%.1fus)\n" % (
86                 time.asctime(time.localtime(datatime)), byteadjust * 1000000)
87             sys.stdout.write(msg)
88             logfile.write(msg)
89         lasttime = datatime
90
91         # Translate unprintable chars; add timestamps
92         out = ""
93         for c in d:
94             if isnewline:
95                 delta = datatime - starttime - (charcount * byteadjust)
96                 out += "%06.3f: " % delta
97                 isnewline = 0
98             oc = ord(c)
99             charcount += 1
100             datatime += byteadjust
101             if oc == 0x0d:
102                 continue
103             if oc == 0x00:
104                 out += "<00>\n"
105                 isnewline = 1
106                 continue
107             if oc == 0x0a:
108                 out += "\n"
109                 isnewline = 1
110                 continue
111             if oc < 0x20 or oc >= 0x7f and oc != 0x09:
112                 out += "<%02x>" % oc
113                 continue
114             out += c
115
116         sys.stdout.write(out)
117         sys.stdout.flush()
118         logfile.write(out)
119         logfile.flush()
120
121 def main():
122     usage = "%prog [options] [<serialdevice> [<baud>]]"
123     opts = optparse.OptionParser(usage)
124     opts.add_option("-f", "--file",
125                     action="store_false", dest="serial", default=True,
126                     help="read from file instead of serialdevice")
127     opts.add_option("-n", "--no-adjust",
128                     action="store_false", dest="adjustbaud", default=True,
129                     help="don't adjust times by serial rate")
130     opts.add_option("-c", "--calibrate-read",
131                     action="store_true", dest="calibrate_read", default=False,
132                     help="read from serial port to calibrate it")
133     opts.add_option("-C", "--calibrate-write",
134                     action="store_true", dest="calibrate_write", default=False,
135                     help="write to serial port to calibrate it")
136     opts.add_option("-t", "--time",
137                     type="float", dest="time", default=None,
138                     help="time to write one byte on serial port (in us)")
139     options, args = opts.parse_args()
140     serialport = 0
141     baud = 115200
142     if len(args) > 2:
143         opts.error("Too many arguments")
144     if len(args) > 0:
145         serialport = args[0]
146     if len(args) > 1:
147         baud = int(args[1])
148     byteadjust = float(BITSPERBYTE) / baud
149     if options.time is not None:
150         byteadjust = options.time / 1000000.0
151     if not options.adjustbaud:
152         byteadjust = 0.0
153
154     if options.serial:
155         # Read from serial port
156         try:
157             import serial
158         except ImportError:
159             print """
160 Unable to find pyserial package ( http://pyserial.sourceforge.net/ ).
161 On Linux machines try: yum install pyserial
162 Or: apt-get install python-serial
163 """
164             sys.exit(1)
165         ser = serial.Serial(serialport, baud, timeout=0)
166     else:
167         # Read from a file
168         ser = open(serialport, 'rb')
169         import fcntl
170         import os
171         fcntl.fcntl(ser, fcntl.F_SETFL
172                     , fcntl.fcntl(ser, fcntl.F_GETFL) | os.O_NONBLOCK)
173
174     if options.calibrate_read:
175         calibrateserialread(ser, byteadjust)
176         return
177     if options.calibrate_write:
178         calibrateserialwrite(ser, byteadjust)
179         return
180
181     logname = time.strftime("seriallog-%Y%m%d_%H%M%S.log")
182     f = open(logname, 'wb')
183     readserial(ser, f, byteadjust)
184
185 if __name__ == '__main__':
186     main()