Add support for plotting arbitrary flatbuffer vectors
Adds support for both:
-Plotting every element in a vector.
-Plotting repeated sub-messages.
Change-Id: I52de3dbcf7bcf345a7a21d9de6d04692926a9590
diff --git a/aos/network/www/aos_plotter.ts b/aos/network/www/aos_plotter.ts
index b84bfc4..35c27a7 100644
--- a/aos/network/www/aos_plotter.ts
+++ b/aos/network/www/aos_plotter.ts
@@ -60,6 +60,32 @@
this.messages.push(
new TimestampedMessage(Table.getRootTable(new ByteBuffer(data)), time));
}
+ private readField<T>(
+ message: Table, fieldName: string,
+ normalReader: (message: Table, name: string) => T | null,
+ vectorReader: (message: Table, name: string) => T[] | null): T[]|null {
+ // Typescript handles bindings in non-obvious ways that aren't caught well
+ // by the compiler.
+ normalReader = normalReader.bind(this.parser);
+ vectorReader = vectorReader.bind(this.parser);
+ const regex = /(.*)\[([0-9]*)\]/;
+ const match = fieldName.match(regex);
+ if (match) {
+ const name = match[1];
+ const vector = vectorReader(message, name);
+ if (vector === null) {
+ return null;
+ }
+ if (match[2] === "") {
+ return vector;
+ } else {
+ const index = parseInt(match[2]);
+ return (index < vector.length) ? [vector[index]] : null;
+ }
+ }
+ const singleResult = normalReader(message, fieldName);
+ return singleResult ? [singleResult] : null;
+ }
// Returns a time-series of every single instance of the given field. Format
// of the return value is [time0, value0, time1, value1,... timeN, valueN],
// to match with the Line.setPoint() interface.
@@ -70,41 +96,44 @@
getField(field: string[]): Float32Array {
const fieldName = field[field.length - 1];
const subMessage = field.slice(0, field.length - 1);
- const results = new Float32Array(this.messages.length * 2);
+ const results = [];
for (let ii = 0; ii < this.messages.length; ++ii) {
- let message = this.messages[ii].message;
+ let tables = [this.messages[ii].message];
for (const subMessageName of subMessage) {
- message = this.parser.readTable(message, subMessageName);
- if (message === undefined) {
- break;
+ let nextTables = [];
+ for (const table of tables) {
+ const nextTable = this.readField(
+ table, subMessageName, Parser.prototype.readTable,
+ Parser.prototype.readVectorOfTables);
+ if (nextTable === null) {
+ continue;
+ }
+ nextTables = nextTables.concat(nextTable);
}
+ tables = nextTables;
}
- results[ii * 2] = this.messages[ii].time;
- const regex = /(.*)\[([0-9]*)\]/;
- let name = fieldName;
- let match = fieldName.match(regex);
- let index = undefined;
- if (match) {
- name = match[1]
- index = parseInt(match[2])
- }
- if (message === undefined) {
- results[ii * 2 + 1] = NaN;
+ const time = this.messages[ii].time;
+ if (tables.length === 0) {
+ results.push(time);
+ results.push(NaN);
} else {
- if (index === undefined) {
- results[ii * 2 + 1] = this.parser.readScalar(message, name);
- } else {
- const vector =
- this.parser.readVectorOfScalars(message, name);
- if (index < vector.length) {
- results[ii * 2 + 1] = vector[index];
+ for (const table of tables) {
+ const values = this.readField(
+ table, fieldName, Parser.prototype.readScalar,
+ Parser.prototype.readVectorOfScalars);
+ if (values === null) {
+ results.push(time);
+ results.push(NaN);
} else {
- results[ii * 2 + 1] = NaN;
+ for (const value of values) {
+ results.push(time);
+ results.push((value === null) ? NaN : value);
+ }
}
}
}
}
- return results;
+ return new Float32Array(results);
}
numMessages(): number {
return this.messages.length;
diff --git a/aos/network/www/demo_plot.ts b/aos/network/www/demo_plot.ts
index d223757..ebdff7c 100644
--- a/aos/network/www/demo_plot.ts
+++ b/aos/network/www/demo_plot.ts
@@ -19,11 +19,11 @@
import Connection = proxy.Connection;
export function plotDemo(conn: Connection, parentDiv: Element): void {
- const width = 900;
- const height = 400;
+ const width = AosPlotter.DEFAULT_WIDTH;
+ const height = AosPlotter.DEFAULT_HEIGHT;
const benchmarkDiv = document.createElement('div');
- benchmarkDiv.style.top = height.toString();
+ benchmarkDiv.style.top = (height * 2).toString();
benchmarkDiv.style.left = '0';
benchmarkDiv.style.position = 'absolute';
parentDiv.appendChild(benchmarkDiv);
@@ -33,20 +33,45 @@
const aosPlotter = new AosPlotter(conn);
{
- // Setup a plot that just shows the PID of each timing report message.
- // For the basic live_web_plotter_demo, this will be a boring line showing
- // just the PID of the proxy process. On a real system, or against a logfile,
- // this would show the PIDs of all active processes.
+ // Setup a plot that shows some arbitrary PDP current values.
+ const pdpValues =
+ aosPlotter.addMessageSource('/aos', 'frc971.PDPValues');
+ const timingPlot = aosPlotter.addPlot(parentDiv);
+ timingPlot.plot.getAxisLabels().setTitle('Current Values');
+ timingPlot.plot.getAxisLabels().setYLabel('Current (Amps)');
+ timingPlot.plot.getAxisLabels().setXLabel('Monotonic Send Time (sec)');
+ // Displays points for every single current sample at each time-point.
+ const allValuesLine = timingPlot.addMessageLine(pdpValues, ['currents[]']);
+ allValuesLine.setDrawLine(false);
+ allValuesLine.setPointSize(5);
+ // Displays a line for the current along channel 1.
+ const singleValueLine = timingPlot.addMessageLine(pdpValues, ['currents[1]']);
+ singleValueLine.setDrawLine(true);
+ singleValueLine.setPointSize(0);
+ const voltageLine = timingPlot.addMessageLine(pdpValues, ['voltage']);
+ voltageLine.setPointSize(0);
+ }
+
+ {
const timingReport =
aosPlotter.addMessageSource('/aos', 'aos.timing.Report');
- const timingPlot =
- aosPlotter.addPlot(parentDiv, [0, 0], [width, height]);
- timingPlot.plot.getAxisLabels().setTitle('Timing Report PID');
+ // Setup a plot that just shows some arbitrary timing data.
+ const timingPlot = aosPlotter.addPlot(parentDiv);
+ timingPlot.plot.getAxisLabels().setTitle('Timing Report Wakeups');
timingPlot.plot.getAxisLabels().setYLabel('PID');
timingPlot.plot.getAxisLabels().setXLabel('Monotonic Send Time (sec)');
- const msgLine = timingPlot.addMessageLine(timingReport, ['pid']);
- msgLine.setDrawLine(false);
- msgLine.setPointSize(5);
+ // Show *all* the wakeup latencies for all timers.
+ const allValuesLine = timingPlot.addMessageLine(
+ timingReport, ['timers[]', 'wakeup_latency', 'average']);
+ allValuesLine.setDrawLine(false);
+ allValuesLine.setPointSize(5);
+ // Show *all* the wakeup latencies for the first timer in each timing report
+ // (this is not actually all that helpful unless you were to also filter by
+ // PID).
+ const singleValueLine = timingPlot.addMessageLine(
+ timingReport, ['timers[0]', 'wakeup_latency', 'average']);
+ singleValueLine.setDrawLine(true);
+ singleValueLine.setPointSize(0);
}
// Set up and draw the benchmarking plot.