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 VelocityTracker. 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Enable DEBUG_VELOCITY to print the output. 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# This code supports side-by-side comparison of two algorithms. 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# The old algorithm should be modified to emit debug log messages containing 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# the word "OLD". 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport numpy as np 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport matplotlib.pyplot as plot 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport subprocess 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport re 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport fcntl 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport os 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport errno 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport bisect 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskifrom datetime import datetime, timedelta 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Parameters. 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskitimespan = 15 # seconds total span shown 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiscrolljump = 5 # seconds jump when scrolling 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskitimeticks = 1 # seconds between each time tick 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Non-blocking stream wrapper. 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiclass NonBlockingStream: 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def __init__(self, stream): 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK) 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.stream = stream 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.buffer = '' 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.pos = 0 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def readline(self): 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski while True: 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski index = self.buffer.find('\n', self.pos) 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if index != -1: 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = self.buffer[self.pos:index] 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.pos = index + 1 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return result 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.buffer = self.buffer[self.pos:] 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.pos = 0 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try: 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski chunk = os.read(self.stream.fileno(), 4096) 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski except OSError, e: 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if e.errno == errno.EAGAIN: 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return None 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski raise e 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if len(chunk) == 0: 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if len(self.buffer) == 0: 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski raise(EOFError) 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski else: 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski result = self.buffer 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.buffer = '' 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.pos = 0 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return result 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.buffer += chunk 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Plotter 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiclass Plotter: 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def __init__(self, adbout): 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.adbout = adbout 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.fig = plot.figure(1) 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.fig.suptitle('Velocity Tracker', fontsize=12) 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.fig.set_dpi(96) 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.fig.set_size_inches(16, 12, forward=True) 85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_x = self._make_timeseries() 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_y = self._make_timeseries() 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_magnitude = self._make_timeseries() 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_axes = self._add_timeseries_axes( 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 1, 'Velocity', 'px/s', [-5000, 5000], 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski yticks=range(-5000, 5000, 1000)) 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_line_x = self._add_timeseries_line( 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_axes, 'vx', 'red') 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_line_y = self._add_timeseries_line( 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_axes, 'vy', 'green') 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_line_magnitude = self._add_timeseries_line( 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_axes, 'magnitude', 'blue') 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._add_timeseries_legend(self.velocity_axes) 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski shared_axis = self.velocity_axes 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_x = self._make_timeseries() 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_y = self._make_timeseries() 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_magnitude = self._make_timeseries() 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_axes = self._add_timeseries_axes( 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 2, 'Old Algorithm Velocity', 'px/s', [-5000, 5000], 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski sharex=shared_axis, 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski yticks=range(-5000, 5000, 1000)) 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_line_x = self._add_timeseries_line( 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_axes, 'vx', 'red') 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_line_y = self._add_timeseries_line( 112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_axes, 'vy', 'green') 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_line_magnitude = self._add_timeseries_line( 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_axes, 'magnitude', 'blue') 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._add_timeseries_legend(self.old_velocity_axes) 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.timer = self.fig.canvas.new_timer(interval=100) 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.timer.add_callback(lambda: self.update()) 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.timer.start() 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.timebase = None 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._reset_parse_state() 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Initialize a time series. 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _make_timeseries(self): 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return [[], []] 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Add a subplot to the figure for a time series. 129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None): 130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski num_graphs = 2 131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski height = 0.9 / num_graphs 132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski top = 0.95 - height * index 133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski axes = self.fig.add_axes([0.1, top, 0.8, height], 134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski xscale='linear', 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski xlim=[0, timespan], 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ylabel=ylabel, 137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski yscale='linear', 138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ylim=ylim, 139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski sharex=sharex) 140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold') 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski axes.set_xlabel('time (s)', fontsize=10, fontweight='bold') 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski axes.set_ylabel(ylabel, fontsize=10, fontweight='bold') 143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski axes.set_xticks(range(0, timespan + 1, timeticks)) 144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski axes.set_yticks(yticks) 145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski axes.grid(True) 146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for label in axes.get_xticklabels(): 148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski label.set_fontsize(9) 149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for label in axes.get_yticklabels(): 150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski label.set_fontsize(9) 151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return axes 153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Add a line to the axes for a time series. 155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _add_timeseries_line(self, axes, label, color, linewidth=1): 156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return axes.plot([], label=label, color=color, linewidth=linewidth)[0] 157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Add a legend to a time series. 159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _add_timeseries_legend(self, axes): 160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski axes.legend( 161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski loc='upper left', 162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski bbox_to_anchor=(1.01, 1), 163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski borderpad=0.1, 164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski borderaxespad=0.1, 165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski prop={'size': 10}) 166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Resets the parse state. 168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _reset_parse_state(self): 169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_velocity_x = None 170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_velocity_y = None 171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_velocity_magnitude = None 172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_old_velocity_x = None 173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_old_velocity_y = None 174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_old_velocity_magnitude = None 175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Update samples. 177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def update(self): 178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski timeindex = 0 179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski while True: 180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try: 181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski line = self.adbout.readline() 182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski except EOFError: 183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski plot.close() 184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return 185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if line is None: 186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski break 187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski print line 188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try: 190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski timestamp = self._parse_timestamp(line) 191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski except ValueError, e: 192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski continue 193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if self.timebase is None: 194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.timebase = timestamp 195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski delta = timestamp - self.timebase 196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski timeindex = delta.seconds + delta.microseconds * 0.000001 197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if line.find(': position') != -1: 199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_velocity_x = self._get_following_number(line, 'vx=') 200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_velocity_y = self._get_following_number(line, 'vy=') 201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_velocity_magnitude = self._get_following_number(line, 'speed=') 202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._append(self.velocity_x, timeindex, self.parse_velocity_x) 203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._append(self.velocity_y, timeindex, self.parse_velocity_y) 204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._append(self.velocity_magnitude, timeindex, self.parse_velocity_magnitude) 205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if line.find(': OLD') != -1: 207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_old_velocity_x = self._get_following_number(line, 'vx=') 208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_old_velocity_y = self._get_following_number(line, 'vy=') 209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.parse_old_velocity_magnitude = self._get_following_number(line, 'speed=') 210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._append(self.old_velocity_x, timeindex, self.parse_old_velocity_x) 211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._append(self.old_velocity_y, timeindex, self.parse_old_velocity_y) 212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._append(self.old_velocity_magnitude, timeindex, self.parse_old_velocity_magnitude) 213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Scroll the plots. 215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if timeindex > timespan: 216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski bottom = int(timeindex) - timespan + scrolljump 217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.timebase += timedelta(seconds=bottom) 218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._scroll(self.velocity_x, bottom) 219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._scroll(self.velocity_y, bottom) 220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._scroll(self.velocity_magnitude, bottom) 221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._scroll(self.old_velocity_x, bottom) 222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._scroll(self.old_velocity_y, bottom) 223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self._scroll(self.old_velocity_magnitude, bottom) 224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Redraw the plots. 226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_line_x.set_data(self.velocity_x) 227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_line_y.set_data(self.velocity_y) 228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.velocity_line_magnitude.set_data(self.velocity_magnitude) 229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_line_x.set_data(self.old_velocity_x) 230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_line_y.set_data(self.old_velocity_y) 231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.old_velocity_line_magnitude.set_data(self.old_velocity_magnitude) 232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski self.fig.canvas.draw_idle() 234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Scroll a time series. 236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _scroll(self, timeseries, bottom): 237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski bottom_index = bisect.bisect_left(timeseries[0], bottom) 238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski del timeseries[0][:bottom_index] 239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski del timeseries[1][:bottom_index] 240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for i, timeindex in enumerate(timeseries[0]): 241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski timeseries[0][i] = timeindex - bottom 242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Extract a word following the specified prefix. 244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _get_following_word(self, line, prefix): 245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski prefix_index = line.find(prefix) 246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if prefix_index == -1: 247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return None 248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski start_index = prefix_index + len(prefix) 249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski delim_index = line.find(',', start_index) 250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if delim_index == -1: 251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return line[start_index:] 252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski else: 253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return line[start_index:delim_index] 254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Extract a number following the specified prefix. 256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _get_following_number(self, line, prefix): 257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski word = self._get_following_word(line, prefix) 258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if word is None: 259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return None 260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return float(word) 261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Add a value to a time series. 263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _append(self, timeseries, timeindex, number): 264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski timeseries[0].append(timeindex) 265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski timeseries[1].append(number) 266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Parse the logcat timestamp. 268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski # Timestamp has the form '01-21 20:42:42.930' 269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski def _parse_timestamp(self, line): 270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f') 271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Notice 273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiprint "Velocity Tracker plotting tool" 274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiprint "-----------------------------------------\n" 275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiprint "Please enable debug logging and recompile the code." 276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Start adb. 278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiprint "Starting adb logcat.\n" 279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiadb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'Input:*', 'VelocityTracker:*'], 281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski stdout=subprocess.PIPE) 282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiadbout = NonBlockingStream(adb.stdout) 283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Prepare plotter. 285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiplotter = Plotter(adbout) 286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiplotter.update() 287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski# Main loop. 289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiplot.show() 290