12ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#!/usr/bin/env python2.6
22ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#
32ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Copyright (C) 2011 The Android Open Source Project
42ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#
52ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Licensed under the Apache License, Version 2.0 (the "License");
62ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# you may not use this file except in compliance with the License.
72ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# You may obtain a copy of the License at
82ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#
92ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#      http://www.apache.org/licenses/LICENSE-2.0
102ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#
112ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Unless required by applicable law or agreed to in writing, software
122ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# distributed under the License is distributed on an "AS IS" BASIS,
132ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
142ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# See the License for the specific language governing permissions and
152ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# limitations under the License.
162ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#
172ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
182ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#
192ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Plots debug log output from VelocityTracker.
202ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Enable DEBUG_VELOCITY to print the output.
212ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#
222ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# This code supports side-by-side comparison of two algorithms.
232ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# The old algorithm should be modified to emit debug log messages containing
242ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# the word "OLD".
252ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown#
262ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
272ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownimport numpy as np
282ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownimport matplotlib.pyplot as plot
292ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownimport subprocess
302ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownimport re
312ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownimport fcntl
322ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownimport os
332ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownimport errno
342ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownimport bisect
352ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownfrom datetime import datetime, timedelta
362ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
372ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Parameters.
382ed2462aa29c564f5231f317c27b3188da875e52Jeff Browntimespan = 15 # seconds total span shown
392ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownscrolljump = 5 # seconds jump when scrolling
402ed2462aa29c564f5231f317c27b3188da875e52Jeff Browntimeticks = 1 # seconds between each time tick
412ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
422ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Non-blocking stream wrapper.
432ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownclass NonBlockingStream:
442ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def __init__(self, stream):
452ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK)
462ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.stream = stream
472ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.buffer = ''
482ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.pos = 0
492ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
502ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def readline(self):
512ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    while True:
522ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      index = self.buffer.find('\n', self.pos)
532ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      if index != -1:
542ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        result = self.buffer[self.pos:index]
552ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.pos = index + 1
562ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        return result
572ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
582ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self.buffer = self.buffer[self.pos:]
592ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self.pos = 0
602ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      try:
612ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        chunk = os.read(self.stream.fileno(), 4096)
622ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      except OSError, e:
632ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        if e.errno == errno.EAGAIN:
642ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown          return None
652ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        raise e
662ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      if len(chunk) == 0:
672ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        if len(self.buffer) == 0:
682ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown          raise(EOFError)
692ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        else:
702ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown          result = self.buffer
712ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown          self.buffer = ''
722ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown          self.pos = 0
732ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown          return result
742ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self.buffer += chunk
752ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
762ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Plotter
772ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownclass Plotter:
782ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def __init__(self, adbout):
792ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.adbout = adbout
802ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
812ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.fig = plot.figure(1)
822ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.fig.suptitle('Velocity Tracker', fontsize=12)
832ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.fig.set_dpi(96)
842ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.fig.set_size_inches(16, 12, forward=True)
852ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
862ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_x = self._make_timeseries()
872ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_y = self._make_timeseries()
882ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_magnitude = self._make_timeseries()
892ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_axes = self._add_timeseries_axes(
902ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        1, 'Velocity', 'px/s', [-5000, 5000],
912ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        yticks=range(-5000, 5000, 1000))
922ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_line_x = self._add_timeseries_line(
932ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.velocity_axes, 'vx', 'red')
942ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_line_y = self._add_timeseries_line(
952ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.velocity_axes, 'vy', 'green')
962ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_line_magnitude = self._add_timeseries_line(
972ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.velocity_axes, 'magnitude', 'blue')
982ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self._add_timeseries_legend(self.velocity_axes)
992ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1002ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    shared_axis = self.velocity_axes
1012ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1022ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_x = self._make_timeseries()
1032ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_y = self._make_timeseries()
1042ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_magnitude = self._make_timeseries()
1052ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_axes = self._add_timeseries_axes(
1062ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        2, 'Old Algorithm Velocity', 'px/s', [-5000, 5000],
1072ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        sharex=shared_axis,
1082ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        yticks=range(-5000, 5000, 1000))
1092ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_line_x = self._add_timeseries_line(
1102ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.old_velocity_axes, 'vx', 'red')
1112ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_line_y = self._add_timeseries_line(
1122ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.old_velocity_axes, 'vy', 'green')
1132ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_line_magnitude = self._add_timeseries_line(
1142ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.old_velocity_axes, 'magnitude', 'blue')
1152ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self._add_timeseries_legend(self.old_velocity_axes)
1162ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1172ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.timer = self.fig.canvas.new_timer(interval=100)
1182ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.timer.add_callback(lambda: self.update())
1192ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.timer.start()
1202ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1212ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.timebase = None
1222ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self._reset_parse_state()
1232ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1242ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Initialize a time series.
1252ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _make_timeseries(self):
1262ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    return [[], []]
1272ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1282ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Add a subplot to the figure for a time series.
1292ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None):
1302ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    num_graphs = 2
1312ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    height = 0.9 / num_graphs
1322ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    top = 0.95 - height * index
1332ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    axes = self.fig.add_axes([0.1, top, 0.8, height],
1342ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        xscale='linear',
1352ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        xlim=[0, timespan],
1362ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        ylabel=ylabel,
1372ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        yscale='linear',
1382ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        ylim=ylim,
1392ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        sharex=sharex)
1402ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold')
1412ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    axes.set_xlabel('time (s)', fontsize=10, fontweight='bold')
1422ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    axes.set_ylabel(ylabel, fontsize=10, fontweight='bold')
1432ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    axes.set_xticks(range(0, timespan + 1, timeticks))
1442ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    axes.set_yticks(yticks)
1452ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    axes.grid(True)
1462ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1472ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    for label in axes.get_xticklabels():
1482ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      label.set_fontsize(9)
1492ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    for label in axes.get_yticklabels():
1502ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      label.set_fontsize(9)
1512ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1522ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    return axes
1532ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1542ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Add a line to the axes for a time series.
1552ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _add_timeseries_line(self, axes, label, color, linewidth=1):
1562ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    return axes.plot([], label=label, color=color, linewidth=linewidth)[0]
1572ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1582ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Add a legend to a time series.
1592ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _add_timeseries_legend(self, axes):
1602ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    axes.legend(
1612ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        loc='upper left',
1622ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        bbox_to_anchor=(1.01, 1),
1632ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        borderpad=0.1,
1642ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        borderaxespad=0.1,
1652ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        prop={'size': 10})
1662ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1672ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Resets the parse state.
1682ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _reset_parse_state(self):
1692ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.parse_velocity_x = None
1702ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.parse_velocity_y = None
1712ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.parse_velocity_magnitude = None
1722ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.parse_old_velocity_x = None
1732ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.parse_old_velocity_y = None
1742ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.parse_old_velocity_magnitude = None
1752ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1762ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Update samples.
1772ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def update(self):
1782ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    timeindex = 0
1792ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    while True:
1802ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      try:
1812ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        line = self.adbout.readline()
1822ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      except EOFError:
1832ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        plot.close()
1842ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        return
1852ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      if line is None:
1862ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        break
1872ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      print line
1882ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1892ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      try:
1902ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        timestamp = self._parse_timestamp(line)
1912ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      except ValueError, e:
1922ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        continue
1932ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      if self.timebase is None:
1942ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.timebase = timestamp
1952ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      delta = timestamp - self.timebase
1962ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      timeindex = delta.seconds + delta.microseconds * 0.000001
1972ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
1982ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      if line.find(': position') != -1:
1992ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.parse_velocity_x = self._get_following_number(line, 'vx=')
2002ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.parse_velocity_y = self._get_following_number(line, 'vy=')
2012ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.parse_velocity_magnitude = self._get_following_number(line, 'speed=')
2022ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self._append(self.velocity_x, timeindex, self.parse_velocity_x)
2032ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self._append(self.velocity_y, timeindex, self.parse_velocity_y)
2042ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self._append(self.velocity_magnitude, timeindex, self.parse_velocity_magnitude)
2052ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2062ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      if line.find(': OLD') != -1:
2072ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.parse_old_velocity_x = self._get_following_number(line, 'vx=')
2082ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.parse_old_velocity_y = self._get_following_number(line, 'vy=')
2092ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self.parse_old_velocity_magnitude = self._get_following_number(line, 'speed=')
2102ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self._append(self.old_velocity_x, timeindex, self.parse_old_velocity_x)
2112ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self._append(self.old_velocity_y, timeindex, self.parse_old_velocity_y)
2122ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown        self._append(self.old_velocity_magnitude, timeindex, self.parse_old_velocity_magnitude)
2132ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2142ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    # Scroll the plots.
2152ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    if timeindex > timespan:
2162ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      bottom = int(timeindex) - timespan + scrolljump
2172ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self.timebase += timedelta(seconds=bottom)
2182ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self._scroll(self.velocity_x, bottom)
2192ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self._scroll(self.velocity_y, bottom)
2202ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self._scroll(self.velocity_magnitude, bottom)
2212ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self._scroll(self.old_velocity_x, bottom)
2222ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self._scroll(self.old_velocity_y, bottom)
2232ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      self._scroll(self.old_velocity_magnitude, bottom)
2242ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2252ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    # Redraw the plots.
2262ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_line_x.set_data(self.velocity_x)
2272ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_line_y.set_data(self.velocity_y)
2282ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.velocity_line_magnitude.set_data(self.velocity_magnitude)
2292ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_line_x.set_data(self.old_velocity_x)
2302ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_line_y.set_data(self.old_velocity_y)
2312ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.old_velocity_line_magnitude.set_data(self.old_velocity_magnitude)
2322ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2332ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    self.fig.canvas.draw_idle()
2342ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2352ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Scroll a time series.
2362ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _scroll(self, timeseries, bottom):
2372ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    bottom_index = bisect.bisect_left(timeseries[0], bottom)
2382ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    del timeseries[0][:bottom_index]
2392ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    del timeseries[1][:bottom_index]
2402ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    for i, timeindex in enumerate(timeseries[0]):
2412ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      timeseries[0][i] = timeindex - bottom
2422ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2432ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Extract a word following the specified prefix.
2442ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _get_following_word(self, line, prefix):
2452ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    prefix_index = line.find(prefix)
2462ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    if prefix_index == -1:
2472ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      return None
2482ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    start_index = prefix_index + len(prefix)
2492ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    delim_index = line.find(',', start_index)
2502ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    if delim_index == -1:
2512ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      return line[start_index:]
2522ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    else:
2532ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      return line[start_index:delim_index]
2542ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2552ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Extract a number following the specified prefix.
2562ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _get_following_number(self, line, prefix):
2572ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    word = self._get_following_word(line, prefix)
2582ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    if word is None:
2592ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown      return None
2602ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    return float(word)
2612ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2622ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Add a value to a time series.
2632ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _append(self, timeseries, timeindex, number):
2642ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    timeseries[0].append(timeindex)
2652ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    timeseries[1].append(number)
2662ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2672ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Parse the logcat timestamp.
2682ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  # Timestamp has the form '01-21 20:42:42.930'
2692ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown  def _parse_timestamp(self, line):
2702ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f')
2712ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2722ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Notice
2732ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownprint "Velocity Tracker plotting tool"
2742ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownprint "-----------------------------------------\n"
2752ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownprint "Please enable debug logging and recompile the code."
2762ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2772ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Start adb.
2782ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownprint "Starting adb logcat.\n"
2792ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2802ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownadb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'Input:*', 'VelocityTracker:*'],
2812ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown    stdout=subprocess.PIPE)
2822ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownadbout = NonBlockingStream(adb.stdout)
2832ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2842ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Prepare plotter.
2852ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownplotter = Plotter(adbout)
2862ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownplotter.update()
2872ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
2882ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown# Main loop.
2892ed2462aa29c564f5231f317c27b3188da875e52Jeff Brownplot.show()
290