Extend tools/readserial.py to support serial port timing calibration.

Some serial ports have slightly different timing.  These timing
variations result in less accurate boot time reporting.  So, add a
calibration mechanism to the tool so that one can determine how much
time a specific machine's serial port uses.

Also, extend the main part of the tool to allow the user to specify
an exact timing parameter.
diff --git a/tools/readserial.py b/tools/readserial.py
index 9c955c6..d85392e 100755
--- a/tools/readserial.py
+++ b/tools/readserial.py
@@ -15,18 +15,48 @@
 
 # Reset time counter after this much idle time.
 RESTARTINTERVAL = 60
-# Alter timing reports based on how much time would be spent writing
-# to serial.
-ADJUSTBAUD = 1
 # Number of bits in a transmitted byte - 8N1 is 1 start bit + 8 data
 # bits + 1 stop bit.
 BITSPERBYTE = 10
 
-def readserial(infile, logfile, baudrate):
+def calibrateserialwrite(outfile, byteadjust):
+    # Build 4000 bytes of dummy data.
+    data = "0123456789" * 4 + "012345678" + "\n"
+    data = data * 80
+    while 1:
+        st = time.time()
+        outfile.write(data)
+        outfile.flush()
+        et = time.time()
+        sys.stdout.write(
+            "Wrote %d - %.1fus per char (theory states %.1fus)\n" % (
+                len(data), (et-st) / len(data) * 1000000, byteadjust * 1000000))
+        sys.stdout.flush()
+        time.sleep(3)
+
+def calibrateserialread(infile, byteadjust):
+    starttime = lasttime = 0
+    totalchars = 0
+    while 1:
+        select.select([infile], [], [])
+        d = infile.read(4096)
+        curtime = time.time()
+        if curtime - lasttime > 1.0:
+            if starttime and totalchars:
+                sys.stdout.write(
+                    "Calibrating on %d bytes - %.1fus per char"
+                    " (theory states %.1fus)\n" % (
+                        totalchars,
+                        float(lasttime - starttime) * 1000000 / totalchars,
+                        byteadjust * 1000000))
+            totalchars = 0
+            starttime = curtime
+        else:
+            totalchars += len(d)
+        lasttime = curtime
+
+def readserial(infile, logfile, byteadjust):
     lasttime = 0
-    byteadjust = 0.0
-    if ADJUSTBAUD:
-        byteadjust = float(BITSPERBYTE) / baudrate
     while 1:
         # Read data
         try:
@@ -52,8 +82,8 @@
             starttime = datatime
             charcount = 0
             isnewline = 1
-            msg = "\n\n======= %s (adjust=%d)\n" % (
-                time.asctime(time.localtime(datatime)), ADJUSTBAUD)
+            msg = "\n\n======= %s (adjust=%.1fus)\n" % (
+                time.asctime(time.localtime(datatime)), byteadjust * 1000000)
             sys.stdout.write(msg)
             logfile.write(msg)
         lasttime = datatime
@@ -97,6 +127,15 @@
     opts.add_option("-n", "--no-adjust",
                     action="store_false", dest="adjustbaud", default=True,
                     help="don't adjust times by serial rate")
+    opts.add_option("-c", "--calibrate-read",
+                    action="store_true", dest="calibrate_read", default=False,
+                    help="read from serial port to calibrate it")
+    opts.add_option("-C", "--calibrate-write",
+                    action="store_true", dest="calibrate_write", default=False,
+                    help="write to serial port to calibrate it")
+    opts.add_option("-t", "--time",
+                    type="float", dest="time", default=None,
+                    help="time to write one byte on serial port (in us)")
     options, args = opts.parse_args()
     serialport = 0
     baud = 115200
@@ -106,8 +145,11 @@
         serialport = args[0]
     if len(args) > 1:
         baud = int(args[1])
-    global ADJUSTBAUD
-    ADJUSTBAUD=options.adjustbaud
+    byteadjust = float(BITSPERBYTE) / baud
+    if options.time is not None:
+        byteadjust = options.time / 1000000.0
+    if not options.adjustbaud:
+        byteadjust = 0.0
 
     if options.serial:
         # Read from serial port
@@ -129,9 +171,16 @@
         fcntl.fcntl(ser, fcntl.F_SETFL
                     , fcntl.fcntl(ser, fcntl.F_GETFL) | os.O_NONBLOCK)
 
+    if options.calibrate_read:
+        calibrateserialread(ser, byteadjust)
+        return
+    if options.calibrate_write:
+        calibrateserialwrite(ser, byteadjust)
+        return
+
     logname = time.strftime("seriallog-%Y%m%d_%H%M%S.log")
     f = open(logname, 'wb')
-    readserial(ser, f, baud)
+    readserial(ser, f, byteadjust)
 
 if __name__ == '__main__':
     main()