aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2012-10-15 14:09:43 +0800
committerAndy Green <andy.green@linaro.org>2012-10-15 14:09:43 +0800
commit3f41cccaef284e02e1a0e6fd0bc028410d1471d1 (patch)
tree208e9dd7328cb457bb083924d9506b38ce06b179
parent2416ea0a0b69bef1d3de77453d15be1233eb423f (diff)
add graticules and time scrolling
This lets you break away from following the head of the capture by mouse-scrolling inside the viewport. The "scrollbar" at the bottom shows the viewport in the context of the whole capture. Capture continues unaffected by this, and you can rejoin following the head of the capture by scrolling back to it. Eventually the capture ringbuffer will be exhausted, by default after 120s and what you're looking at overwritten. You can use the Run checkbox at the top to halt capture to avoid that, if you captured something interesting. Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r--aepd/aepd.h8
-rw-r--r--aepd/main.c19
-rw-r--r--aepd/share/aepscope.html397
-rw-r--r--aepd/websocket-protocol.c99
-rw-r--r--libarmep/sample.c3
5 files changed, 440 insertions, 86 deletions
diff --git a/aepd/aepd.h b/aepd/aepd.h
index d59009c..c43e8da 100644
--- a/aepd/aepd.h
+++ b/aepd/aepd.h
@@ -33,6 +33,7 @@
#include "../libarmep/libarmep.h"
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/aepd"
+#define DOUBLES_PER_CH_SAMPLE 3
enum demo_protocols {
/* always first */
@@ -44,12 +45,6 @@ enum demo_protocols {
DEMO_PROTOCOL_COUNT
};
-#define MAX_FIFO_EXTENT_SECONDS 100
-
-#define DOUBLES_PER_CH_SAMPLE 3
-#define MAX_FIFO_EXTENT (MAX_PROBES * CHANNELS_PER_PROBE * sizeof(double) * \
- DOUBLES_PER_CH_SAMPLE * 10000 * MAX_FIFO_EXTENT_SECONDS)
-
struct aepd_shared {
char fifo_filepath_stg[L_tmpnam + 1];
char *fifo_filepath;
@@ -60,6 +55,7 @@ struct aepd_shared {
unsigned long fifo_pos;
double fifo_head_time;
unsigned long modulo_integer_chan_size;
+ int stop_flag;
};
extern struct aepd_shared *aepd_shared;
diff --git a/aepd/main.c b/aepd/main.c
index f8e917d..0ace5a8 100644
--- a/aepd/main.c
+++ b/aepd/main.c
@@ -22,6 +22,11 @@
#include "aepd.h"
+unsigned long max_fifo_extent_seconds = 120;
+
+#define MAX_FIFO_EXTENT (MAX_PROBES * CHANNELS_PER_PROBE * sizeof(double) * \
+ DOUBLES_PER_CH_SAMPLE * 10000 * max_fifo_extent_seconds)
+
struct aepd_shared *aepd_shared;
static double sam[MAX_PROBES * CHANNELS_PER_PROBE * DOUBLES_PER_CH_SAMPLE];
extern struct libwebsocket_protocols protocols[];
@@ -82,6 +87,7 @@ struct aep_context aep_context = {
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
+ { "buffer", required_argument, NULL, 'b' },
{ "ssl", no_argument, NULL, 's' },
{ "interface", required_argument, NULL, 'i' },
{ NULL, 0, 0, 0 }
@@ -153,11 +159,15 @@ int main(int argc, char *argv[])
zero_fifo();
while (n >= 0) {
- n = getopt_long(argc, argv, "si:p:", options, NULL);
+ n = getopt_long(argc, argv, "b:si:p:", options, NULL);
if (n < 0)
continue;
switch (n) {
+ case 'b':
+ max_fifo_extent_seconds = atoi(optarg);
+ break;
+
case 's':
use_ssl = 1;
break;
@@ -172,6 +182,7 @@ int main(int argc, char *argv[])
default:
case 'h':
fprintf(stderr, "Usage: arm-probe \n"
+ " [--buffer -b <secs>] duration of capture memory (5MB/sec!) default 120\n"
" [--ssl -s] Listen using SSL / Encrypted link\n"
" [--interface -i <if>] Listen on specific "
"interface, eg, eth1\n"
@@ -259,6 +270,9 @@ int main(int argc, char *argv[])
continue;
}
+ if (aepd_shared->stop_flag)
+ goto done;
+
/*
* we have the next result in aep_result..
* voltage and current per channel
@@ -290,11 +304,12 @@ int main(int argc, char *argv[])
add_fifo(&sam[0], aep_result->chans * 3 * sizeof(double));
aepd_shared->fifo_head_time = aep_result->samtime;
+
if (aepd_shared->chans != aep_result->chans) {
aepd_shared->chans = aep_result->chans;
zero_fifo();
}
-
+done:
/* done with it */
aep_free_result(&aep_context);
diff --git a/aepd/share/aepscope.html b/aepd/share/aepscope.html
index 634c933..b2f55c3 100644
--- a/aepd/share/aepscope.html
+++ b/aepd/share/aepscope.html
@@ -40,16 +40,21 @@
<td>
<img src="linaro-logo-32.png">
</td>
- <td id=wsdi_statustd align=center>
- <div id=wsdi_status>Not initialized</div>
- </td>
<td>
<table><tr><td>Time zoom</td><td><div id=tb></div></td></tr><tr><td colspan="2">
<input type="range" id="rate" min="0" max="14" onchange="update_options();"></td></tr></table>
</td>
<td>
+ <table><tr><td>Power zoom</td><td><div id=pz></div></td></tr><tr><td colspan="2">
+ <input type="range" id="scale" step="0.1" min="0.1" max="10" onchange="update_options();"></td></tr></table>
+ </td>
+ <td>
+ <input type="checkbox" id="run" checked="checked" onchange="update_options();">Run</input>
<div id=val>-</div>
</td>
+ <td>
+ <div id=val2>-</div>
+ </td>
</tr>
</table>
</td>
@@ -58,7 +63,10 @@
<td style="vertical-align:top">
<table style="background-color:#000000">
<tr>
- <td id=pane0>
+ <td>
+ <div id="pane0">
+ <canvas id="canvas0">
+ </div>
</td>
</tr>
</table>
@@ -70,13 +78,21 @@
</table>
<script>
-var ring_size = 8192;
+
+var x_axis_height = 16 + 16;
+var y_axis_width = 24;
+var xlen = 600;
+var ylen = 400;
+
+var ring_size = xlen + 1;
var max_chans = 8 * 3;
var ringV = new Array(max_chans);
var ringA = new Array(max_chans);
var ringW = new Array(max_chans);
var ring_head = 0;
var total = 0;
+var running = 1;
+var last_running = 0;
var connection = 0;
var chans = 0;
@@ -91,9 +107,6 @@ var ctx = new Array(3);
var socket;
-var xlen = 600;
-var ylen = 400;
-
var bounce = 0;
var last_head = -1;
@@ -104,13 +117,64 @@ var ch_colour = new Array();
var ch_class = new Array();
var ch_flags = new Array();
var ch_order = new Array();
+
+var height = new Array(xlen);
+
var ov;
var worst_depth;
var order;
var do_title = 0;
+var sent_time = 0;
+var peak_time = 0;
+
+var viewport_offset_time = 0;
+var dirty = 1;
+var loading = 0;
+
+var rates = [ 10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 4, 3, 2, 1 ];
+var srates = [ "1s", "500ms", "200ms", "100ms", "50ms", "20ms", "10ms", "5ms", "2ms", "1ms", "500us", "400us", "300us", "200us", "100us" ];
+var intervals = [ 50, 20, 10, 5, 2, 1, 1, 0.5, 0.25, 0.1, 0.05, 0.05, 0.025, 0.025, 0.01 ];
+var sigs = [ 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 2, 3, 3, 2 ];
+
+function event_wheel(e)
+{
+ var f;
+
+ e = e ? e : window.event;
+ var raw = e.detail ? e.detail : e.wheelDelta;
+ var normal = e.detail ? e.detail * -1 : e.wheelDelta / 40;
+// document.getElementById('val').innerHTML =
+// "&nbsp;Raw Value: " + raw + "&nbsp;Normalized Value: " + normal;
+
+ f = viewport_offset_time + (normal / 3) * rates[rate] * 0.0001 * xlen / 10;
+ if (f < (-peak_time + (rates[rate] * 0.0001 * xlen) - 0.0001) || f > 0)
+ return cancelEvent(e);
+
+ viewport_offset_time = f;
+
+// document.getElementById("val").textContent = viewport_offset_time.toFixed(4)+" "+(-peak_time).toFixed(4);
+
+ update_options();
+
+ return cancelEvent(e);
+}
+
+function read_local_stg(stg_name, element_name, default_value)
+{
+ var n;
+
+ if (localStorage[stg_name]) {
+ n = parseFloat(localStorage[stg_name]);
+ document.getElementById(element_name).value = n;
+ return n;
+ }
+
+ return default_value;
+}
+
+rate = read_local_stg("aepd.rate", "rate", rate);
+watts_fullscale = read_local_stg("aepd.scale", "scale", watts_fullscale);
-var rates = [ 10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 4, 3, 2, 1 ];
-var srates = [ "1s", "500ms", "200ms", "100ms", "50ms", "20ms", "10ms", "5ms", "2ms", "1ms", "500us", "400us", "300us", "200us", "100us" ];
const CHFLAG_TOPLEVEL = 1;
const CHFLAG_VIRTUAL = 2;
@@ -211,15 +275,37 @@ function conn_retry()
try {
socket.onopen = function() {
+ /*
+ * clear it down
+ */
+ for (n = 0; n < xlen; n++)
+ for (i = 0; i < max_chans; i++)
+ ringW[i][n] = 0;
+ last_head = -1;
+ ring_head = -1;
grayOut(false);
- document.getElementById("wsdi_statustd").style.backgroundColor = "#40ff40";
- document.getElementById("wsdi_status").textContent = " Connected ";
connection = 1;
- socket.send("r"+(rate)+"\n");
+ update_options();
}
socket.onmessage = function got_packet(msg) {
+ if (msg.data[0] == 't') {
+
+ f = msg.data.substr(1);
+ y = f.split(' ');
+ sent_time = parseFloat(y[0]);
+ peak_time = sent_time; // + ((rates[rate] * 0.0001) * xlen);
+ running = y[1];
+ if (running != 0)
+ document.getElementById("run").checked = true;
+ else
+ document.getElementById("run").checked = false;
+ loading = xlen - 1;
+
+ return;
+ }
+
if (msg.data[0] == '=') {
channel_data = 1;
do_title = 1;
@@ -289,10 +375,16 @@ function conn_retry()
if (ring_head == ring_size)
ring_head = 0;
+ peak_time += (rates[rate] * 0.0001);
+ if (loading)
+ loading--;
+
total++;
block++;
}
+
+
if (!channel_data && do_title) {
var n, b, found, done_list;
@@ -319,8 +411,6 @@ function conn_retry()
do_all_children(b, 1, 0);
}
- document.getElementById("val").textContent = chans + ' ' + ov;
-
do_title = 0;
tab = '<table><tr style="background-color: #000000"><td></td>';
@@ -357,11 +447,13 @@ function conn_retry()
document.getElementById("cha").innerHTML = tab;
}
+
+ if (!loading)
+ dirty = 1;
+
}
socket.onclose = function(){
- document.getElementById("wsdi_statustd").style.backgroundColor = "#ff4040";
- document.getElementById("wsdi_status").textContent = " disconnected ";
connection = 0;
grayOut(true,{'zindex':'499'});
setTimeout("conn_retry();", 1000);
@@ -399,69 +491,193 @@ function units(n) {
function show(cv)
{
- var n, p, y, chan, q, z, peak;
+ var n, p, y, chan, q, z, peak, ro, rx, extent, x2, xx;
if (!connection || !ring_size)
return;
- if (last_head == ring_head)
+ if (!dirty)
return;
+ dirty = 0;
+
+ last_running = running;
+
ctx = canvas[0].getContext("2d");
ctx.save();
- ctx.globalCompositeOperation = "copy";
+// ctx.globalCompositeOperation = "copy";
ctx.globalAlpha = 1.0;
+ ctx.fillStyle = '#ffffff';
+ if (running == 0)
+ ctx.fillStyle = '#f0f0f0';
+ ctx.fillRect(0, 0, xlen + y_axis_width, ylen + x_axis_height);
+
+
+ /*
+ * time scrollbar
+ */
+ ctx.fillStyle = 'rgb(128,128,128)';
+ ctx.lineWidth = 0;
+
+ x2 = xlen + y_axis_width;
+ extent = rates[rate] * 0.0001 * xlen;
+ ro = peak_time + viewport_offset_time;
+ rx = ro - extent;
+ if (rx < 0)
+ rx = 0;
+
+ x = (x2 * (rx / peak_time));
+ xx = x2 * (extent / peak_time);
+ if (xx < 10) { // minimum width
+ x -= (10 - xx) / 2;
+ xx = 10;
+ }
+
+// document.getElementById("val").textContent = peak_time+" "+ro+" "+extent+" "+rx+" "+x;
+
+ ctx.fillRect(x, ylen + x_axis_height - 12, xx, 8);
+
q = ring_head;
last_head = q;
- //document.getElementById("val").textContent = q + " " + total + " ";
+ for (n = 0; n < xlen; n++)
+ height[n] = ylen -2;
- for (n = xlen - 1; n >= 0; n--) {
+ chan = 0;
+ while (chan < ch_order.length) {
- q--;
- if (q == 0)
- q = ring_size - 1;
+ z = ch_order[chan];
+ if (z >= chans || z == undefined) {
+ chan++;
+ continue;
+ }
- y = ylen - 2;
- chan = 0;
- peak = ylen;
- while (chan < ch_order.length) {
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = ch_colour[z];
- z = ch_order[chan];
- if (z < chans && z != undefined) {
+ for (n = xlen - 1; n >= 0; n--) {
- ctx.lineWidth = 1;
- ctx.strokeStyle = ch_colour[z];
+ q--;
+ if (q == 0)
+ q = ring_size - 1;
- ctx.beginPath();
+ ctx.beginPath();
+ if (q >= 0)
p = (ringW[z][q] * (ylen - 4)) / watts_fullscale;
- if ((ch_flags[z] & (CHFLAG_TOPLEVEL | CHFLAG_VIRTUAL)) == CHFLAG_TOPLEVEL) {
- ctx.moveTo(n + 0.5, ylen - 2);
- ctx.lineTo(n + 0.5, ylen - 2 - p);
- peak = ylen - 2 - p;
- } else {
+ if ((ch_flags[z] & (CHFLAG_TOPLEVEL | CHFLAG_VIRTUAL)) == CHFLAG_TOPLEVEL) {
+ ctx.moveTo(n + 0.5, ylen - 2);
+ ctx.lineTo(n + 0.5, ylen - 2 - p);
+ } else {
- ctx.moveTo(n + 0.5, y);
- ctx.lineTo(n + 0.5, y - p);
+ ctx.moveTo(n + 0.5, height[n]);
+ ctx.lineTo(n + 0.5, height[n] - p);
- y -= p;
- }
+ height[n] -= p;
+ }
+ ctx.stroke();
+ }
+
+ chan++;
+ }
+
+ /* x (time) axis marks */
+
+ ro = peak_time + viewport_offset_time;
+ r = ro;
+ /* rates[rate] * 0.0001s per pixel */
+ time_pp = rates[rate] * 0.0001;
+ limit = r - (xlen * time_pp);
+ interval = intervals[rate];
+
+ ctx.font = "8pt Arial";
+ ctx.textAlign = "center";
+ ctx.strokeStyle = '#c0c0c0';
+ ctx.fillStyle = '#000000';
+ ctx.globalAlpha = 0.7;
+
+ r = (((r / interval) >> 0) + 1) * interval;
+
+ while (r >= limit) {
+ var f;
+
+ if (r >= 0) {
+ x = xlen - (xlen * ((ro - r) / (ro - limit)));
+
+ f = r.toFixed(sigs[rate]);
+ if (sigs[rate]) {
+ while (f.charAt(f.length - 1) == '0')
+ f = f.substring(0, f.length - 1);
+ if (f.charAt(f.length - 1) == '.')
+ f = f.substring(0, f.length - 1);
+ }
+ ctx.lineWidth = 1;
+ if ( r.toFixed(0) == r)
+ ctx.lineWidth = 2;
+
+ if (x < xlen) {
+ ctx.beginPath();
+ ctx.moveTo(x, ylen);
+ ctx.lineTo(x, 1);
ctx.stroke();
}
- chan++;
+ ctx.fillText(f, x, ylen + 16 - 2);
+ }
+ r -= interval;
+ }
+
+ /* Y (power) axis marks */
+
+ sig = 2;
+ interval = 0.01;
+ if (watts_fullscale >= 0.2)
+ interval = 0.05;
+ if (watts_fullscale >= 0.5) {
+ interval = 0.1;
+ sig = 1;
+ }
+ if (watts_fullscale >= 1) {
+ interval = 0.25;
+ sig = 2;
+ }
+ if (watts_fullscale >= 2) {
+ interval = 0.5;
+ sig = 1;
+ }
+ if (watts_fullscale >= 5) {
+ sig = 0;
+ interval = 1;
+ }
+
+ r = (((watts_fullscale / interval) >> 0) + 1) * interval;
+
+ while (r >= 0) {
+ var f;
+
+ y = (ylen * ((watts_fullscale - r) / (watts_fullscale)));
+
+ f = r.toFixed(sig);
+ if (sig) {
+ while (f.charAt(f.length - 1) == '0')
+ f = f.substring(0, f.length - 1);
+ if (f.charAt(f.length - 1) == '.')
+ f = f.substring(0, f.length - 1);
}
ctx.lineWidth = 1;
- ctx.strokeStyle = '#ffffff';
+ if ( r.toFixed(0) == r)
+ ctx.lineWidth = 2;
+
ctx.beginPath();
- if (peak < y)
- y = peak;
- ctx.moveTo(n, y);
- ctx.lineTo(n, 1);
+ ctx.moveTo(0, y - 2);
+ ctx.lineTo(xlen, y - 2);
ctx.stroke();
+
+ ctx.fillText(f, xlen + (16 / 2), y + 2);
+
+ r -= interval;
}
ctx.restore();
@@ -470,10 +686,26 @@ function show(cv)
function update_options()
{
+ var run;
+ run = 0;
+
+ if (document.getElementById("run").checked)
+ run = 1;
+
rate = document.getElementById("rate").value;
- localStorage["ivmon.rate"] = document.getElementById("rate").value;
+ localStorage["aepd.rate"] = document.getElementById("rate").value;
document.getElementById("tb").textContent = srates[rate];
- socket.send("r"+rates[rate]+" "+xlen+"\n");
+
+ if (viewport_offset_time < (-peak_time + (rates[rate] * 0.0001 * xlen) - 0.0001))
+ viewport_offset_time = (-peak_time + (rates[rate] * 0.0001 * xlen) - 0.0001);
+
+ if (viewport_offset_time > 0)
+ viewport_offset_time = 0;
+
+ socket.send("r"+rates[rate]+" "+xlen+" "+run+" "+viewport_offset_time+"\n");
+ watts_fullscale = document.getElementById("scale").value;
+ localStorage["aepd.scale"] = document.getElementById("scale").value;
+ document.getElementById("pz").textContent = watts_fullscale + 'W';
}
/*
@@ -603,29 +835,70 @@ for (n = 0; n < max_chans; n++) {
}
for (n = 0; n < 1; n++) {
- canvas[n] = document.createElement('canvas');
- canvas[n].height = ylen;
- canvas[n].width = xlen;
+ canvas[n] = document.getElementById('canvas0');
+ canvas[n].height = ylen + x_axis_height;
+ canvas[n].width = xlen + y_axis_width;
- document.getElementById('pane0').appendChild(canvas[n]);
+// document.getElementById('pane0').appendChild(canvas[n]);
}
-
-if (localStorage["ivmon.rate"]) {
- rate = document.getElementById("rate").value =
- parseInt(localStorage["ivmon.rate"]);
- document.getElementById("rate").value = rate;
- //update_options();
-}
+hookEvent(document.getElementById("canvas0"), "mousewheel", event_wheel);
grayOut(true,{'zindex':'499'});
conn_retry();
+var _ctr = 0;
(function animloop(){
requestAnimFrame(animloop);
show();
})();
+function cancelEvent(e)
+{
+ e = e ? e : window.event;
+ if(e.stopPropagation)
+ e.stopPropagation();
+ if(e.preventDefault)
+ e.preventDefault();
+ e.cancelBubble = true;
+ e.cancel = true;
+ e.returnValue = false;
+ return false;
+}
+
+function hookEvent(element, eventName, callback)
+{
+ if(typeof(element) == "string")
+ element = document.getElementById(element);
+ if(element == null)
+ return;
+ if(element.addEventListener)
+ {
+ if(eventName == 'mousewheel')
+ element.addEventListener('DOMMouseScroll', callback, true);
+ element.addEventListener(eventName, callback, false);
+ }
+ else if(element.attachEvent)
+ element.attachEvent("on" + eventName, callback);
+}
+
+function unhookEvent(element, eventName, callback)
+{
+ if(typeof(element) == "string")
+ element = document.getElementById(element);
+ if(element == null)
+ return;
+ if(element.removeEventListener)
+ {
+ if(eventName == 'mousewheel')
+ element.removeEventListener('DOMMouseScroll', callback, true);
+ element.removeEventListener(eventName, callback, false);
+ }
+ else if(element.detachEvent)
+ element.detachEvent("on" + eventName, callback);
+}
+
+
</script>
</article>
</body>
diff --git a/aepd/websocket-protocol.c b/aepd/websocket-protocol.c
index 7420cd5..43bb8eb 100644
--- a/aepd/websocket-protocol.c
+++ b/aepd/websocket-protocol.c
@@ -75,11 +75,14 @@ static int callback_http(struct libwebsocket_context *context,
struct per_session_data__linaro_aepd {
struct libwebsocket *wsi;
- unsigned long ringbuffer_tail;
+ long ringbuffer_tail;
double sam[MAX_PROBES * CHANNELS_PER_PROBE * 3];
int sam_valid;
int stride;
int channels_sent_flag;
+ int issue_timestamp;
+ int viewport_budget;
+ double viewport_offset_time;
};
extern struct aep_context aep_context;
@@ -97,7 +100,8 @@ callback_linaro_aepd(struct libwebsocket_context *context,
char buf[LWS_SEND_BUFFER_PRE_PADDING + 16384 + LWS_SEND_BUFFER_POST_PADDING];
char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
int budget = 10;
- unsigned long extent;
+ int no_valid_sam_flag = 0;
+ long extent;
long l;
switch (reason) {
@@ -108,10 +112,36 @@ callback_linaro_aepd(struct libwebsocket_context *context,
pss->wsi = wsi;
pss->stride = 100;
pss->channels_sent_flag = 0;
+ pss->issue_timestamp = 1;
+ pss->viewport_offset_time = 0;
+ pss->viewport_budget = 0;
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
+ if (pss->issue_timestamp) {
+ pss->issue_timestamp = 0;
+
+ /*
+ * we want to set the sample time context for what we are
+ * about to send
+ */
+
+ l = pss->ringbuffer_tail;
+
+ if (l <= (long)aepd_shared->fifo_pos)
+ extent = aepd_shared->fifo_pos - l;
+ else
+ extent = (aepd_shared->modulo_integer_chan_size - l) + aepd_shared->fifo_pos;
+
+ extent /= aepd_shared->chans * sizeof(double) * 3;
+
+ p += sprintf(p, "t%f %d", aepd_shared->fifo_head_time - ((double)extent * 0.0001), aepd_shared->stop_flag ^ 1);
+ fprintf(stderr, "timestamp headtime=%f aepd_shared->fifo_pos=%ld extent=%ld, l=%ld\n", aepd_shared->fifo_head_time, aepd_shared->fifo_pos, extent, l);
+ puts(&buf[LWS_SEND_BUFFER_PRE_PADDING]);
+ goto send;
+ }
+
if (!pss->channels_sent_flag) {
/* signal it's a message with channel names */
@@ -130,30 +160,59 @@ callback_linaro_aepd(struct libwebsocket_context *context,
}
/*
+ * if we're not following the samples head, we don't need to
+ * spam the viewport any more than one viewport's worth of samples
+ * we're still collecting samples, he can get them by moving his
+ * viewport offset
+ */
+
+ if (pss->viewport_offset_time < -0.00009)
+ if (!pss->viewport_budget) {
+// fprintf(stderr, "bailing %f\n", pss->viewport_offset_time);
+ break;
+ }
+
+ /*
* aggregate up to 'budget' results in one websocket message
*/
while (budget--) {
- if (pss->ringbuffer_tail <= aepd_shared->fifo_pos)
+ if (pss->ringbuffer_tail <= (long)aepd_shared->fifo_pos)
extent = aepd_shared->fifo_pos - pss->ringbuffer_tail;
else
extent = (aepd_shared->modulo_integer_chan_size - pss->ringbuffer_tail) + aepd_shared->fifo_pos;
- if (extent < (pss->stride * aepd_shared->chans * sizeof(double) * 3)) {
+ if (pss->ringbuffer_tail >= 0 && extent < (pss->stride * aepd_shared->chans * sizeof(double) * 3)) {
budget = 0;
continue;
}
- lseek(aepd_shared->fd_fifo_read, pss->ringbuffer_tail, SEEK_SET);
- if (read(aepd_shared->fd_fifo_read, &sam[0], aepd_shared->chans * sizeof(double) * 3) < 0)
- fprintf(stderr, "fifo read fail\n");
+ if (pss->ringbuffer_tail < 0) {
+ no_valid_sam_flag = 1;
+ pss->sam_valid = 0;
+ for (n = 0; n < aepd_shared->chans * 3; n++)
+ sam[n] = pss->sam[n];
+ } else {
+
+ lseek(aepd_shared->fd_fifo_read, pss->ringbuffer_tail, SEEK_SET);
+ if (read(aepd_shared->fd_fifo_read, &sam[0], aepd_shared->chans * sizeof(double) * 3) < 0)
+ fprintf(stderr, "fifo read fail\n");
+ }
+
+ if (pss->viewport_budget)
+ pss->viewport_budget--;
+ else
+ if (pss->viewport_offset_time < -0.00009) {
+// fprintf(stderr, "bail2: %f\n", pss->viewport_offset_time);
+ goto send;
+ }
pss->ringbuffer_tail += (pss->stride * aepd_shared->chans * sizeof(double) * 3 );
- if (pss->ringbuffer_tail > aepd_shared->modulo_integer_chan_size)
+ if (pss->ringbuffer_tail > (long)aepd_shared->modulo_integer_chan_size)
pss->ringbuffer_tail -= aepd_shared->modulo_integer_chan_size;
- if (pss->sam_valid) {
+ if (pss->sam_valid || no_valid_sam_flag) {
/*
* Javascript can't cope with binary, so we must ascii-fy it
@@ -177,9 +236,10 @@ callback_linaro_aepd(struct libwebsocket_context *context,
*p++ = ';';
*p = '\0';
}
-
- memcpy(&pss->sam[0], &sam[0], aepd_shared->chans * sizeof(double) * 3);
- pss->sam_valid = 1;
+ if (!no_valid_sam_flag) {
+ memcpy(&pss->sam[0], &sam[0], aepd_shared->chans * sizeof(double) * 3);
+ pss->sam_valid = 1;
+ }
}
send:
/*
@@ -204,13 +264,22 @@ send:
switch (*(char *)in) {
case 'r':
- if (sscanf(((char *)in) + 1, "%lf %lf\n", &d[0], &d[1]) == 2)
+ puts((char *)in + 1);
+ if (sscanf(((char *)in) + 1, "%lf %lf %lf %lf\n", &d[0], &d[1], &d[2], &d[3]) == 4) {
pss->stride = (int)d[0];
+ pss->viewport_offset_time = d[3];
+
+// fprintf(stderr, "d[0] = %f, d[1] = %f, d[2] = %f\n", d[0], d[1], d[2]);
l = aepd_shared->fifo_pos - ((int)d[1] * pss->stride * aepd_shared->chans * sizeof(double) * 3);
- while (l < 0)
- l += aepd_shared->modulo_integer_chan_size;
+ l += (pss->viewport_offset_time / 0.0001) * aepd_shared->chans * sizeof(double) * 3;
+ if (pss->viewport_offset_time)
+ pss->viewport_budget = d[1];
pss->ringbuffer_tail = l;
+ aepd_shared->stop_flag = ((int)d[2]) ^ 1;
+ pss->issue_timestamp = 1;
libwebsocket_callback_on_writable(context, wsi);
+ } else
+ fprintf(stderr, "sscanf failed\n");
break;
}
break;
diff --git a/libarmep/sample.c b/libarmep/sample.c
index f108438..f17a803 100644
--- a/libarmep/sample.c
+++ b/libarmep/sample.c
@@ -307,7 +307,8 @@ unripe:
aep_result->triggered = ch->triggered;
aep_result->chans = hit;
- aep_result->samtime = ((double)ch->samples - (double)ch->ring_samples) / 10000.0;
+ aep_result->samtime = ((double)ch->samples_seen - (double)ch->ring_samples) / 10000.0;
+
n = 0;
for (m = 0; m <= aep->aep_context->highest; m++) {