14519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#!/usr/bin/env python2.6
24519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#
34519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Copyright (C) 2011 The Android Open Source Project
44519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#
54519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Licensed under the Apache License, Version 2.0 (the "License");
64519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# you may not use this file except in compliance with the License.
74519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# You may obtain a copy of the License at
84519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#
94519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#      http://www.apache.org/licenses/LICENSE-2.0
104519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#
114519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Unless required by applicable law or agreed to in writing, software
124519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# distributed under the License is distributed on an "AS IS" BASIS,
134519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# See the License for the specific language governing permissions and
154519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# limitations under the License.
164519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#
174519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
184519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#
194519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Plots debug log output from WindowOrientationListener.
204519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# See README.txt for details.
214519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown#
224519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
234519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownimport numpy as np
244519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownimport matplotlib.pyplot as plot
254519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownimport subprocess
264519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownimport re
274519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownimport fcntl
284519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownimport os
294519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownimport errno
304519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownimport bisect
314519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownfrom datetime import datetime, timedelta
324519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
334519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Parameters.
344519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Browntimespan = 15 # seconds total span shown
354519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownscrolljump = 5 # seconds jump when scrolling
364519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Browntimeticks = 1 # seconds between each time tick
374519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
384519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Non-blocking stream wrapper.
394519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownclass NonBlockingStream:
404519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def __init__(self, stream):
414519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK)
424519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.stream = stream
434519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.buffer = ''
444519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.pos = 0
454519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
464519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def readline(self):
474519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    while True:
484519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      index = self.buffer.find('\n', self.pos)
494519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if index != -1:
504519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        result = self.buffer[self.pos:index]
514519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.pos = index + 1
524519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        return result
534519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
544519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self.buffer = self.buffer[self.pos:]
554519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self.pos = 0
564519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      try:
574519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        chunk = os.read(self.stream.fileno(), 4096)
584519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      except OSError, e:
594519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        if e.errno == errno.EAGAIN:
604519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown          return None
614519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        raise e
624519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if len(chunk) == 0:
634519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        if len(self.buffer) == 0:
644519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown          raise(EOFError)
654519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        else:
664519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown          result = self.buffer
674519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown          self.buffer = ''
684519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown          self.pos = 0
694519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown          return result
704519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self.buffer += chunk
714519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
724519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Plotter
734519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownclass Plotter:
744519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def __init__(self, adbout):
754519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.adbout = adbout
764519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
774519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.fig = plot.figure(1)
784519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.fig.suptitle('Window Orientation Listener', fontsize=12)
794519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.fig.set_dpi(96)
804519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.fig.set_size_inches(16, 12, forward=True)
814519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
824519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_x = self._make_timeseries()
834519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_y = self._make_timeseries()
844519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_z = self._make_timeseries()
855aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.raw_acceleration_magnitude = self._make_timeseries()
864519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_axes = self._add_timeseries_axes(
874519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        1, 'Raw Acceleration', 'm/s^2', [-20, 20],
884519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        yticks=range(-15, 16, 5))
894519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_line_x = self._add_timeseries_line(
904519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.raw_acceleration_axes, 'x', 'red')
914519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_line_y = self._add_timeseries_line(
924519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.raw_acceleration_axes, 'y', 'green')
934519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_line_z = self._add_timeseries_line(
944519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.raw_acceleration_axes, 'z', 'blue')
955aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.raw_acceleration_line_magnitude = self._add_timeseries_line(
965aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.raw_acceleration_axes, 'magnitude', 'orange', linewidth=2)
974519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self._add_timeseries_legend(self.raw_acceleration_axes)
984519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
994519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    shared_axis = self.raw_acceleration_axes
1004519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
1014519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_x = self._make_timeseries()
1024519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_y = self._make_timeseries()
1034519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_z = self._make_timeseries()
1045aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.filtered_acceleration_magnitude = self._make_timeseries()
1054519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_axes = self._add_timeseries_axes(
1064519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        2, 'Filtered Acceleration', 'm/s^2', [-20, 20],
1074519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        sharex=shared_axis,
1084519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        yticks=range(-15, 16, 5))
1094519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_line_x = self._add_timeseries_line(
1104519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.filtered_acceleration_axes, 'x', 'red')
1114519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_line_y = self._add_timeseries_line(
1124519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.filtered_acceleration_axes, 'y', 'green')
1134519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_line_z = self._add_timeseries_line(
1144519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.filtered_acceleration_axes, 'z', 'blue')
1155aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.filtered_acceleration_line_magnitude = self._add_timeseries_line(
1164519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.filtered_acceleration_axes, 'magnitude', 'orange', linewidth=2)
1174519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self._add_timeseries_legend(self.filtered_acceleration_axes)
1184519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
1194519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.tilt_angle = self._make_timeseries()
1204519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.tilt_angle_axes = self._add_timeseries_axes(
1214519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        3, 'Tilt Angle', 'degrees', [-105, 105],
1224519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        sharex=shared_axis,
1234519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        yticks=range(-90, 91, 30))
1244519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.tilt_angle_line = self._add_timeseries_line(
1254519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.tilt_angle_axes, 'tilt', 'black')
1264519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self._add_timeseries_legend(self.tilt_angle_axes)
1274519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
1284519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.orientation_angle = self._make_timeseries()
1294519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.orientation_angle_axes = self._add_timeseries_axes(
1304519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        4, 'Orientation Angle', 'degrees', [-25, 375],
1314519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        sharex=shared_axis,
1324519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        yticks=range(0, 361, 45))
1334519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.orientation_angle_line = self._add_timeseries_line(
1344519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.orientation_angle_axes, 'orientation', 'black')
1354519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self._add_timeseries_legend(self.orientation_angle_axes)
1364519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
137c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown    self.current_rotation = self._make_timeseries()
138c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown    self.proposed_rotation = self._make_timeseries()
1395aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.predicted_rotation = self._make_timeseries()
1404519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.orientation_axes = self._add_timeseries_axes(
1415aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        5, 'Current / Proposed Orientation', 'rotation', [-1, 4],
1424519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        sharex=shared_axis,
1434519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        yticks=range(0, 4))
144c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown    self.current_rotation_line = self._add_timeseries_line(
145c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown        self.orientation_axes, 'current', 'black', linewidth=2)
1465aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.predicted_rotation_line = self._add_timeseries_line(
1475aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.orientation_axes, 'predicted', 'purple', linewidth=3)
148c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown    self.proposed_rotation_line = self._add_timeseries_line(
149c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown        self.orientation_axes, 'proposed', 'green', linewidth=3)
1504519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self._add_timeseries_legend(self.orientation_axes)
1514519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
1525aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_settled = self._make_timeseries()
1535aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_flat_delay_expired = self._make_timeseries()
1545aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_swing_delay_expired = self._make_timeseries()
155daf5d894ef71c5674e83b11de8b408e3bdabe4c7Jeff Brown    self.time_until_acceleration_delay_expired = self._make_timeseries()
1565aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.stability_axes = self._add_timeseries_axes(
1575aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        6, 'Proposal Stability', 'ms', [-10, 600],
1585aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        sharex=shared_axis,
1595aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        yticks=range(0, 600, 100))
1605aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_settled_line = self._add_timeseries_line(
1615aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.stability_axes, 'time until settled', 'black', linewidth=2)
1625aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_flat_delay_expired_line = self._add_timeseries_line(
1635aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.stability_axes, 'time until flat delay expired', 'green')
1645aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_swing_delay_expired_line = self._add_timeseries_line(
1655aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.stability_axes, 'time until swing delay expired', 'blue')
166daf5d894ef71c5674e83b11de8b408e3bdabe4c7Jeff Brown    self.time_until_acceleration_delay_expired_line = self._add_timeseries_line(
167daf5d894ef71c5674e83b11de8b408e3bdabe4c7Jeff Brown        self.stability_axes, 'time until acceleration delay expired', 'red')
1685aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self._add_timeseries_legend(self.stability_axes)
1694519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
1704519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.sample_latency = self._make_timeseries()
1714519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.sample_latency_axes = self._add_timeseries_axes(
1725aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        7, 'Accelerometer Sampling Latency', 'ms', [-10, 500],
1734519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        sharex=shared_axis,
1744519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        yticks=range(0, 500, 100))
1754519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.sample_latency_line = self._add_timeseries_line(
1764519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.sample_latency_axes, 'latency', 'black')
1774519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self._add_timeseries_legend(self.sample_latency_axes)
1784519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
1795aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.fig.canvas.mpl_connect('button_press_event', self._on_click)
1805aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.paused = False
1815aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown
1824519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.timer = self.fig.canvas.new_timer(interval=100)
1834519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.timer.add_callback(lambda: self.update())
1844519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.timer.start()
1854519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
1864519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.timebase = None
1874519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self._reset_parse_state()
1884519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
1895aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown  # Handle a click event to pause or restart the timer.
1905aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown  def _on_click(self, ev):
1915aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    if not self.paused:
1925aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self.paused = True
1935aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self.timer.stop()
1945aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    else:
1955aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self.paused = False
1965aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self.timer.start()
1975aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown
1984519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Initialize a time series.
1994519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _make_timeseries(self):
2004519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    return [[], []]
2014519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2024519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Add a subplot to the figure for a time series.
2034519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None):
2045aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    num_graphs = 7
2054519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    height = 0.9 / num_graphs
2064519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    top = 0.95 - height * index
2074519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    axes = self.fig.add_axes([0.1, top, 0.8, height],
2084519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        xscale='linear',
2094519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        xlim=[0, timespan],
2104519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        ylabel=ylabel,
2114519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        yscale='linear',
2124519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        ylim=ylim,
2134519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        sharex=sharex)
2144519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold')
2154519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    axes.set_xlabel('time (s)', fontsize=10, fontweight='bold')
2164519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    axes.set_ylabel(ylabel, fontsize=10, fontweight='bold')
2174519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    axes.set_xticks(range(0, timespan + 1, timeticks))
2184519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    axes.set_yticks(yticks)
2194519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    axes.grid(True)
2204519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2214519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    for label in axes.get_xticklabels():
2224519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      label.set_fontsize(9)
2234519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    for label in axes.get_yticklabels():
2244519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      label.set_fontsize(9)
2254519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2264519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    return axes
2274519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2284519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Add a line to the axes for a time series.
2294519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _add_timeseries_line(self, axes, label, color, linewidth=1):
2304519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    return axes.plot([], label=label, color=color, linewidth=linewidth)[0]
2314519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2324519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Add a legend to a time series.
2334519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _add_timeseries_legend(self, axes):
2344519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    axes.legend(
2354519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        loc='upper left',
2364519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        bbox_to_anchor=(1.01, 1),
2374519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        borderpad=0.1,
2384519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        borderaxespad=0.1,
2394519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        prop={'size': 10})
2404519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2414519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Resets the parse state.
2424519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _reset_parse_state(self):
2434519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_raw_acceleration_x = None
2444519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_raw_acceleration_y = None
2454519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_raw_acceleration_z = None
2465aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.parse_raw_acceleration_magnitude = None
2474519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_filtered_acceleration_x = None
2484519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_filtered_acceleration_y = None
2494519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_filtered_acceleration_z = None
2505aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.parse_filtered_acceleration_magnitude = None
2514519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_tilt_angle = None
2524519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_orientation_angle = None
253c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown    self.parse_current_rotation = None
254c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown    self.parse_proposed_rotation = None
2555aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.parse_predicted_rotation = None
2565aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.parse_time_until_settled = None
2575aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.parse_time_until_flat_delay_expired = None
2585aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.parse_time_until_swing_delay_expired = None
259daf5d894ef71c5674e83b11de8b408e3bdabe4c7Jeff Brown    self.parse_time_until_acceleration_delay_expired = None
2604519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.parse_sample_latency = None
2614519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2624519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Update samples.
2634519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def update(self):
2644519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    timeindex = 0
2654519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    while True:
2664519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      try:
2674519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        line = self.adbout.readline()
2684519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      except EOFError:
2694519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        plot.close()
2704519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        return
2714519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if line is None:
2724519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        break
2734519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      print line
2744519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2754519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      try:
2764519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        timestamp = self._parse_timestamp(line)
2774519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      except ValueError, e:
2784519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        continue
2794519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if self.timebase is None:
2804519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.timebase = timestamp
2814519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      delta = timestamp - self.timebase
2824519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      timeindex = delta.seconds + delta.microseconds * 0.000001
2834519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2844519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if line.find('Raw acceleration vector:') != -1:
2854519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_raw_acceleration_x = self._get_following_number(line, 'x=')
2864519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_raw_acceleration_y = self._get_following_number(line, 'y=')
2874519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_raw_acceleration_z = self._get_following_number(line, 'z=')
2885aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.parse_raw_acceleration_magnitude = self._get_following_number(line, 'magnitude=')
2894519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2904519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if line.find('Filtered acceleration vector:') != -1:
2914519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_filtered_acceleration_x = self._get_following_number(line, 'x=')
2924519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_filtered_acceleration_y = self._get_following_number(line, 'y=')
2934519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_filtered_acceleration_z = self._get_following_number(line, 'z=')
2945aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.parse_filtered_acceleration_magnitude = self._get_following_number(line, 'magnitude=')
2954519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2964519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if line.find('tiltAngle=') != -1:
2974519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_tilt_angle = self._get_following_number(line, 'tiltAngle=')
2984519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
2994519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if line.find('orientationAngle=') != -1:
3004519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_orientation_angle = self._get_following_number(line, 'orientationAngle=')
3014519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
3024519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if line.find('Result:') != -1:
303c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown        self.parse_current_rotation = self._get_following_number(line, 'currentRotation=')
304c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown        self.parse_proposed_rotation = self._get_following_number(line, 'proposedRotation=')
3055aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.parse_predicted_rotation = self._get_following_number(line, 'predictedRotation=')
3064519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self.parse_sample_latency = self._get_following_number(line, 'timeDeltaMS=')
3075aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.parse_time_until_settled = self._get_following_number(line, 'timeUntilSettledMS=')
3085aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.parse_time_until_flat_delay_expired = self._get_following_number(line, 'timeUntilFlatDelayExpiredMS=')
3095aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self.parse_time_until_swing_delay_expired = self._get_following_number(line, 'timeUntilSwingDelayExpiredMS=')
310daf5d894ef71c5674e83b11de8b408e3bdabe4c7Jeff Brown        self.parse_time_until_acceleration_delay_expired = self._get_following_number(line, 'timeUntilAccelerationDelayExpiredMS=')
3114519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
3124519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.raw_acceleration_x, timeindex, self.parse_raw_acceleration_x)
3134519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.raw_acceleration_y, timeindex, self.parse_raw_acceleration_y)
3144519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.raw_acceleration_z, timeindex, self.parse_raw_acceleration_z)
3155aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self._append(self.raw_acceleration_magnitude, timeindex, self.parse_raw_acceleration_magnitude)
3164519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.filtered_acceleration_x, timeindex, self.parse_filtered_acceleration_x)
3174519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.filtered_acceleration_y, timeindex, self.parse_filtered_acceleration_y)
3184519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.filtered_acceleration_z, timeindex, self.parse_filtered_acceleration_z)
3195aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self._append(self.filtered_acceleration_magnitude, timeindex, self.parse_filtered_acceleration_magnitude)
3204519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.tilt_angle, timeindex, self.parse_tilt_angle)
3214519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.orientation_angle, timeindex, self.parse_orientation_angle)
322c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown        self._append(self.current_rotation, timeindex, self.parse_current_rotation)
323c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown        if self.parse_proposed_rotation >= 0:
324c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown          self._append(self.proposed_rotation, timeindex, self.parse_proposed_rotation)
325c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown        else:
326c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown          self._append(self.proposed_rotation, timeindex, None)
3275aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        if self.parse_predicted_rotation >= 0:
3285aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown          self._append(self.predicted_rotation, timeindex, self.parse_predicted_rotation)
329c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown        else:
3305aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown          self._append(self.predicted_rotation, timeindex, None)
3315aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self._append(self.time_until_settled, timeindex, self.parse_time_until_settled)
3325aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self._append(self.time_until_flat_delay_expired, timeindex, self.parse_time_until_flat_delay_expired)
3335aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown        self._append(self.time_until_swing_delay_expired, timeindex, self.parse_time_until_swing_delay_expired)
334daf5d894ef71c5674e83b11de8b408e3bdabe4c7Jeff Brown        self._append(self.time_until_acceleration_delay_expired, timeindex, self.parse_time_until_acceleration_delay_expired)
3354519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._append(self.sample_latency, timeindex, self.parse_sample_latency)
3364519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        self._reset_parse_state()
3374519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
3384519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    # Scroll the plots.
3394519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    if timeindex > timespan:
3404519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      bottom = int(timeindex) - timespan + scrolljump
3414519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self.timebase += timedelta(seconds=bottom)
3424519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self._scroll(self.raw_acceleration_x, bottom)
3434519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self._scroll(self.raw_acceleration_y, bottom)
3444519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self._scroll(self.raw_acceleration_z, bottom)
3455aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self._scroll(self.raw_acceleration_magnitude, bottom)
3464519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self._scroll(self.filtered_acceleration_x, bottom)
3474519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self._scroll(self.filtered_acceleration_y, bottom)
3484519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self._scroll(self.filtered_acceleration_z, bottom)
3495aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self._scroll(self.filtered_acceleration_magnitude, bottom)
3504519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self._scroll(self.tilt_angle, bottom)
3514519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      self._scroll(self.orientation_angle, bottom)
352c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown      self._scroll(self.current_rotation, bottom)
353c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown      self._scroll(self.proposed_rotation, bottom)
3545aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self._scroll(self.predicted_rotation, bottom)
3555aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self._scroll(self.time_until_settled, bottom)
3565aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self._scroll(self.time_until_flat_delay_expired, bottom)
3575aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown      self._scroll(self.time_until_swing_delay_expired, bottom)
358daf5d894ef71c5674e83b11de8b408e3bdabe4c7Jeff Brown      self._scroll(self.time_until_acceleration_delay_expired, bottom)
359c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown      self._scroll(self.sample_latency, bottom)
3604519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
3614519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    # Redraw the plots.
3624519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_line_x.set_data(self.raw_acceleration_x)
3634519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_line_y.set_data(self.raw_acceleration_y)
3644519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.raw_acceleration_line_z.set_data(self.raw_acceleration_z)
3655aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.raw_acceleration_line_magnitude.set_data(self.raw_acceleration_magnitude)
3664519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_line_x.set_data(self.filtered_acceleration_x)
3674519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_line_y.set_data(self.filtered_acceleration_y)
3684519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.filtered_acceleration_line_z.set_data(self.filtered_acceleration_z)
3695aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.filtered_acceleration_line_magnitude.set_data(self.filtered_acceleration_magnitude)
3704519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.tilt_angle_line.set_data(self.tilt_angle)
3714519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.orientation_angle_line.set_data(self.orientation_angle)
372c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown    self.current_rotation_line.set_data(self.current_rotation)
373c0347aa19f354a8e1ff4fcd5372b134c0c7c16adJeff Brown    self.proposed_rotation_line.set_data(self.proposed_rotation)
3745aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.predicted_rotation_line.set_data(self.predicted_rotation)
3755aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_settled_line.set_data(self.time_until_settled)
3765aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_flat_delay_expired_line.set_data(self.time_until_flat_delay_expired)
3775aa73ae58f049379a97bc86add541f27170c02a4Jeff Brown    self.time_until_swing_delay_expired_line.set_data(self.time_until_swing_delay_expired)
378daf5d894ef71c5674e83b11de8b408e3bdabe4c7Jeff Brown    self.time_until_acceleration_delay_expired_line.set_data(self.time_until_acceleration_delay_expired)
3794519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.sample_latency_line.set_data(self.sample_latency)
3804519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
3814519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    self.fig.canvas.draw_idle()
3824519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
3834519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Scroll a time series.
3844519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _scroll(self, timeseries, bottom):
3854519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    bottom_index = bisect.bisect_left(timeseries[0], bottom)
3864519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    del timeseries[0][:bottom_index]
3874519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    del timeseries[1][:bottom_index]
3884519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    for i, timeindex in enumerate(timeseries[0]):
3894519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      timeseries[0][i] = timeindex - bottom
3904519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
3914519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Extract a word following the specified prefix.
3924519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _get_following_word(self, line, prefix):
3934519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    prefix_index = line.find(prefix)
3944519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    if prefix_index == -1:
3954519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      return None
3964519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    start_index = prefix_index + len(prefix)
3974519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    delim_index = line.find(',', start_index)
3984519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    if delim_index == -1:
3994519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      return line[start_index:]
4004519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    else:
4014519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      return line[start_index:delim_index]
4024519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4034519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Extract a number following the specified prefix.
4044519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _get_following_number(self, line, prefix):
4054519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    word = self._get_following_word(line, prefix)
4064519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    if word is None:
4074519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      return None
4084519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    return float(word)
4094519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4104519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Extract an array of numbers following the specified prefix.
4114519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _get_following_array_of_numbers(self, line, prefix):
4124519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    prefix_index = line.find(prefix + '[')
4134519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    if prefix_index == -1:
4144519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      return None
4154519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    start_index = prefix_index + len(prefix) + 1
4164519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    delim_index = line.find(']', start_index)
4174519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    if delim_index == -1:
4184519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      return None
4194519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4204519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    result = []
4214519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    while start_index < delim_index:
4224519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      comma_index = line.find(', ', start_index, delim_index)
4234519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      if comma_index == -1:
4244519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        result.append(float(line[start_index:delim_index]))
4254519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown        break;
4264519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      result.append(float(line[start_index:comma_index]))
4274519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown      start_index = comma_index + 2
4284519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    return result
4294519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4304519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Add a value to a time series.
4314519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _append(self, timeseries, timeindex, number):
4324519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    timeseries[0].append(timeindex)
4334519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    timeseries[1].append(number)
4344519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4354519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Parse the logcat timestamp.
4364519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  # Timestamp has the form '01-21 20:42:42.930'
4374519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown  def _parse_timestamp(self, line):
4384519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f')
4394519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4404519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Notice
4414519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownprint "Window Orientation Listener plotting tool"
4424519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownprint "-----------------------------------------\n"
4434519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownprint "Please turn on the Window Orientation Listener logging in Development Settings."
4444519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4454519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Start adb.
4464519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownprint "Starting adb logcat.\n"
4474519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4484519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownadb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'WindowOrientationListener:V'],
4494519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown    stdout=subprocess.PIPE)
4504519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownadbout = NonBlockingStream(adb.stdout)
4514519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4524519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Prepare plotter.
4534519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownplotter = Plotter(adbout)
4544519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownplotter.update()
4554519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown
4564519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brown# Main loop.
4574519f07e9c6b993fbe7a3d3df24d71d9450a54f1Jeff Brownplot.show()
458