blob: a7383e835ef062b71c15684b8d10fd9a1acf4ce2 [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
Kevin O'Connor999567f2014-12-31 00:18:05 -050011import sys, os, time, select, optparse
Kevin O'Connor2547bb82009-04-19 11:04:59 -040012
Johannes Krampf19f789b2014-01-19 16:03:49 +010013from python23compat import as_bytes
14
Kevin O'Connor2547bb82009-04-19 11:04:59 -040015# Reset time counter after this much idle time.
16RESTARTINTERVAL = 60
Kevin O'Connor77443202009-12-05 14:23:27 -050017# Number of bits in a transmitted byte - 8N1 is 1 start bit + 8 data
18# bits + 1 stop bit.
19BITSPERBYTE = 10
Kevin O'Connor2547bb82009-04-19 11:04:59 -040020
Kevin O'Connor8365dee2011-07-09 13:16:24 -040021def calibrateserialwrite(outfile, byteadjust):
22 # Build 4000 bytes of dummy data.
23 data = "0123456789" * 4 + "012345678" + "\n"
24 data = data * 80
25 while 1:
26 st = time.time()
Johannes Krampf19f789b2014-01-19 16:03:49 +010027 outfile.write(as_bytes(data))
Kevin O'Connor8365dee2011-07-09 13:16:24 -040028 outfile.flush()
29 et = time.time()
30 sys.stdout.write(
31 "Wrote %d - %.1fus per char (theory states %.1fus)\n" % (
32 len(data), (et-st) / len(data) * 1000000, byteadjust * 1000000))
33 sys.stdout.flush()
34 time.sleep(3)
35
36def calibrateserialread(infile, byteadjust):
37 starttime = lasttime = 0
38 totalchars = 0
39 while 1:
40 select.select([infile], [], [])
41 d = infile.read(4096)
42 curtime = time.time()
43 if curtime - lasttime > 1.0:
44 if starttime and totalchars:
45 sys.stdout.write(
46 "Calibrating on %d bytes - %.1fus per char"
47 " (theory states %.1fus)\n" % (
48 totalchars,
49 float(lasttime - starttime) * 1000000 / totalchars,
50 byteadjust * 1000000))
51 totalchars = 0
52 starttime = curtime
53 else:
54 totalchars += len(d)
55 lasttime = curtime
56
57def readserial(infile, logfile, byteadjust):
Kevin O'Connora1dadf42009-04-26 21:24:16 -040058 lasttime = 0
Kevin O'Connor2547bb82009-04-19 11:04:59 -040059 while 1:
60 # Read data
61 try:
62 res = select.select([infile, sys.stdin], [], [])
63 except KeyboardInterrupt:
64 sys.stdout.write("\n")
Kevin O'Connor999567f2014-12-31 00:18:05 -050065 return -1
Kevin O'Connor2547bb82009-04-19 11:04:59 -040066 if sys.stdin in res[0]:
67 # Got keyboard input - force reset on next serial input
68 sys.stdin.read(1)
Kevin O'Connora1dadf42009-04-26 21:24:16 -040069 lasttime = 0
Kevin O'Connor2547bb82009-04-19 11:04:59 -040070 if len(res[0]) == 1:
71 continue
Kevin O'Connor2547bb82009-04-19 11:04:59 -040072 d = infile.read(4096)
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -040073 if not d:
Kevin O'Connor999567f2014-12-31 00:18:05 -050074 return 0
Kevin O'Connor58db9c42009-12-12 13:28:38 -050075 datatime = time.time()
76
77 datatime -= len(d) * byteadjust
Kevin O'Connor2547bb82009-04-19 11:04:59 -040078
79 # Reset start time if no data for some time
Kevin O'Connor58db9c42009-12-12 13:28:38 -050080 if datatime - lasttime > RESTARTINTERVAL:
81 starttime = datatime
Kevin O'Connor2547bb82009-04-19 11:04:59 -040082 charcount = 0
83 isnewline = 1
Kevin O'Connor8365dee2011-07-09 13:16:24 -040084 msg = "\n\n======= %s (adjust=%.1fus)\n" % (
85 time.asctime(time.localtime(datatime)), byteadjust * 1000000)
Kevin O'Connora53ab002009-12-05 13:44:39 -050086 sys.stdout.write(msg)
Johannes Krampf19f789b2014-01-19 16:03:49 +010087 logfile.write(as_bytes(msg))
Kevin O'Connor58db9c42009-12-12 13:28:38 -050088 lasttime = datatime
Kevin O'Connor2547bb82009-04-19 11:04:59 -040089
90 # Translate unprintable chars; add timestamps
Johannes Krampf19f789b2014-01-19 16:03:49 +010091 out = as_bytes("")
Kevin O'Connor2547bb82009-04-19 11:04:59 -040092 for c in d:
93 if isnewline:
Kevin O'Connor58db9c42009-12-12 13:28:38 -050094 delta = datatime - starttime - (charcount * byteadjust)
Kevin O'Connor2547bb82009-04-19 11:04:59 -040095 out += "%06.3f: " % delta
96 isnewline = 0
97 oc = ord(c)
98 charcount += 1
Kevin O'Connor58db9c42009-12-12 13:28:38 -050099 datatime += byteadjust
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400100 if oc == 0x0d:
101 continue
102 if oc == 0x00:
103 out += "<00>\n"
104 isnewline = 1
105 continue
106 if oc == 0x0a:
107 out += "\n"
108 isnewline = 1
109 continue
110 if oc < 0x20 or oc >= 0x7f and oc != 0x09:
111 out += "<%02x>" % oc
112 continue
113 out += c
114
Johannes Krampf19f789b2014-01-19 16:03:49 +0100115 if (sys.version_info > (3, 0)):
116 sys.stdout.buffer.write(out)
117 else:
118 sys.stdout.write(out)
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400119 sys.stdout.flush()
120 logfile.write(out)
121 logfile.flush()
122
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400123def main():
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400124 usage = "%prog [options] [<serialdevice> [<baud>]]"
125 opts = optparse.OptionParser(usage)
126 opts.add_option("-f", "--file",
127 action="store_false", dest="serial", default=True,
Kevin O'Connor999567f2014-12-31 00:18:05 -0500128 help="read from unix named pipe instead of serialdevice")
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400129 opts.add_option("-n", "--no-adjust",
130 action="store_false", dest="adjustbaud", default=True,
131 help="don't adjust times by serial rate")
Kevin O'Connor8365dee2011-07-09 13:16:24 -0400132 opts.add_option("-c", "--calibrate-read",
133 action="store_true", dest="calibrate_read", default=False,
134 help="read from serial port to calibrate it")
135 opts.add_option("-C", "--calibrate-write",
136 action="store_true", dest="calibrate_write", default=False,
137 help="write to serial port to calibrate it")
138 opts.add_option("-t", "--time",
139 type="float", dest="time", default=None,
140 help="time to write one byte on serial port (in us)")
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400141 options, args = opts.parse_args()
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400142 serialport = 0
143 baud = 115200
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400144 if len(args) > 2:
145 opts.error("Too many arguments")
146 if len(args) > 0:
147 serialport = args[0]
148 if len(args) > 1:
149 baud = int(args[1])
Kevin O'Connor8365dee2011-07-09 13:16:24 -0400150 byteadjust = float(BITSPERBYTE) / baud
151 if options.time is not None:
152 byteadjust = options.time / 1000000.0
153 if not options.adjustbaud:
154 byteadjust = 0.0
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400155
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400156 if options.serial:
157 # Read from serial port
Kevin O'Connor94330982010-10-17 21:38:38 -0400158 try:
159 import serial
160 except ImportError:
Johannes Krampf064fd062014-01-12 11:14:54 -0500161 print("""
Kevin O'Connor94330982010-10-17 21:38:38 -0400162Unable to find pyserial package ( http://pyserial.sourceforge.net/ ).
163On Linux machines try: yum install pyserial
164Or: apt-get install python-serial
Johannes Krampf064fd062014-01-12 11:14:54 -0500165""")
Kevin O'Connor94330982010-10-17 21:38:38 -0400166 sys.exit(1)
Kevin O'Connor2dcd9fa2010-08-28 14:55:32 -0400167 ser = serial.Serial(serialport, baud, timeout=0)
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400168
Kevin O'Connor8365dee2011-07-09 13:16:24 -0400169 if options.calibrate_read:
170 calibrateserialread(ser, byteadjust)
171 return
172 if options.calibrate_write:
173 calibrateserialwrite(ser, byteadjust)
174 return
175
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400176 logname = time.strftime("seriallog-%Y%m%d_%H%M%S.log")
177 f = open(logname, 'wb')
Kevin O'Connor999567f2014-12-31 00:18:05 -0500178 if options.serial:
179 readserial(ser, f, byteadjust)
180 else:
181 # Read from a pipe
182 while 1:
183 ser = os.fdopen(os.open(serialport, os.O_RDONLY|os.O_NONBLOCK), 'rb')
184 res = readserial(ser, f, byteadjust)
185 ser.close()
186 if res < 0:
187 break
Kevin O'Connor2547bb82009-04-19 11:04:59 -0400188
189if __name__ == '__main__':
190 main()