aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2012-10-06 20:04:42 +0800
committerAndy Green <andy.green@linaro.org>2012-10-15 07:37:49 +0800
commit68d6c70d6b330941a5f22a35269d63d9d920064a (patch)
treeae26a7615239a3a67b30bb7d80e99dbee8e33a92
parente1d63c1dfceef029bff15eda57fce6255bd159eb (diff)
introduce aepd
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r--Makefile.am2
-rw-r--r--README8
-rw-r--r--aepd/Makefile.am25
-rw-r--r--aepd/aepd.h65
-rw-r--r--aepd/main.c313
-rw-r--r--aepd/share/aepscope.html475
-rw-r--r--aepd/share/favicon.icobin0 -> 1150 bytes
-rw-r--r--aepd/share/linaro-logo-32.pngbin0 -> 5126 bytes
-rw-r--r--aepd/websocket-protocol.c218
-rw-r--r--configure.ac3
-rw-r--r--libarmep/sample.c2
-rw-r--r--libarmep/service.c18
12 files changed, 1122 insertions, 7 deletions
diff --git a/Makefile.am b/Makefile.am
index 6fff323..0a19074 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,2 +1,2 @@
+SUBDIRS = libarmep aepd arm-probe
-SUBDIRS=libarmep arm-probe
diff --git a/README b/README
index 0ed94e7..0134290 100644
--- a/README
+++ b/README
@@ -16,6 +16,14 @@ Make sure you have
packages installed.
+To build the websockets-based daemon, you will need to build libwebsockets,
+built and installed on your box, which you can get from here
+
+git clone git://git.warmcat.com/libwebsockets
+
+It uses the same autotools based build approach.
+
+
To initially configure the sources for your system, or if you change the
autotools-related content:
diff --git a/aepd/Makefile.am b/aepd/Makefile.am
new file mode 100644
index 0000000..9096ae3
--- /dev/null
+++ b/aepd/Makefile.am
@@ -0,0 +1,25 @@
+bin_PROGRAMS=aepd
+aepd_SOURCES=main.c websocket-protocol.c
+aepd_CFLAGS=-fPIC -Wall -Werror -std=gnu99 -pedantic -DINSTALL_DATADIR=\"${datarootdir}\"
+aepd_LDFLAGS=-fPIC
+aepd_LDADD=-L../libarmep -larmep -lwebsockets
+
+#
+# cook a random test cert and key
+# notice your real cert and key will want to be 0600 permissions
+#
+aepd.pem aepd.key.pem:
+ printf "GB\nErewhon\nAll around\naepd-test-cert\n\nlocalhost\nnone@invalid.org\n" | \
+ openssl req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout \
+ ./aepd.key.pem -out ./aepd.pem >/dev/null 2>&1 && \
+ chmod 644 ./aepd.key.pem \
+ ./aepd.pem
+
+clean-local:
+ rm -f ./aepd.key.pem ./aepd.pem
+
+install-data-local: aepd.pem aepd.key.pem
+ mkdir -p $(DESTDIR)$(datadir)/aepd
+ cp share/aepscope.html share/favicon.ico aepd.pem aepd.key.pem share/linaro-logo-32.png \
+ $(DESTDIR)$(datadir)/aepd
+
diff --git a/aepd/aepd.h b/aepd/aepd.h
new file mode 100644
index 0000000..cb3ed3d
--- /dev/null
+++ b/aepd/aepd.h
@@ -0,0 +1,65 @@
+/*
+ * Author: Andy Green <andy.green@linaro.org>
+ * Copyright (C) 2012 Linaro, LTD
+ * Libwebsocket demo code (C) 2010-2012 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+
+#include <libwebsockets.h>
+
+#include "../libarmep/libarmep.h"
+
+#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/aepd"
+
+enum demo_protocols {
+ /* always first */
+ PROTOCOL_HTTP,
+
+ PROTOCOL_AEPD,
+
+ /* always last */
+ DEMO_PROTOCOL_COUNT
+};
+
+#define MAX_FIFO_EXTENT_SECONDS 10
+
+#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;
+ int fd_fifo_write;
+ int fd_fifo_read;
+ int fifo_wrapped;
+ int chans;
+ unsigned long fifo_pos;
+ double fifo_head_time;
+ unsigned long modulo_integer_chan_size;
+};
+
+extern struct aepd_shared *aepd_shared;
diff --git a/aepd/main.c b/aepd/main.c
new file mode 100644
index 0000000..c11c91e
--- /dev/null
+++ b/aepd/main.c
@@ -0,0 +1,313 @@
+/*
+ * Author: Andy Green <andy.green@linaro.org>
+ * Copyright (C) 2012 Linaro, LTD
+ * Libwebsocket demo code (C) 2010-2012 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "aepd.h"
+
+struct aepd_shared *aepd_shared;
+static double sam[MAX_PROBES * CHANNELS_PER_PROBE * DOUBLES_PER_CH_SAMPLE];
+extern struct libwebsocket_protocols protocols[];
+
+void zero_fifo(void)
+{
+ int n;
+
+ lseek(aepd_shared->fd_fifo_write, 0, SEEK_SET);
+ aepd_shared->fifo_pos = 0;
+ aepd_shared->fifo_wrapped = 0;
+ for (n = 0; n < sizeof(sam) / sizeof(sam[0]); n++)
+ sam[n] = 0.0;
+ if (aepd_shared->chans > 0)
+ aepd_shared->modulo_integer_chan_size =
+ (MAX_FIFO_EXTENT / (aepd_shared->chans * sizeof(double) * 3)) *
+ (aepd_shared->chans * sizeof(double) * 3);
+}
+
+int add_fifo(void *data, unsigned int length)
+{
+ long l;
+
+ l = write(aepd_shared->fd_fifo_write, data, length);
+ if (l < length) {
+ fprintf(stderr, "fifo write failed...\n");
+ return (int)l;
+ }
+
+ /*
+ * make sure the other processes can see it...
+ */
+ fdatasync(aepd_shared->fd_fifo_write);
+
+ aepd_shared->fifo_pos += length;
+ if (aepd_shared->fifo_pos >= aepd_shared->modulo_integer_chan_size) {
+ aepd_shared->fifo_wrapped = 1;
+ aepd_shared->fifo_pos = 0;
+ lseek(aepd_shared->fd_fifo_write, 0, SEEK_SET);
+ }
+
+ return 0;
+}
+
+struct aep_context aep_context = {
+ .config_filepath = "./config",
+ .highest = -1,
+ .decimate = 1,
+ .mv_min = 400,
+ .trigger_filter_us = 400,
+ .end_trigger_filter_us = 500000,
+ .average_len = 1,
+ .configuration_name = "default_configuration",
+ .verbose = 0,
+};
+
+
+static struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "port", required_argument, NULL, 'p' },
+ { "ssl", no_argument, NULL, 's' },
+ { "interface", required_argument, NULL, 'i' },
+ { NULL, 0, 0, 0 }
+};
+
+static int loop = 1;
+
+void sighandler(int sig)
+{
+ loop = 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int n = 0, m;
+ const char *cert_path =
+ LOCAL_RESOURCE_PATH"/aepd.pem";
+ const char *key_path =
+ LOCAL_RESOURCE_PATH"/aepd.key.pem";
+ int port = 15164;
+ int use_ssl = 0;
+ struct libwebsocket_context *context;
+ int opts = 0;
+ char interface_name[128] = "";
+ const char *interface_ptr = NULL;
+ struct aep_result *aep_result;
+ struct timeval tv;
+ unsigned long last = 0;
+ unsigned long ms10 = -1;
+
+ fprintf(stderr,
+ "ARM Energy Probe Daemon (C) Copyright 2012 Linaro, LTD\n"
+ "licensed under LGPL2.1\n");
+
+ signal(SIGINT, sighandler);
+
+ /*
+ * create our lump of shared memory
+ * which is usable by all forked processes
+ */
+
+ n = open("/dev/zero", O_RDWR);
+ aepd_shared = mmap(NULL, sizeof (struct aepd_shared),
+ PROT_READ | PROT_WRITE, MAP_SHARED, n, 0);
+ close(n);
+
+ /*
+ * open spool fifo for result data we can serve
+ * it's a large ring buffer to deal with long term pretrigger
+ * websocket clients can make requests for variously-zoomed
+ * parts of this buffer.
+ */
+
+ aepd_shared->fifo_filepath = tmpnam(aepd_shared->fifo_filepath_stg);
+ aepd_shared->fd_fifo_write = open(aepd_shared->fifo_filepath,
+ O_CREAT | O_RDWR, 0600);
+ if (aepd_shared->fd_fifo_write < 0) {
+ fprintf(stderr, "Unable to open sample fifo file %s\n",
+ aepd_shared->fifo_filepath);
+ return -1;
+ }
+ aepd_shared->fd_fifo_read = open(aepd_shared->fifo_filepath, O_RDONLY);
+ if (aepd_shared->fd_fifo_read < 0) {
+ fprintf(stderr, "Unable to open sample fifo file %s for read\n",
+ aepd_shared->fifo_filepath);
+ return -1;
+ }
+
+ zero_fifo();
+
+ while (n >= 0) {
+ n = getopt_long(argc, argv, "si:p:", options, NULL);
+ if (n < 0)
+ continue;
+ switch (n) {
+
+ case 's':
+ use_ssl = 1;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'i':
+ strncpy(interface_name, optarg, sizeof interface_name);
+ interface_name[(sizeof interface_name) - 1] = '\0';
+ break;
+
+ default:
+ case 'h':
+ fprintf(stderr, "Usage: arm-probe \n"
+ " [--ssl -s] Listen using SSL / Encrypted link\n"
+ " [--interface -i <if>] Listen on specific "
+ "interface, eg, eth1\n"
+ " [--port -p -<port>] Port to listen on "
+ "(default %u)\n", port
+ );
+ exit(1);
+ }
+ }
+
+ /* libwebsockets context */
+
+ if (!use_ssl)
+ cert_path = key_path = NULL;
+
+ context = libwebsocket_create_context(port, interface_ptr, protocols,
+ NULL,
+ cert_path, key_path, -1, -1, opts);
+ if (context == NULL) {
+ fprintf(stderr, "libwebsocket init failed\n");
+ return -1;
+ }
+
+ aep_context.original_count_channel_names = aep_context.count_channel_names;
+
+ configure(&aep_context, NULL, "xx", aep_context.config_filepath, NULL);
+
+
+ /*
+ * fork off the AEP service process
+ * runs in its own process to exploit SMP to dedicate one core for that
+ * what happens to samples is decoupled from capture process with large
+ * shared-memory buffer to allow for jitter
+ */
+
+ if (aep_init_and_fork(&aep_context, argv) < 1)
+ return 0; /* child process exit */
+
+
+ n = fork();
+ if (n < 0) {
+ fprintf(stderr, "websockets service fork failed\n");
+ return n;
+ }
+ if (!n) {
+ strcpy(argv[0] + strlen(argv[0]), " - websockets server");
+
+ /* websockets service process */
+
+ while (1) {
+ if (libwebsocket_service(context, 100))
+ break;
+ if (getppid() == 1)
+ break;
+
+ gettimeofday(&tv, NULL);
+
+ ms10 = (tv.tv_sec * 10) + (tv.tv_usec / 100000);
+
+ if (ms10 > last) {
+ last = ms10;
+ libwebsocket_callback_on_writable_all_protocol(&protocols[1]);
+ }
+ }
+
+ libwebsocket_context_destroy(context);
+ return 0;
+ }
+
+ /*
+ * this process just has to deal with servicing AEP output from the
+ * AEP service process and making it available to the websocket
+ * services via the fifo ring file
+ */
+
+ aepd_shared->chans = -1;
+
+ while (loop) {
+
+ aep_result = aep_wait_for_next_result(&aep_context);
+ if (!aep_result) {
+ if (aep_context.aep_shared->finished)
+ loop = 0;
+
+ continue;
+ }
+
+ /*
+ * we have the next result in aep_result..
+ * voltage and current per channel
+ */
+
+ m = 0;
+ for (n = 0; n < aep_result->chans * 2; n += 2) {
+
+ /*
+ * accumulate in V, A, W per-channel.
+ * We do summing like that so that we can compute
+ * averages over any distance without iteration, by
+ * (sample(x + distance) - sample(x)) / distance.
+ * We can recover individual intersample delta still
+ * by sample(x + 1) - sample(x) if we want it.
+ * Doubles are used to maximize dynamic range.
+ */
+
+ sam[m++] += aep_result->buf[n];
+ sam[m++] += aep_result->buf[n + 1];
+ sam[m++] += aep_result->buf[n] * aep_result->buf[n + 1];
+ }
+
+ /*
+ * notice we have expanded the V/A 2 sample data
+ * into W as well. That's because average of instantaneous W
+ * is not at all the same as average V * average A
+ */
+
+ 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 with it */
+
+ aep_free_result(&aep_context);
+ }
+
+ close(aepd_shared->fd_fifo_write);
+ close(aepd_shared->fd_fifo_read);
+ unlink(aepd_shared->fifo_filepath);
+
+ sem_close(aep_context.semaphore);
+
+ fprintf(stderr, "exited\n");
+
+ return 0;
+}
+
diff --git a/aepd/share/aepscope.html b/aepd/share/aepscope.html
new file mode 100644
index 0000000..c66e82b
--- /dev/null
+++ b/aepd/share/aepscope.html
@@ -0,0 +1,475 @@
+<!DOCTYPE html>
+<!--
+/*
+ * Author: Andy Green <andy.green@linaro.org>
+ * Copyright (C) 2012 Linaro, LTD
+ * Libwebsocket demo code (C) 2010-2012 Andy Green <andy@warmcat.com>
+ * Repo: http://git.linaro.org/gitweb?p=tools/arm-probe.git;a=summary
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+-->
+<html lang="en">
+<head>
+<meta charset=utf-8 />
+<title>ARM Energy Probe aepd UI</title>
+</head>
+<body>
+<header>
+</header>
+<article>
+<table>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td>
+ <img src="linaro-logo-32.png">
+ </td>
+ <td id=wsdi_statustd align=center>
+ <div id=wsdi_status>Not initialized</div>
+ </td>
+ <td>
+ Resolution<br>
+ <select id=rate onchange="update_options();">
+ <option value=1>100us</option>
+ <option value=2>200us</option>
+ <option value=5>500us</option>
+ <option value=10>1ms</option>
+ <option value=20>2ms</option>
+ <option value=50>5ms</option>
+ <option value=100>10ms</option>
+ <option value=200>20ms</option>
+ <option value=500>50ms</option>
+ <option value=1000>100ms</option>
+ <option value=5000>500ms</option>
+ <option value=10000>1s</option>
+ </select>
+ </td>
+ <td>
+ <div id=val>-</div>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table style="background-color:#000000">
+ <tr>
+ <td id=pane0>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>
+ <div id="cha"></div>
+ </td>
+ </tr>
+</table>
+
+<script>
+var ring_size = 8192;
+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 connection = 0;
+var chans = 0;
+
+var start = 10;
+var main_start = 25;
+
+var rate;
+var watts_fullscale = 4.0;
+var canvas = new Array(3);
+var ctx = new Array(3);
+
+var socket;
+
+var xlen = 600;
+var ylen = 400;
+
+var bounce = 0;
+var last_head = -1;
+
+var colours = new Array();
+colours[0] = "#ff0000";
+colours[1] = "#c00000";
+colours[2] = "#a00000";
+colours[3] = "#e0e000";
+colours[4] = "#0000c0";
+colours[5] = "#a0c0e0";
+colours[6] = "#e000e0";
+colours[7] = "#0000ff";
+colours[8] = "#000000";
+
+
+function get_appropriate_ws_url()
+{
+ var pcol;
+ var u = document.URL;
+
+ /*
+ * We open the websocket encrypted if this page came on an
+ * https:// url itself, otherwise unencrypted
+ */
+
+ if (u.substring(0, 5) == "https") {
+ pcol = "wss://";
+ u = u.substr(8);
+ } else {
+ pcol = "ws://";
+ if (u.substring(0, 4) == "http")
+ u = u.substr(7);
+ }
+
+ u = u.split('/');
+
+ return pcol + u[0];
+}
+
+function conn_retry()
+{
+ var r1, r2, r3, x, y, chan, z, block;
+
+ if (connection)
+ return;
+
+ socket = new WebSocket(get_appropriate_ws_url(), "linaro.aepd");
+
+ try {
+ socket.onopen = function() {
+ grayOut(false);
+ document.getElementById("wsdi_statustd").style.backgroundColor = "#40ff40";
+ document.getElementById("wsdi_status").textContent = " Connected ";
+ connection = 1;
+ socket.send("r"+(rate)+"\n");
+ }
+
+ socket.onmessage = function got_packet(msg) {
+
+ z = msg.data.split(';');
+
+ block = 0;
+ while (block < (z.length - 1)) {
+
+ y = z[block].split(',');
+ chan = 0;
+ while (chan < (y.length - 1)) {
+
+ x = y[chan].split(' ');
+ if (x.length != 3) {
+ chan++;
+ continue;
+ }
+
+ if (x[0].charAt(0) == '-')
+ r1 = (-x[0].substring(1));
+ else
+ r1 = (+x[0]);
+
+ if (x[1].charAt(0) == '-')
+ r2 = (-x[1].substring(1));
+ else
+ r2 = (+x[1]);
+
+ if (x[2].charAt(0) == '-')
+ r3 = (-x[2].substring(1));
+ else
+ r3 = (+x[2]);
+
+
+ ringV[chan][ring_head] = r1;
+ ringA[chan][ring_head] = r2;
+ ringW[chan][ring_head] = r3;
+
+ chan++;
+ }
+
+ chans = chan;
+
+ ring_head++;
+ if (ring_head == ring_size)
+ ring_head = 0;
+
+ total++;
+
+ block++;
+ }
+ }
+
+ 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);
+ }
+ } catch(exception) {
+// alert('<p>Error' + exception);
+// setTimeout("conn_retry", 1000);
+ }
+}
+
+function units(n) {
+ var s = '';
+
+ if (n < 0) {
+ s = '-';
+ n = -n;
+ }
+
+ if (n >= 1000000000) {
+ b = n % 1000000;
+ return (s + (n - b) / 1000000000);
+ } else
+ if (n >= 1000000) {
+ b = n % 1000;
+ return (s + (n - b) / 1000000 + 'm');
+ } else
+ if (n >= 1000)
+ return (s + (n / 1000).toFixed(3) + 'u');
+ else
+ if (n != 0)
+ return (s + n.toFixed(1) + 'n');
+
+ return ('0');
+}
+
+function show(cv)
+{
+ var n, p, y, chan, q;
+
+ if (!connection)
+ return;
+
+ if (last_head == ring_head)
+ return;
+
+ ctx = canvas[0].getContext("2d");
+ ctx.save();
+ ctx.globalCompositeOperation = "copy";
+ ctx.globalAlpha = 1.0;
+
+ q = ring_head;
+ last_head = q;
+
+ //document.getElementById("val").textContent = q + " " + total + " ";
+
+ for (n = xlen - 1; n >= 0; n--) {
+
+ q--;
+ if (q == 0)
+ q = ring_size - 1;
+
+ y = ylen - 2;
+ chan = 0;
+ while (chan < chans) {
+
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = colours[chan];
+
+ ctx.beginPath();
+
+ p = (ringW[chan][q] * ylen) / watts_fullscale;
+
+ ctx.moveTo(n + 0.5, y);
+ ctx.lineTo(n + 0.5, y - p);
+
+ y -= p;
+
+ ctx.stroke();
+ chan++;
+ }
+
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = '#ffffff';
+ ctx.beginPath();
+ ctx.moveTo(n, y);
+ ctx.lineTo(n, 1);
+ ctx.stroke();
+ }
+
+ ctx.restore();
+}
+
+
+function update_options()
+{
+ rate = document.getElementById("rate").value;
+ localStorage["ivmon.rate"] = rate;
+ socket.send("r"+(rate)+"\n");
+}
+
+/*
+ * This section around grayOut came from here:
+ * http://www.codingforums.com/archive/index.php/t-151720.html
+ * Assumed public domain
+ */
+
+function grayOut(vis, options) {
+ var options = options || {};
+ var zindex = options.zindex || 50;
+ var opacity = options.opacity || 70;
+ var opaque = (opacity / 100);
+ var bgcolor = options.bgcolor || '#000000';
+ var dark = document.getElementById('darkenScreenObject');
+
+ if (!dark) {
+ var tbody = document.getElementsByTagName("body")[0];
+ var tnode = document.createElement('div');
+ tnode.style.position = 'absolute';
+ tnode.style.top = '0px';
+ tnode.style.left = '0px';
+ tnode.style.overflow = 'hidden';
+ tnode.style.display ='none';
+ tnode.id = 'darkenScreenObject';
+ tbody.appendChild(tnode);
+ dark = document.getElementById('darkenScreenObject');
+ }
+ if (vis) {
+ dark.style.opacity = opaque;
+ dark.style.MozOpacity = opaque;
+ dark.style.filter ='alpha(opacity='+opacity+')';
+ dark.style.zIndex = zindex;
+ dark.style.backgroundColor = bgcolor;
+ dark.style.width = gsize(1);
+ dark.style.height = gsize(0);
+ dark.style.display ='block';
+ addEvent(window, "resize",
+ function() {
+ dark.style.height = gsize(0);
+ dark.style.width = gsize(1);
+ }
+ );
+ } else {
+ dark.style.display = 'none';
+ removeEvent(window, "resize",
+ function() {
+ dark.style.height = gsize(0);
+ dark.style.width = gsize(1);
+ }
+ );
+ }
+}
+
+function gsize(ptype)
+{
+ var h = document.compatMode == 'CSS1Compat' &&
+ !window.opera ?
+ document.documentElement.clientHeight :
+ document.body.clientHeight;
+ var w = document.compatMode == 'CSS1Compat' &&
+ !window.opera ?
+ document.documentElement.clientWidth :
+ document.body.clientWidth;
+ if (document.body &&
+ (document.body.scrollWidth || document.body.scrollHeight)) {
+ var pageWidth = (w > (t = document.body.scrollWidth)) ?
+ ("" + w + "px") : ("" + (t) + "px");
+ var pageHeight = (h > (t = document.body.scrollHeight)) ?
+ ("" + h + "px") : ("" + (t) + "px");
+ } else if (document.body.offsetWidth) {
+ var pageWidth = (w > (t = document.body.offsetWidth)) ?
+ ("" + w + "px") : ("" + (t) + "px");
+ var pageHeight =(h > (t = document.body.offsetHeight)) ?
+ ("" + h + "px") : ("" + (t) + "px");
+ } else {
+ var pageWidth = '100%';
+ var pageHeight = '100%';
+ }
+ return (ptype == 1) ? pageWidth : pageHeight;
+}
+
+function addEvent( obj, type, fn ) {
+ if ( obj.attachEvent ) {
+ obj['e' + type + fn] = fn;
+ obj[type+fn] = function() { obj['e' + type+fn]( window.event );}
+ obj.attachEvent('on' + type, obj[type + fn]);
+ } else
+ obj.addEventListener(type, fn, false);
+}
+
+function removeEvent( obj, type, fn ) {
+ if ( obj.detachEvent ) {
+ obj.detachEvent('on' + type, obj[type + fn]);
+ obj[type + fn] = null;
+ } else
+ obj.removeEventListener(type, fn, false);
+}
+
+/*
+ * end of grayOut related stuff
+ *
+ * requestAnimFrame stuff came from here
+ * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+ * presumed public domain
+ */
+
+window.requestAnimFrame = (function(){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(/* function */ callback, /* DOMElement */ element){
+ window.setTimeout(callback, 1000 / 24);
+ };
+})();
+
+/*
+ * end of requestAnimFrame stuff
+ */
+
+for (n = 0; n < max_chans; n++) {
+ ringV[n] = new Array(ring_size);
+ ringA[n] = new Array(ring_size);
+ ringW[n] = new Array(ring_size);
+}
+
+for (n = 0; n < 1; n++) {
+ canvas[n] = document.createElement('canvas');
+ canvas[n].height = ylen;
+ canvas[n].width = xlen;
+
+ document.getElementById('pane0').appendChild(canvas[n]);
+}
+
+
+if (localStorage["ivmon.rate"]) {
+ rate = document.getElementById("rate").value =
+ parseInt(localStorage["ivmon.rate"]);
+ document.getElementById("rate").value = rate;
+}
+
+grayOut(true,{'zindex':'499'});
+conn_retry();
+
+(function animloop(){
+ requestAnimFrame(animloop);
+ show();
+})();
+
+</script>
+</article>
+</body>
+</html>
+
diff --git a/aepd/share/favicon.ico b/aepd/share/favicon.ico
new file mode 100644
index 0000000..576d338
--- /dev/null
+++ b/aepd/share/favicon.ico
Binary files differ
diff --git a/aepd/share/linaro-logo-32.png b/aepd/share/linaro-logo-32.png
new file mode 100644
index 0000000..6b245d0
--- /dev/null
+++ b/aepd/share/linaro-logo-32.png
Binary files differ
diff --git a/aepd/websocket-protocol.c b/aepd/websocket-protocol.c
new file mode 100644
index 0000000..cd81512
--- /dev/null
+++ b/aepd/websocket-protocol.c
@@ -0,0 +1,218 @@
+/*
+ * Author: Andy Green <andy.green@linaro.org>
+ * Copyright (C) 2012 Linaro, LTD
+ * Libwebsocket demo code (C) 2010-2012 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "aepd.h"
+
+/*
+ * We take a strict whitelist approach to stop ../ attacks
+ */
+
+struct serveable {
+ const char *urlpath;
+ const char *mimetype;
+};
+
+static struct serveable whitelist[] = {
+ { "/favicon.ico", "image/x-icon" },
+ { "/linaro-logo-32.png", "image/png" },
+
+ /* last one is the default served if no match */
+ { "/aepscope.html", "text/html" },
+};
+
+/* this protocol server (always the first one) just knows how to do HTTP */
+
+static int callback_http(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason, void *user,
+ void *in, size_t len)
+{
+ int n;
+ char buf[512];
+
+ switch (reason) {
+ case LWS_CALLBACK_HTTP:
+
+ for (n = 0; n < (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
+ if (in && strcmp(in, whitelist[n].urlpath) == 0)
+ break;
+
+ sprintf(buf, LOCAL_RESOURCE_PATH"%s", whitelist[n].urlpath);
+
+ if (libwebsockets_serve_http_file(wsi, buf, whitelist[n].mimetype))
+ fprintf(stderr, "Failed to send HTTP file\n");
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+
+/* linaro_aepd_protocol */
+
+struct per_session_data__linaro_aepd {
+ struct libwebsocket *wsi;
+ unsigned long ringbuffer_tail;
+ double sam[MAX_PROBES * CHANNELS_PER_PROBE * 3];
+ int sam_valid;
+ int stride;
+};
+
+
+static int
+callback_linaro_aepd(struct libwebsocket_context *context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ int n, m;
+ struct per_session_data__linaro_aepd *pss = user;
+ double sam[MAX_PROBES * CHANNELS_PER_PROBE * 3];
+ double d[10];
+ 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;
+
+ switch (reason) {
+
+ case LWS_CALLBACK_ESTABLISHED:
+ pss->ringbuffer_tail = aepd_shared->fifo_pos;
+ pss->sam_valid = 0;
+ pss->wsi = wsi;
+ pss->stride = 100;
+ break;
+
+ case LWS_CALLBACK_SERVER_WRITEABLE:
+
+ /*
+ * aggregate up to 'budget' results in one websocket message
+ */
+
+ while (budget--) {
+
+ if (pss->ringbuffer_tail <= 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)) {
+ 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");
+
+ pss->ringbuffer_tail += (pss->stride * aepd_shared->chans * sizeof(double) * 3 );
+ if (pss->ringbuffer_tail > aepd_shared->modulo_integer_chan_size)
+ pss->ringbuffer_tail -= aepd_shared->modulo_integer_chan_size;
+
+ if (pss->sam_valid) {
+
+ /*
+ * Javascript can't cope with binary, so we must ascii-fy it
+ */
+
+ m = 0;
+ for (n = 0; n < aepd_shared->chans; n++) {
+ p += sprintf(p, "%f %f %f",
+ (sam[m] - pss->sam[m]) / (double)pss->stride,
+ (sam[m + 1] - pss->sam[m + 1]) / (double)pss->stride,
+ (sam[m + 2] - pss->sam[m + 2]) / (double)pss->stride
+ );
+
+ if (n + 1 != aepd_shared->chans) {
+ *p++ = ',';
+ *p = '\0';
+ }
+ m += 3;
+ }
+
+ *p++ = ';';
+ *p = '\0';
+ }
+
+ memcpy(&pss->sam[0], &sam[0], aepd_shared->chans * sizeof(double) * 3);
+ pss->sam_valid = 1;
+ }
+
+ /*
+ * if we generated something, send it. We are guaranteed not to block
+ * because we got here by POLLOUT seen on the socket
+ */
+
+ if (p != &buf[LWS_SEND_BUFFER_PRE_PADDING]) {
+ n = libwebsocket_write(wsi, (unsigned char *)
+ &buf[LWS_SEND_BUFFER_PRE_PADDING],
+ p - &buf[LWS_SEND_BUFFER_PRE_PADDING], LWS_WRITE_TEXT);
+ if (n < 0) {
+ fprintf(stderr, "ERROR writing to socket");
+ return 1;
+ }
+ libwebsocket_callback_on_writable(context, wsi);
+ }
+
+ break;
+
+ case LWS_CALLBACK_RECEIVE:
+
+ switch (*(char *)in) {
+ case 'r':
+ if (sscanf(((char *)in) + 1, "%lf\n", &d[0]) == 1)
+ pss->stride = (int)d[0];
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* list of supported protocols and callbacks */
+
+struct libwebsocket_protocols protocols[] = {
+ /* first protocol must always be HTTP handler */
+
+ {
+ "http-only", /* name */
+ callback_http, /* callback */
+ 0 /* per_session_data_size */
+ },
+ {
+ "linaro.aepd",
+ callback_linaro_aepd,
+ sizeof(struct per_session_data__linaro_aepd),
+ },
+ {
+ NULL, NULL, 0 /* End of list */
+ }
+};
+
diff --git a/configure.ac b/configure.ac
index 03a6e94..65140bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,7 +34,8 @@ AC_CHECK_FUNCS([poll memset ])
AC_CONFIG_FILES([Makefile
libarmep/Makefile
- arm-probe/Makefile])
+ arm-probe/Makefile
+ aepd/Makefile])
AC_OUTPUT
diff --git a/libarmep/sample.c b/libarmep/sample.c
index d3f5a25..f108438 100644
--- a/libarmep/sample.c
+++ b/libarmep/sample.c
@@ -336,7 +336,7 @@ unripe:
}
}
- if (aep_shared->head == (sizeof(aep_shared->aep_result) / sizeof(*aep_result)) - 1)
+ if (aep_shared->head == (sizeof(aep_shared->aep_result) / sizeof(aep_shared->aep_result[0])) - 1)
aep_shared->head = 0;
else
aep_shared->head++;
diff --git a/libarmep/service.c b/libarmep/service.c
index c8d0208..2f85cff 100644
--- a/libarmep/service.c
+++ b/libarmep/service.c
@@ -563,8 +563,6 @@ int aep_init_and_fork(struct aep_context *aep_context, char *argv[])
loop = 1;
- signal(SIGINT, sighandler);
-
init_interpolation();
/*
@@ -583,6 +581,10 @@ int aep_init_and_fork(struct aep_context *aep_context, char *argv[])
sprintf(semname, "linaro.aep.%u\n", getpid());
aep_context->semaphore = sem_open(semname, O_CREAT | O_RDWR, 0600, 0);
+ if (aep_context->semaphore == SEM_FAILED) {
+ fprintf(stderr, "Failed to open sem %s\n", semname);
+ return -1;
+ }
/* fork off aep service loop */
@@ -590,6 +592,8 @@ int aep_init_and_fork(struct aep_context *aep_context, char *argv[])
if (n)
return n;
+ signal(SIGINT, sighandler);
+
/*
* child process runs independently
* fills the named pipe fifo with sample packets
@@ -598,12 +602,16 @@ int aep_init_and_fork(struct aep_context *aep_context, char *argv[])
if (argv)
strcpy(argv[0] + strlen(argv[0]), " - AEP server");
- aep_context->semaphore = sem_open(semname, O_CREAT | O_RDWR, 0600, 0);
+ aep_context->semaphore = sem_open(semname, O_RDWR, 0600, 0);
+ if (aep_context->semaphore == SEM_FAILED) {
+ fprintf(stderr, "Child failed to open sem %s\n", semname);
+ return -1;
+ }
aep_context->aep_shared->finished = 0;
aep_context->poll_timeout_ms = 10;
- while (!aep_context->aep_shared->finished) {
+ while (!aep_context->aep_shared->finished && loop && getppid() != 1) {
n = poll(aep_context->pollfds, aep_context->count_pollfds, aep_context->poll_timeout_ms);
if (n < 0)
@@ -674,6 +682,8 @@ struct aep_result * aep_wait_for_next_result(struct aep_context *aep_context)
if (aep_shared->tail == aep_shared->head)
return NULL;
+// fprintf(stderr, "%d %d, ", aep_shared->tail, aep_shared->head);
+
return &aep_shared->aep_result[aep_shared->tail];
}