1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#!/usr/bin/env python2.6
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Copyright (C) 2011 The Android Open Source Project
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Licensed under the Apache License, Version 2.0 (the "License");
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# you may not use this file except in compliance with the License.
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# You may obtain a copy of the License at
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#      http://www.apache.org/licenses/LICENSE-2.0
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Unless required by applicable law or agreed to in writing, software
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# distributed under the License is distributed on an "AS IS" BASIS,
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# See the License for the specific language governing permissions and
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# limitations under the License.
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Plots debug log output from WindowOrientationListener.
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# See README.txt for details.
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport numpy as np
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport matplotlib.pyplot as plot
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport subprocess
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport re
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport fcntl
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport os
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport errno
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport bisect
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskifrom datetime import datetime, timedelta
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Parameters.
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskitimespan = 15 # seconds total span shown
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiscrolljump = 5 # seconds jump when scrolling
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskitimeticks = 1 # seconds between each time tick
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Non-blocking stream wrapper.
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiclass NonBlockingStream:
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def __init__(self, stream):
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK)
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.stream = stream
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.buffer = ''
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.pos = 0
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def readline(self):
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while True:
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      index = self.buffer.find('\n', self.pos)
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if index != -1:
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = self.buffer[self.pos:index]
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.pos = index + 1
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return result
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self.buffer = self.buffer[self.pos:]
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self.pos = 0
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      try:
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        chunk = os.read(self.stream.fileno(), 4096)
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      except OSError, e:
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if e.errno == errno.EAGAIN:
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          return None
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        raise e
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if len(chunk) == 0:
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if len(self.buffer) == 0:
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          raise(EOFError)
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        else:
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          result = self.buffer
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          self.buffer = ''
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          self.pos = 0
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          return result
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self.buffer += chunk
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Plotter
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiclass Plotter:
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def __init__(self, adbout):
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.adbout = adbout
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.fig = plot.figure(1)
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.fig.suptitle('Window Orientation Listener', fontsize=12)
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.fig.set_dpi(96)
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.fig.set_size_inches(16, 12, forward=True)
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_x = self._make_timeseries()
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_y = self._make_timeseries()
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_z = self._make_timeseries()
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_magnitude = self._make_timeseries()
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_axes = self._add_timeseries_axes(
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        1, 'Raw Acceleration', 'm/s^2', [-20, 20],
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        yticks=range(-15, 16, 5))
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_line_x = self._add_timeseries_line(
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.raw_acceleration_axes, 'x', 'red')
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_line_y = self._add_timeseries_line(
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.raw_acceleration_axes, 'y', 'green')
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_line_z = self._add_timeseries_line(
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.raw_acceleration_axes, 'z', 'blue')
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_line_magnitude = self._add_timeseries_line(
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.raw_acceleration_axes, 'magnitude', 'orange', linewidth=2)
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self._add_timeseries_legend(self.raw_acceleration_axes)
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    shared_axis = self.raw_acceleration_axes
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_x = self._make_timeseries()
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_y = self._make_timeseries()
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_z = self._make_timeseries()
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_magnitude = self._make_timeseries()
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_axes = self._add_timeseries_axes(
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        2, 'Filtered Acceleration', 'm/s^2', [-20, 20],
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sharex=shared_axis,
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        yticks=range(-15, 16, 5))
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_line_x = self._add_timeseries_line(
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.filtered_acceleration_axes, 'x', 'red')
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_line_y = self._add_timeseries_line(
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.filtered_acceleration_axes, 'y', 'green')
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_line_z = self._add_timeseries_line(
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.filtered_acceleration_axes, 'z', 'blue')
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_line_magnitude = self._add_timeseries_line(
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.filtered_acceleration_axes, 'magnitude', 'orange', linewidth=2)
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self._add_timeseries_legend(self.filtered_acceleration_axes)
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.tilt_angle = self._make_timeseries()
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.tilt_angle_axes = self._add_timeseries_axes(
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        3, 'Tilt Angle', 'degrees', [-105, 105],
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sharex=shared_axis,
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        yticks=range(-90, 91, 30))
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.tilt_angle_line = self._add_timeseries_line(
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.tilt_angle_axes, 'tilt', 'black')
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self._add_timeseries_legend(self.tilt_angle_axes)
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.orientation_angle = self._make_timeseries()
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.orientation_angle_axes = self._add_timeseries_axes(
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        4, 'Orientation Angle', 'degrees', [-25, 375],
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sharex=shared_axis,
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        yticks=range(0, 361, 45))
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.orientation_angle_line = self._add_timeseries_line(
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.orientation_angle_axes, 'orientation', 'black')
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self._add_timeseries_legend(self.orientation_angle_axes)
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.current_rotation = self._make_timeseries()
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.proposed_rotation = self._make_timeseries()
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.predicted_rotation = self._make_timeseries()
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.orientation_axes = self._add_timeseries_axes(
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        5, 'Current / Proposed Orientation', 'rotation', [-1, 4],
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sharex=shared_axis,
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        yticks=range(0, 4))
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.current_rotation_line = self._add_timeseries_line(
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.orientation_axes, 'current', 'black', linewidth=2)
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.predicted_rotation_line = self._add_timeseries_line(
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.orientation_axes, 'predicted', 'purple', linewidth=3)
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.proposed_rotation_line = self._add_timeseries_line(
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.orientation_axes, 'proposed', 'green', linewidth=3)
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self._add_timeseries_legend(self.orientation_axes)
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_settled = self._make_timeseries()
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_flat_delay_expired = self._make_timeseries()
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_swing_delay_expired = self._make_timeseries()
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_acceleration_delay_expired = self._make_timeseries()
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.stability_axes = self._add_timeseries_axes(
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        6, 'Proposal Stability', 'ms', [-10, 600],
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sharex=shared_axis,
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        yticks=range(0, 600, 100))
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_settled_line = self._add_timeseries_line(
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.stability_axes, 'time until settled', 'black', linewidth=2)
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_flat_delay_expired_line = self._add_timeseries_line(
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.stability_axes, 'time until flat delay expired', 'green')
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_swing_delay_expired_line = self._add_timeseries_line(
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.stability_axes, 'time until swing delay expired', 'blue')
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_acceleration_delay_expired_line = self._add_timeseries_line(
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.stability_axes, 'time until acceleration delay expired', 'red')
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self._add_timeseries_legend(self.stability_axes)
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.sample_latency = self._make_timeseries()
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.sample_latency_axes = self._add_timeseries_axes(
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        7, 'Accelerometer Sampling Latency', 'ms', [-10, 500],
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sharex=shared_axis,
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        yticks=range(0, 500, 100))
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.sample_latency_line = self._add_timeseries_line(
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.sample_latency_axes, 'latency', 'black')
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self._add_timeseries_legend(self.sample_latency_axes)
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.fig.canvas.mpl_connect('button_press_event', self._on_click)
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.paused = False
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.timer = self.fig.canvas.new_timer(interval=100)
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.timer.add_callback(lambda: self.update())
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.timer.start()
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.timebase = None
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self._reset_parse_state()
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Handle a click event to pause or restart the timer.
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _on_click(self, ev):
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if not self.paused:
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self.paused = True
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self.timer.stop()
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else:
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self.paused = False
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self.timer.start()
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Initialize a time series.
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _make_timeseries(self):
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return [[], []]
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Add a subplot to the figure for a time series.
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None):
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    num_graphs = 7
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    height = 0.9 / num_graphs
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    top = 0.95 - height * index
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    axes = self.fig.add_axes([0.1, top, 0.8, height],
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        xscale='linear',
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        xlim=[0, timespan],
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ylabel=ylabel,
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        yscale='linear',
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ylim=ylim,
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sharex=sharex)
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold')
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    axes.set_xlabel('time (s)', fontsize=10, fontweight='bold')
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    axes.set_ylabel(ylabel, fontsize=10, fontweight='bold')
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    axes.set_xticks(range(0, timespan + 1, timeticks))
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    axes.set_yticks(yticks)
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    axes.grid(True)
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for label in axes.get_xticklabels():
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      label.set_fontsize(9)
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for label in axes.get_yticklabels():
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      label.set_fontsize(9)
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return axes
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Add a line to the axes for a time series.
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _add_timeseries_line(self, axes, label, color, linewidth=1):
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return axes.plot([], label=label, color=color, linewidth=linewidth)[0]
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Add a legend to a time series.
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _add_timeseries_legend(self, axes):
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    axes.legend(
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        loc='upper left',
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bbox_to_anchor=(1.01, 1),
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        borderpad=0.1,
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        borderaxespad=0.1,
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        prop={'size': 10})
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Resets the parse state.
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _reset_parse_state(self):
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_raw_acceleration_x = None
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_raw_acceleration_y = None
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_raw_acceleration_z = None
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_raw_acceleration_magnitude = None
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_filtered_acceleration_x = None
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_filtered_acceleration_y = None
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_filtered_acceleration_z = None
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_filtered_acceleration_magnitude = None
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_tilt_angle = None
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_orientation_angle = None
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_current_rotation = None
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_proposed_rotation = None
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_predicted_rotation = None
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_time_until_settled = None
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_time_until_flat_delay_expired = None
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_time_until_swing_delay_expired = None
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_time_until_acceleration_delay_expired = None
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.parse_sample_latency = None
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Update samples.
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def update(self):
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    timeindex = 0
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while True:
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      try:
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        line = self.adbout.readline()
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      except EOFError:
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        plot.close()
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if line is None:
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        break
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      print line
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      try:
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        timestamp = self._parse_timestamp(line)
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      except ValueError, e:
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        continue
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if self.timebase is None:
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.timebase = timestamp
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      delta = timestamp - self.timebase
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      timeindex = delta.seconds + delta.microseconds * 0.000001
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if line.find('Raw acceleration vector:') != -1:
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_raw_acceleration_x = self._get_following_number(line, 'x=')
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_raw_acceleration_y = self._get_following_number(line, 'y=')
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_raw_acceleration_z = self._get_following_number(line, 'z=')
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_raw_acceleration_magnitude = self._get_following_number(line, 'magnitude=')
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if line.find('Filtered acceleration vector:') != -1:
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_filtered_acceleration_x = self._get_following_number(line, 'x=')
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_filtered_acceleration_y = self._get_following_number(line, 'y=')
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_filtered_acceleration_z = self._get_following_number(line, 'z=')
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_filtered_acceleration_magnitude = self._get_following_number(line, 'magnitude=')
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if line.find('tiltAngle=') != -1:
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_tilt_angle = self._get_following_number(line, 'tiltAngle=')
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if line.find('orientationAngle=') != -1:
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_orientation_angle = self._get_following_number(line, 'orientationAngle=')
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if line.find('Result:') != -1:
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_current_rotation = self._get_following_number(line, 'currentRotation=')
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_proposed_rotation = self._get_following_number(line, 'proposedRotation=')
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_predicted_rotation = self._get_following_number(line, 'predictedRotation=')
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_sample_latency = self._get_following_number(line, 'timeDeltaMS=')
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_time_until_settled = self._get_following_number(line, 'timeUntilSettledMS=')
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_time_until_flat_delay_expired = self._get_following_number(line, 'timeUntilFlatDelayExpiredMS=')
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_time_until_swing_delay_expired = self._get_following_number(line, 'timeUntilSwingDelayExpiredMS=')
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self.parse_time_until_acceleration_delay_expired = self._get_following_number(line, 'timeUntilAccelerationDelayExpiredMS=')
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.raw_acceleration_x, timeindex, self.parse_raw_acceleration_x)
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.raw_acceleration_y, timeindex, self.parse_raw_acceleration_y)
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.raw_acceleration_z, timeindex, self.parse_raw_acceleration_z)
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.raw_acceleration_magnitude, timeindex, self.parse_raw_acceleration_magnitude)
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.filtered_acceleration_x, timeindex, self.parse_filtered_acceleration_x)
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.filtered_acceleration_y, timeindex, self.parse_filtered_acceleration_y)
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.filtered_acceleration_z, timeindex, self.parse_filtered_acceleration_z)
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.filtered_acceleration_magnitude, timeindex, self.parse_filtered_acceleration_magnitude)
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.tilt_angle, timeindex, self.parse_tilt_angle)
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.orientation_angle, timeindex, self.parse_orientation_angle)
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.current_rotation, timeindex, self.parse_current_rotation)
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if self.parse_proposed_rotation >= 0:
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          self._append(self.proposed_rotation, timeindex, self.parse_proposed_rotation)
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        else:
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          self._append(self.proposed_rotation, timeindex, None)
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if self.parse_predicted_rotation >= 0:
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          self._append(self.predicted_rotation, timeindex, self.parse_predicted_rotation)
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        else:
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          self._append(self.predicted_rotation, timeindex, None)
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.time_until_settled, timeindex, self.parse_time_until_settled)
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.time_until_flat_delay_expired, timeindex, self.parse_time_until_flat_delay_expired)
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.time_until_swing_delay_expired, timeindex, self.parse_time_until_swing_delay_expired)
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.time_until_acceleration_delay_expired, timeindex, self.parse_time_until_acceleration_delay_expired)
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._append(self.sample_latency, timeindex, self.parse_sample_latency)
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        self._reset_parse_state()
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    # Scroll the plots.
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if timeindex > timespan:
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      bottom = int(timeindex) - timespan + scrolljump
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self.timebase += timedelta(seconds=bottom)
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.raw_acceleration_x, bottom)
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.raw_acceleration_y, bottom)
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.raw_acceleration_z, bottom)
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.raw_acceleration_magnitude, bottom)
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.filtered_acceleration_x, bottom)
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.filtered_acceleration_y, bottom)
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.filtered_acceleration_z, bottom)
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.filtered_acceleration_magnitude, bottom)
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.tilt_angle, bottom)
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.orientation_angle, bottom)
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.current_rotation, bottom)
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.proposed_rotation, bottom)
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.predicted_rotation, bottom)
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.time_until_settled, bottom)
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.time_until_flat_delay_expired, bottom)
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.time_until_swing_delay_expired, bottom)
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.time_until_acceleration_delay_expired, bottom)
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      self._scroll(self.sample_latency, bottom)
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    # Redraw the plots.
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_line_x.set_data(self.raw_acceleration_x)
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_line_y.set_data(self.raw_acceleration_y)
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_line_z.set_data(self.raw_acceleration_z)
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.raw_acceleration_line_magnitude.set_data(self.raw_acceleration_magnitude)
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_line_x.set_data(self.filtered_acceleration_x)
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_line_y.set_data(self.filtered_acceleration_y)
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_line_z.set_data(self.filtered_acceleration_z)
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.filtered_acceleration_line_magnitude.set_data(self.filtered_acceleration_magnitude)
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.tilt_angle_line.set_data(self.tilt_angle)
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.orientation_angle_line.set_data(self.orientation_angle)
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.current_rotation_line.set_data(self.current_rotation)
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.proposed_rotation_line.set_data(self.proposed_rotation)
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.predicted_rotation_line.set_data(self.predicted_rotation)
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_settled_line.set_data(self.time_until_settled)
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_flat_delay_expired_line.set_data(self.time_until_flat_delay_expired)
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_swing_delay_expired_line.set_data(self.time_until_swing_delay_expired)
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.time_until_acceleration_delay_expired_line.set_data(self.time_until_acceleration_delay_expired)
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.sample_latency_line.set_data(self.sample_latency)
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    self.fig.canvas.draw_idle()
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Scroll a time series.
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _scroll(self, timeseries, bottom):
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bottom_index = bisect.bisect_left(timeseries[0], bottom)
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    del timeseries[0][:bottom_index]
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    del timeseries[1][:bottom_index]
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for i, timeindex in enumerate(timeseries[0]):
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      timeseries[0][i] = timeindex - bottom
390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Extract a word following the specified prefix.
392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _get_following_word(self, line, prefix):
393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    prefix_index = line.find(prefix)
394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if prefix_index == -1:
395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return None
396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    start_index = prefix_index + len(prefix)
397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delim_index = line.find(',', start_index)
398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if delim_index == -1:
399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return line[start_index:]
400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else:
401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return line[start_index:delim_index]
402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Extract a number following the specified prefix.
404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _get_following_number(self, line, prefix):
405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    word = self._get_following_word(line, prefix)
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if word is None:
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return None
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return float(word)
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Extract an array of numbers following the specified prefix.
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _get_following_array_of_numbers(self, line, prefix):
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    prefix_index = line.find(prefix + '[')
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if prefix_index == -1:
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return None
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    start_index = prefix_index + len(prefix) + 1
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delim_index = line.find(']', start_index)
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if delim_index == -1:
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return None
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = []
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while start_index < delim_index:
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      comma_index = line.find(', ', start_index, delim_index)
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if comma_index == -1:
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result.append(float(line[start_index:delim_index]))
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        break;
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      result.append(float(line[start_index:comma_index]))
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      start_index = comma_index + 2
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Add a value to a time series.
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _append(self, timeseries, timeindex, number):
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    timeseries[0].append(timeindex)
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    timeseries[1].append(number)
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Parse the logcat timestamp.
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  # Timestamp has the form '01-21 20:42:42.930'
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  def _parse_timestamp(self, line):
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f')
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Notice
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiprint "Window Orientation Listener plotting tool"
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiprint "-----------------------------------------\n"
443e97c9a244b71b6376003c377b56f7a86bcd0049fJeff Brownprint "Please turn on the Window Orientation Listener logging.  See README.txt."
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Start adb.
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiprint "Starting adb logcat.\n"
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiadb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'WindowOrientationListener:V'],
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    stdout=subprocess.PIPE)
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiadbout = NonBlockingStream(adb.stdout)
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Prepare plotter.
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiplotter = Plotter(adbout)
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiplotter.update()
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Main loop.
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiplot.show()
458