blob: 3333e843a1c85486cccc5cac41986210dd2904ae [file] [log] [blame]
Kevin O'Connor2547bb82009-04-19 11:04:59 -04001#!/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:
Kevin O'Connorffc06872014-06-11 15:40:04 -04009# scripts/readserial.py /dev/ttyUSB0 115200
Kevin O'Connor2547bb82009-04-19 11:04:59 -040010
11import sys
12import time
13import select
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -040014import optparse
Kevin O'Connor2547bb82009-04-19 11:04:59 -040015
Johannes Krampf19f789b2014-01-19 16:03:49 +010016from python23compat import as_bytes
17
Kevin O'Connor2547bb82009-04-19 11:04:59 -040018# Reset time counter after this much idle time.
19RESTARTINTERVAL = 60
Kevin O'Connor77443202009-12-05 14:23:27 -050020# Number of bits in a transmitted byte - 8N1 is 1 start bit + 8 data
21# bits + 1 stop bit.
22BITSPERBYTE = 10
Kevin O'Connor2547bb82009-04-19 11:04:59 -040023
Kevin O'Connor8365dee2011-07-09 13:16:24 -040024def calibrateserialwrite(outfile, byteadjust):
25 # Build 4000 bytes of dummy data.
26 data = "0123456789" * 4 + "012345678" + "\n"
27 data = data * 80
28 while 1:
29 st = time.time()
Johannes Krampf19f789b2014-01-19 16:03:49 +010030 outfile.write(as_bytes(data))
Kevin O'Connor8365dee2011-07-09 13:16:24 -040031 outfile.flush()
32 et = time.time()
33 sys.stdout.write(
34 "Wrote %d - %.1fus per char (theory states %.1fus)\n" % (
35 len(data), (et-st) / len(data) * 1000000, byteadjust * 1000000))
36 sys.stdout.flush()
37 time.sleep(3)
38
39def calibrateserialread(infile, byteadjust):
40 starttime = lasttime = 0
41 totalchars = 0
42 while 1:
43 select.select([infile], [], [])
44 d = infile.read(4096)
45 curtime = time.time()
46 if curtime - lasttime > 1.0:
47 if starttime and totalchars:
48 sys.stdout.write(
49 "Calibrating on %d bytes - %.1fus per char"
50 " (theory states %.1fus)\n" % (
51 totalchars,
52 float(lasttime - starttime) * 1000000 / totalchars,
53 byteadjust * 1000000))
54 totalchars = 0
55 starttime = curtime
56 else:
57 totalchars += len(d)
58 lasttime = curtime
59
60def readserial(infile, logfile, byteadjust):
Kevin O'Connora1dadf42009-04-26 21:24:16 -040061 lasttime = 0
Kevin O'Connor2547bb82009-04-19 11:04:59 -040062 while 1:
63 # Read data
64 try:
65 res = select.select([infile, sys.stdin], [], [])
66 except KeyboardInterrupt:
67 sys.stdout.write("\n")
68 break
69 if sys.stdin in res[0]:
70 # Got keyboard input - force reset on next serial input
71 sys.stdin.read(1)
Kevin O'Connora1dadf42009-04-26 21:24:16 -040072 lasttime = 0
Kevin O'Connor2547bb82009-04-19 11:04:59 -040073 if len(res[0]) == 1:
74 continue
Kevin O'Connor2547bb82009-04-19 11:04:59 -040075 d = infile.read(4096)
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -040076 if not d:
77 break
Kevin O'Connor58db9c42009-12-12 13:28:38 -050078 datatime = time.time()
79
80 datatime -= len(d) * byteadjust
Kevin O'Connor2547bb82009-04-19 11:04:59 -040081
82 # Reset start time if no data for some time
Kevin O'Connor58db9c42009-12-12 13:28:38 -050083 if datatime - lasttime > RESTARTINTERVAL:
84 starttime = datatime
Kevin O'Connor2547bb82009-04-19 11:04:59 -040085 charcount = 0
86 isnewline = 1
Kevin O'Connor8365dee2011-07-09 13:16:24 -040087 msg = "\n\n======= %s (adjust=%.1fus)\n" % (
88 time.asctime(time.localtime(datatime)), byteadjust * 1000000)
Kevin O'Connora53ab002009-12-05 13:44:39 -050089 sys.stdout.write(msg)
Johannes Krampf19f789b2014-01-19 16:03:49 +010090 logfile.write(as_bytes(msg))
Kevin O'Connor58db9c42009-12-12 13:28:38 -050091 lasttime = datatime
Kevin O'Connor2547bb82009-04-19 11:04:59 -040092
93 # Translate unprintable chars; add timestamps
Johannes Krampf19f789b2014-01-19 16:03:49 +010094 out = as_bytes("")
Kevin O'Connor2547bb82009-04-19 11:04:59 -040095 for c in d:
96 if isnewline:
Kevin O'Connor58db9c42009-12-12 13:28:38 -050097 delta = datatime - starttime - (charcount * byteadjust)
Kevin O'Connor2547bb82009-04-19 11:04:59 -040098 out += "%06.3f: " % delta
99 isnewline = 0
100 oc = ord(c)
101 charcount += 1
Kevin O'Connor58db9c42009-12-12 13:28:38 -0500102 datatime += byteadjust
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400103 if oc == 0x0d:
104 continue
105 if oc == 0x00:
106 out += "<00>\n"
107 isnewline = 1
108 continue
109 if oc == 0x0a:
110 out += "\n"
111 isnewline = 1
112 continue
113 if oc < 0x20 or oc >= 0x7f and oc != 0x09:
114 out += "<%02x>" % oc
115 continue
116 out += c
117
Johannes Krampf19f789b2014-01-19 16:03:49 +0100118 if (sys.version_info > (3, 0)):
119 sys.stdout.buffer.write(out)
120 else:
121 sys.stdout.write(out)
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400122 sys.stdout.flush()
123 logfile.write(out)
124 logfile.flush()
125
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400126def main():
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400127 usage = "%prog [options] [<serialdevice> [<baud>]]"
128 opts = optparse.OptionParser(usage)
129 opts.add_option("-f", "--file",
130 action="store_false", dest="serial", default=True,
131 help="read from file instead of serialdevice")
132 opts.add_option("-n", "--no-adjust",
133 action="store_false", dest="adjustbaud", default=True,
134 help="don't adjust times by serial rate")
Kevin O'Connor8365dee2011-07-09 13:16:24 -0400135 opts.add_option("-c", "--calibrate-read",
136 action="store_true", dest="calibrate_read", default=False,
137 help="read from serial port to calibrate it")
138 opts.add_option("-C", "--calibrate-write",
139 action="store_true", dest="calibrate_write", default=False,
140 help="write to serial port to calibrate it")
141 opts.add_option("-t", "--time",
142 type="float", dest="time", default=None,
143 help="time to write one byte on serial port (in us)")
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400144 options, args = opts.parse_args()
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400145 serialport = 0
146 baud = 115200
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400147 if len(args) > 2:
148 opts.error("Too many arguments")
149 if len(args) > 0:
150 serialport = args[0]
151 if len(args) > 1:
152 baud = int(args[1])
Kevin O'Connor8365dee2011-07-09 13:16:24 -0400153 byteadjust = float(BITSPERBYTE) / baud
154 if options.time is not None:
155 byteadjust = options.time / 1000000.0
156 if not options.adjustbaud:
157 byteadjust = 0.0
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400158
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400159 if options.serial:
160 # Read from serial port
Kevin O'Connor94330982010-10-17 21:38:38 -0400161 try:
162 import serial
163 except ImportError:
Johannes Krampf064fd062014-01-12 11:14:54 -0500164 print("""
Kevin O'Connor94330982010-10-17 21:38:38 -0400165Unable to find pyserial package ( http://pyserial.sourceforge.net/ ).
166On Linux machines try: yum install pyserial
167Or: apt-get install python-serial
Johannes Krampf064fd062014-01-12 11:14:54 -0500168""")
Kevin O'Connor94330982010-10-17 21:38:38 -0400169 sys.exit(1)
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400170 ser = serial.Serial(serialport, baud, timeout=0)
171 else:
172 # Read from a file
173 ser = open(serialport, 'rb')
174 import fcntl
175 import os
176 fcntl.fcntl(ser, fcntl.F_SETFL
177 , fcntl.fcntl(ser, fcntl.F_GETFL) | os.O_NONBLOCK)
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400178
Kevin O'Connor8365dee2011-07-09 13:16:24 -0400179 if options.calibrate_read:
180 calibrateserialread(ser, byteadjust)
181 return
182 if options.calibrate_write:
183 calibrateserialwrite(ser, byteadjust)
184 return
185
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400186 logname = time.strftime("seriallog-%Y%m%d_%H%M%S.log")
187 f = open(logname, 'wb')
Kevin O'Connor8365dee2011-07-09 13:16:24 -0400188 readserial(ser, f, byteadjust)
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400189
190if __name__ == '__main__':
191 main()