aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2012-10-12 09:03:59 +0800
committerAndy Green <andy.green@linaro.org>2012-10-12 09:18:17 +0800
commit0ed496e702cb52ba5eee23864ba4643c4407824d (patch)
tree5458b7c2ed60dbc2c16b0cdc693309f42897f082
parent020f93df6d6354a18e05a65707967ce53bba26e5 (diff)
refactor sample.c into protocol.c and service.c
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r--libarmep/Makefile.am2
-rw-r--r--libarmep/libarmep.h23
-rw-r--r--libarmep/protocol.c430
-rw-r--r--libarmep/sample.c1113
-rw-r--r--libarmep/service.c674
5 files changed, 1148 insertions, 1094 deletions
diff --git a/libarmep/Makefile.am b/libarmep/Makefile.am
index 4a9a68b..c71834d 100644
--- a/libarmep/Makefile.am
+++ b/libarmep/Makefile.am
@@ -4,6 +4,8 @@ dist_libarmep_la_SOURCES=sample.c \
interpolation.c \
configuration.c \
avg-mean-us.c \
+ protocol.c \
+ service.c \
libarmep.h
libarmep_la_CFLAGS=-Wall -Werror -std=gnu99 -pedantic -pthread
diff --git a/libarmep/libarmep.h b/libarmep/libarmep.h
index 4533c64..5bd3f8a 100644
--- a/libarmep/libarmep.h
+++ b/libarmep/libarmep.h
@@ -307,25 +307,30 @@ struct interp {
double raw;
};
+/*
+ * internal
+ */
+
+extern int aep_protocol_parser(struct aep *aep, int samples);
+extern int process_sample(struct aep *aep, int ch_index);
extern int avg_mean_us_init(struct avg_mean_us *amu, int width);
extern void avg_mean_us_add(struct avg_mean_us *amu, unsigned short s);
extern double avg_mean_us(struct avg_mean_us *amu);
extern void avg_mean_us_free(struct avg_mean_us *amu);
extern void avg_mean_us_flush(struct avg_mean_us *amu);
-
extern struct interp_tables interp_tables[3];
extern double correct(int no_correction, double common_mode, double in, struct interp_tables *itable);
-
-extern int get_stdin_line(char *buf, int maxlen);
-extern int process_sample(struct aep *aep, int ch_index);
-
extern int configure(struct aep_context *aep_context, struct aep *aep, const char *dev_filepath,
const char *config_filepath, struct aep_channel *wch);
-extern char configuration_name[64];
-extern int service_aeps(struct aep_context *aep_context, int fd);
extern void probe_close(struct aep *aep);
extern void init_interpolation(void);
+
+/*
+ * external apis
+ */
+
+extern int service_aeps(struct aep_context *aep_context, int fd);
extern int aep_init_and_fork(struct aep_context *aep_context);
-struct aep_result * aep_wait_for_next_result(struct aep_context *aep_context);
-void aep_free_result(struct aep_context *aep_context);
+extern struct aep_result * aep_wait_for_next_result(struct aep_context *aep_context);
+extern void aep_free_result(struct aep_context *aep_context);
diff --git a/libarmep/protocol.c b/libarmep/protocol.c
new file mode 100644
index 0000000..ad05c64
--- /dev/null
+++ b/libarmep/protocol.c
@@ -0,0 +1,430 @@
+/*
+ * Author: Andy Green <andy.green@linaro.org>
+ * Copyright (C) 2012 Linaro, LTD
+ *
+ * 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 "libarmep.h"
+
+int aep_protocol_parser(struct aep *aep, int samples)
+{
+ unsigned char v;
+ static unsigned char cmd[] = {
+ AEPC_CONFIG, 0, 6,
+ };
+ int bad = 0;
+
+ while (aep->head != aep->tail && samples--) {
+
+ v = aep->ring[aep->head++];
+ if (aep->head == sizeof(aep->ring))
+ aep->head = 0;
+
+ if (aep->aep_context->verbose)
+ fprintf(stderr, "%02X ", v);
+
+ switch (aep->state) {
+
+ /*
+ * this filters the input to sync, it will keep returning to
+ * look for the first byte if any of AC FF FF FF FF FF FF FF FF
+ * is not correctly seen.
+ */
+
+ case APP_INIT_MAGIC:
+ switch (aep->counter++) {
+ case 0:
+ if (v != 0xac)
+ aep->counter = 0;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ if (v != 0xff)
+ aep->counter = 0;
+ break;
+ case 63:
+ if (aep->aep_context->verbose)
+ fprintf(stderr,
+ "magic ok, asking for version\n");
+ v = AEPC_VERSION;
+ if (write(aep->fd, &v, 1) != 1)
+ return -1;
+ aep->state++;
+ aep->counter = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case APP_INIT_VERSION:
+ switch (aep->counter++) {
+ case 0:
+ if (v != 0xac)
+ return -1;
+ break;
+ case 1:
+ aep->version = v;
+ break;
+ case 2:
+ aep->version |= v << 8;
+ break;
+ case 3:
+ aep->version |= v << 16;
+ break;
+ case 4:
+ aep->version |= v << 24;
+ break;
+ case 63:
+ if (aep->aep_context->verbose)
+ fprintf(stderr,
+ "version ok, asking for vendor\n");
+ v = AEPC_VENDOR;
+ if (write(aep->fd, &v, 1) != 1)
+ return -1;
+ aep->state++;
+ aep->counter = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case APP_INIT_VENDOR:
+ switch (aep->counter++) {
+ case 0:
+ if (v != 0xac)
+ return -1;
+ break;
+ case 63:
+ if (aep->aep_context->verbose)
+ fprintf(stderr,
+ "vendor ok, asking for rate\n");
+ v = AEPC_RATE;
+ if (write(aep->fd, &v, 1) != 1)
+ return -1;
+ aep->state++;
+ aep->counter = 0;
+ aep->name[63] = '\0';
+ break;
+ default:
+ aep->name[aep->counter - 2] = v;
+ break;
+ }
+ break;
+
+
+ case APP_INIT_RATE:
+ switch (aep->counter++) {
+ case 0:
+ if (v != 0xac)
+ return -1;
+ break;
+ case 1:
+ aep->rate = v;
+ break;
+ case 2:
+ aep->rate |= v << 8;
+ break;
+ case 63:
+ if (aep->aep_context->verbose)
+ fprintf(stderr,
+ "rate ok, doing config\n");
+ aep->state++;
+ aep->counter = 0;
+ cmd[1] = 0;
+ if (write(aep->fd, &cmd[0], sizeof cmd) !=
+ sizeof cmd)
+ return -1;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case APP_INIT_CONFIG_1:
+
+ switch (aep->counter++) {
+ case 0:
+ if (v != 0xac)
+ return -1;
+ break;
+ case 63:
+ if (aep->aep_context->verbose)
+ fprintf(stderr,
+ "rate ok, doing config\n");
+ aep->state++;
+ aep->counter = 0;
+ cmd[1] = 1;
+ if (write(aep->fd, &cmd[0], sizeof cmd) !=
+ sizeof cmd)
+ return -1;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case APP_INIT_CONFIG_2:
+
+ switch (aep->counter++) {
+ case 0:
+ if (v != 0xac)
+ return -1;
+ break;
+ case 63:
+ if (aep->aep_context->verbose)
+ fprintf(stderr,
+ "rate ok, doing config\n");
+ aep->state++;
+ aep->counter = 0;
+ cmd[1] = 2;
+ if (write(aep->fd, &cmd[0], sizeof cmd) !=
+ sizeof cmd)
+ return -1;
+ break;
+ default:
+ break;
+ }
+ break;
+
+
+
+ case APP_INIT_CONFIG_3:
+
+ switch (aep->counter++) {
+ case 0:
+ if (v != 0xac)
+ return -1;
+ break;
+ case 63:
+ if (aep->aep_context->verbose)
+ fprintf(stderr,
+ "Configured new probe instance "
+ "%s %s %08X %d\n",
+ aep->dev_filepath, aep->name,
+ aep->version, aep->rate);
+
+ aep->done_config |= 2;
+ aep->state = APP_INIT_START_ACK;
+ aep->counter = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case APP_INIT_START_ACK:
+ if (v != 0xac)
+ return -1;
+
+ if (aep->aep_context->verbose)
+ fprintf(stderr,
+ "Start acknowledge seen "
+ "%s %s %08X %d\n",
+ aep->dev_filepath, aep->name,
+ aep->version, aep->rate);
+
+ aep->done_config |= 4;
+ aep->state = APP_FRAME_L;
+ aep->counter = 0;
+ break;
+
+ case APP_FRAME_L:
+ if (v == (aep->predicted_frame & 0xff)) {
+ aep->state = APP_FRAME_H;
+ break;
+ }
+ fprintf(stderr, "%d:.L(%d %d)", aep->index, v, aep->predicted_frame & 0xff);
+ /* lost sync... */
+ if (aep->invalid < AEP_INVALID_COVER)
+ aep->invalid = AEP_INVALID_COVER;
+ aep->state = APP_FRAME_H_BAD;
+ break;
+
+ case APP_FRAME_H:
+
+ if (v == aep->predicted_frame >> 8) {
+ aep->state = APP_VOLTAGE_L1;
+ aep->predicted_frame++;
+ if (aep->invalid) {
+ aep->invalid--;
+ if (aep->invalid == 0)
+ fprintf(stderr, "%d:donetime\n", aep->index);
+ else
+ fprintf(stderr, "-%d:%d-", aep->index, aep->invalid);
+ }
+ break;
+ }
+
+ fprintf(stderr, "%d:.H(%d %d)", aep->index, v, aep->predicted_frame >> 8);
+
+ /* fallthru */
+
+ case APP_FRAME_H_BAD:
+ /* lost sync - slip one byte and use that as frame prediction for next time */
+ aep->predicted_frame = v;
+ if (aep->invalid < AEP_INVALID_COVER)
+ aep->invalid = AEP_INVALID_COVER;
+ aep->state = APP_VOLTAGE_L1_BAD;
+ break;
+
+ case APP_VOLTAGE_L1_BAD:
+ aep->predicted_frame |= v << 8;
+ aep->predicted_frame++;
+ aep->state = APP_VOLTAGE_H1_BAD;
+ break;
+
+ case APP_VOLTAGE_H1_BAD:
+ case APP_CURRENT_L1_BAD:
+ case APP_CURRENT_H1_BAD:
+ case APP_VOLTAGE_L2_BAD:
+ case APP_VOLTAGE_H2_BAD:
+ case APP_CURRENT_L2_BAD:
+ case APP_CURRENT_H2_BAD:
+ case APP_VOLTAGE_L3_BAD:
+ case APP_VOLTAGE_H3_BAD:
+ case APP_CURRENT_L3_BAD:
+ case APP_CURRENT_H3_BAD:
+ aep->state++;
+ break;
+
+ case APP_SWALLOW:
+
+ //if (aep->aep_context->verbose)
+ fprintf(stderr, "%s: LOST SYNC *\n",
+ aep->dev_filepath);
+ bad++;
+ if (bad > 16) {
+ fprintf(stderr, "%s: too much lost sync\n",
+ aep->dev_filepath);
+ return -1;
+ }
+
+ aep->state = APP_FRAME_L;
+ break;
+
+ /* good path */
+
+ case APP_VOLTAGE_L1:
+ aep->voltage = v;
+ aep->state++;
+ break;
+
+ case APP_VOLTAGE_H1:
+ aep->voltage |= v << 8;
+ aep->state++;
+ break;
+
+ case APP_CURRENT_L1:
+ aep->current = v;
+ aep->state++;
+ break;
+
+ case APP_CURRENT_H1:
+ aep->current |= v << 8;
+ aep->state++;
+
+ if (aep->invalid)
+ break;
+
+ if (aep->current > ADC_COUNT_CURRENT_CLIP_LIMIT)
+ fprintf(stderr, "\n*** %d.0: %s Shunt diff voltage %fV above"
+ " %fV limit: clipping *** \n",
+ aep->index, aep->ch[0].channel_name,
+ (double)aep->current / ADC_COUNTS_PER_VOLT_CH2,
+ (double)ADC_COUNT_CURRENT_CLIP_LIMIT /
+ ADC_COUNTS_PER_VOLT_CH2);
+
+ return process_sample(aep, 0);
+ case APP_VOLTAGE_L2:
+ aep->voltage = v;
+ aep->state++;
+ break;
+
+ case APP_VOLTAGE_H2:
+ aep->voltage |= v << 8;
+ aep->state++;
+ break;
+
+ case APP_CURRENT_L2:
+ aep->current = v;
+ aep->state++;
+ break;
+
+ case APP_CURRENT_H2:
+ aep->current |= v << 8;
+ aep->state++;
+
+ if (aep->invalid)
+ break;
+
+ if (aep->current > ADC_COUNT_CURRENT_CLIP_LIMIT)
+ fprintf(stderr, "\n*** %d.1: %s Shunt diff voltage %fV above"
+ " %fV limit: clipping *** \n",
+ aep->index, aep->ch[1].channel_name,
+ (double)aep->current / ADC_COUNTS_PER_VOLT_CH2,
+ (double)ADC_COUNT_CURRENT_CLIP_LIMIT /
+ ADC_COUNTS_PER_VOLT_CH2);
+
+ return process_sample(aep, 1);
+
+ case APP_VOLTAGE_L3:
+ aep->voltage = v;
+ aep->state++;
+ break;
+
+ case APP_VOLTAGE_H3:
+ aep->voltage |= v << 8;
+ aep->state++;
+ break;
+
+ case APP_CURRENT_L3:
+ aep->current = v;
+ aep->state++;
+ break;
+
+ case APP_CURRENT_H3:
+ aep->current |= v << 8;
+ aep->state = APP_FRAME_L;
+
+ if (aep->invalid) {
+ fprintf(stderr, "#%d ", aep->index);
+ break;
+ }
+
+ if (aep->current > ADC_COUNT_CURRENT_CLIP_LIMIT)
+ fprintf(stderr, "\n*** %d.2: %s Shunt diff voltage %fV above"
+ " %fV limit: clipping *** \n",
+ aep->index, aep->ch[2].channel_name,
+ (double)aep->current / ADC_COUNTS_PER_VOLT_CH2,
+ (double)ADC_COUNT_CURRENT_CLIP_LIMIT /
+ ADC_COUNTS_PER_VOLT_CH2);
+
+ return process_sample(aep, 2);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/libarmep/sample.c b/libarmep/sample.c
index 94c7b02..d3f5a25 100644
--- a/libarmep/sample.c
+++ b/libarmep/sample.c
@@ -1,33 +1,28 @@
-#include "libarmep.h"
+/*
+ * Author: Andy Green <andy.green@linaro.org>
+ * Copyright (C) 2012 Linaro, LTD
+ *
+ * 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 <linux/serial.h>
-#include <sys/mman.h>
+#include "libarmep.h"
int somebody_triggered = -1;
struct aep_channel *who_triggered = NULL;
-
-void add_pollfd(struct aep_context *aep_context, int fd, int events)
-{
- aep_context->pollfds[aep_context->count_pollfds].fd = fd;
- aep_context->pollfds[aep_context->count_pollfds].events = events;
- aep_context->pollfds[aep_context->count_pollfds++].revents = 0;
-}
-
-void remove_pollfd(struct aep_context *aep_context, int fd)
-{
- int n;
-
- for (n = 0; n < aep_context->count_pollfds; n++)
- if (aep_context->pollfds[n].fd == fd) {
- while (n < aep_context->count_pollfds) {
- aep_context->pollfds[n] = aep_context->pollfds[n + 1];
- n++;
- }
- aep_context->count_pollfds--;
- }
-}
-
static void track_limits_convert_to_current(struct aep_channel *ch,
double *v1, double *v2)
{
@@ -97,7 +92,6 @@ int process_sample(struct aep *aep, int ch_index)
int m, i, from_pretrig = 0, n, hit;
struct aep_shared *aep_shared;
struct aep_result *aep_result;
-// int sem = 0;
if (!aep->aep_context->no_correction) {
vo0 = ch->voffset[0];
@@ -176,9 +170,9 @@ unripe:
ch->trigger_filter++;
if (ch->trigger_filter > aep->aep_context->trigger_filter_us / 100 || somebody_triggered != -1) {
- if (somebody_triggered != -1) {
+ if (somebody_triggered != -1)
ch->trigger_slave = who_triggered;
- } else {
+ else {
who_triggered = ch;
somebody_triggered = ch->samples_seen;
}
@@ -279,7 +273,8 @@ unripe:
goto done;
}
- /* not everyone else may be ready, save them up */
+ /* not everyone else may be ready, save the data first in per-channel sync ring buffers */
+
if (v1 < 0)
v1 = 0;
if (v2 < 0)
@@ -341,18 +336,13 @@ 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_result)) - 1)
aep_shared->head = 0;
- } else {
+ else
aep_shared->head++;
- }
-
-// sem = 0;
-// sem_getvalue(aep->aep_context->semaphore, &sem);
-// if (sem < 1)
- if (sem_post(aep->aep_context->semaphore) < 0)
- fprintf(stderr, "failed to set semaphore\n");
+ if (sem_post(aep->aep_context->semaphore) < 0)
+ fprintf(stderr, "failed to set semaphore\n");
done:
@@ -370,1052 +360,5 @@ done:
return 0;
}
-static int service_aep_buffers(struct aep *aep, int samples)
-{
- unsigned char v;
- static unsigned char cmd[] = {
- AEPC_CONFIG, 0, 6,
- };
- int bad = 0;
-
- while (aep->head != aep->tail && samples--) {
-
- v = aep->ring[aep->head++];
- if (aep->head == sizeof(aep->ring))
- aep->head = 0;
-
- if (aep->aep_context->verbose)
- fprintf(stderr, "%02X ", v);
-
- switch (aep->state) {
-
- /*
- * this filters the input to sync, it will keep returning to
- * look for the first byte if any of AC FF FF FF FF FF FF FF FF
- * is not correctly seen.
- */
-
- case APP_INIT_MAGIC:
- switch (aep->counter++) {
- case 0:
- if (v != 0xac)
- aep->counter = 0;
- break;
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- if (v != 0xff)
- aep->counter = 0;
- break;
- case 63:
- if (aep->aep_context->verbose)
- fprintf(stderr,
- "magic ok, asking for version\n");
- v = AEPC_VERSION;
- if (write(aep->fd, &v, 1) != 1)
- return -1;
- aep->state++;
- aep->counter = 0;
- break;
- default:
- break;
- }
- break;
-
- case APP_INIT_VERSION:
- switch (aep->counter++) {
- case 0:
- if (v != 0xac)
- return -1;
- break;
- case 1:
- aep->version = v;
- break;
- case 2:
- aep->version |= v << 8;
- break;
- case 3:
- aep->version |= v << 16;
- break;
- case 4:
- aep->version |= v << 24;
- break;
- case 63:
- if (aep->aep_context->verbose)
- fprintf(stderr,
- "version ok, asking for vendor\n");
- v = AEPC_VENDOR;
- if (write(aep->fd, &v, 1) != 1)
- return -1;
- aep->state++;
- aep->counter = 0;
- break;
- default:
- break;
- }
- break;
-
- case APP_INIT_VENDOR:
- switch (aep->counter++) {
- case 0:
- if (v != 0xac)
- return -1;
- break;
- case 63:
- if (aep->aep_context->verbose)
- fprintf(stderr,
- "vendor ok, asking for rate\n");
- v = AEPC_RATE;
- if (write(aep->fd, &v, 1) != 1)
- return -1;
- aep->state++;
- aep->counter = 0;
- aep->name[63] = '\0';
- break;
- default:
- aep->name[aep->counter - 2] = v;
- break;
- }
- break;
-
-
- case APP_INIT_RATE:
- switch (aep->counter++) {
- case 0:
- if (v != 0xac)
- return -1;
- break;
- case 1:
- aep->rate = v;
- break;
- case 2:
- aep->rate |= v << 8;
- break;
- case 63:
- if (aep->aep_context->verbose)
- fprintf(stderr,
- "rate ok, doing config\n");
- aep->state++;
- aep->counter = 0;
- cmd[1] = 0;
- if (write(aep->fd, &cmd[0], sizeof cmd) !=
- sizeof cmd)
- return -1;
- break;
- default:
- break;
- }
- break;
-
- case APP_INIT_CONFIG_1:
-
- switch (aep->counter++) {
- case 0:
- if (v != 0xac)
- return -1;
- break;
- case 63:
- if (aep->aep_context->verbose)
- fprintf(stderr,
- "rate ok, doing config\n");
- aep->state++;
- aep->counter = 0;
- cmd[1] = 1;
- if (write(aep->fd, &cmd[0], sizeof cmd) !=
- sizeof cmd)
- return -1;
- break;
- default:
- break;
- }
- break;
-
- case APP_INIT_CONFIG_2:
-
- switch (aep->counter++) {
- case 0:
- if (v != 0xac)
- return -1;
- break;
- case 63:
- if (aep->aep_context->verbose)
- fprintf(stderr,
- "rate ok, doing config\n");
- aep->state++;
- aep->counter = 0;
- cmd[1] = 2;
- if (write(aep->fd, &cmd[0], sizeof cmd) !=
- sizeof cmd)
- return -1;
- break;
- default:
- break;
- }
- break;
-
-
-
- case APP_INIT_CONFIG_3:
-
- switch (aep->counter++) {
- case 0:
- if (v != 0xac)
- return -1;
- break;
- case 63:
- if (aep->aep_context->verbose)
- fprintf(stderr,
- "Configured new probe instance "
- "%s %s %08X %d\n",
- aep->dev_filepath, aep->name,
- aep->version, aep->rate);
-
- aep->done_config |= 2;
- aep->state = APP_INIT_START_ACK;
- aep->counter = 0;
- break;
- default:
- break;
- }
- break;
-
- case APP_INIT_START_ACK:
- if (v != 0xac)
- return -1;
-
- if (aep->aep_context->verbose)
- fprintf(stderr,
- "Start acknowledge seen "
- "%s %s %08X %d\n",
- aep->dev_filepath, aep->name,
- aep->version, aep->rate);
-
- aep->done_config |= 4;
- aep->state = APP_FRAME_L;
- aep->counter = 0;
- break;
-
- case APP_FRAME_L:
- if (v == (aep->predicted_frame & 0xff)) {
- aep->state = APP_FRAME_H;
- break;
- }
- fprintf(stderr, "%d:.L(%d %d)", aep->index, v, aep->predicted_frame & 0xff);
- /* lost sync... */
- if (aep->invalid < AEP_INVALID_COVER)
- aep->invalid = AEP_INVALID_COVER;
- aep->state = APP_FRAME_H_BAD;
- break;
-
- case APP_FRAME_H:
-
- if (v == aep->predicted_frame >> 8) {
- aep->state = APP_VOLTAGE_L1;
- aep->predicted_frame++;
- if (aep->invalid) {
- aep->invalid--;
- if (aep->invalid == 0)
- fprintf(stderr, "%d:donetime\n", aep->index);
- else
- fprintf(stderr, "-%d:%d-", aep->index, aep->invalid);
- }
- break;
- }
-
- fprintf(stderr, "%d:.H(%d %d)", aep->index, v, aep->predicted_frame >> 8);
-
- /* fallthru */
-
- case APP_FRAME_H_BAD:
- /* lost sync - slip one byte and use that as frame prediction for next time */
- aep->predicted_frame = v;
- if (aep->invalid < AEP_INVALID_COVER)
- aep->invalid = AEP_INVALID_COVER;
- aep->state = APP_VOLTAGE_L1_BAD;
- break;
-
- case APP_VOLTAGE_L1_BAD:
- aep->predicted_frame |= v << 8;
- aep->predicted_frame++;
- aep->state = APP_VOLTAGE_H1_BAD;
- break;
-
- case APP_VOLTAGE_H1_BAD:
- case APP_CURRENT_L1_BAD:
- case APP_CURRENT_H1_BAD:
- case APP_VOLTAGE_L2_BAD:
- case APP_VOLTAGE_H2_BAD:
- case APP_CURRENT_L2_BAD:
- case APP_CURRENT_H2_BAD:
- case APP_VOLTAGE_L3_BAD:
- case APP_VOLTAGE_H3_BAD:
- case APP_CURRENT_L3_BAD:
- case APP_CURRENT_H3_BAD:
- aep->state++;
- break;
-
- case APP_SWALLOW:
-
- //if (aep->aep_context->verbose)
- fprintf(stderr, "%s: LOST SYNC *\n",
- aep->dev_filepath);
- bad++;
- if (bad > 16) {
- fprintf(stderr, "%s: too much lost sync\n",
- aep->dev_filepath);
- return -1;
- }
-
- aep->state = APP_FRAME_L;
- break;
-
- /* good path */
-
- case APP_VOLTAGE_L1:
- aep->voltage = v;
- aep->state++;
- break;
-
- case APP_VOLTAGE_H1:
- aep->voltage |= v << 8;
- aep->state++;
- break;
-
- case APP_CURRENT_L1:
- aep->current = v;
- aep->state++;
- break;
-
- case APP_CURRENT_H1:
- aep->current |= v << 8;
- aep->state++;
-
- if (aep->invalid)
- break;
-
- if (aep->current > ADC_COUNT_CURRENT_CLIP_LIMIT)
- fprintf(stderr, "\n*** %d.0: %s Shunt diff voltage %fV above"
- " %fV limit: clipping *** \n",
- aep->index, aep->ch[0].channel_name,
- (double)aep->current / ADC_COUNTS_PER_VOLT_CH2,
- (double)ADC_COUNT_CURRENT_CLIP_LIMIT /
- ADC_COUNTS_PER_VOLT_CH2);
-
- return process_sample(aep, 0);
- case APP_VOLTAGE_L2:
- aep->voltage = v;
- aep->state++;
- break;
-
- case APP_VOLTAGE_H2:
- aep->voltage |= v << 8;
- aep->state++;
- break;
-
- case APP_CURRENT_L2:
- aep->current = v;
- aep->state++;
- break;
-
- case APP_CURRENT_H2:
- aep->current |= v << 8;
- aep->state++;
-
- if (aep->invalid)
- break;
-
- if (aep->current > ADC_COUNT_CURRENT_CLIP_LIMIT)
- fprintf(stderr, "\n*** %d.1: %s Shunt diff voltage %fV above"
- " %fV limit: clipping *** \n",
- aep->index, aep->ch[1].channel_name,
- (double)aep->current / ADC_COUNTS_PER_VOLT_CH2,
- (double)ADC_COUNT_CURRENT_CLIP_LIMIT /
- ADC_COUNTS_PER_VOLT_CH2);
-
- return process_sample(aep, 1);
-
- case APP_VOLTAGE_L3:
- aep->voltage = v;
- aep->state++;
- break;
-
- case APP_VOLTAGE_H3:
- aep->voltage |= v << 8;
- aep->state++;
- break;
-
- case APP_CURRENT_L3:
- aep->current = v;
- aep->state++;
- break;
-
- case APP_CURRENT_H3:
- aep->current |= v << 8;
- aep->state = APP_FRAME_L;
-
- if (aep->invalid) {
- fprintf(stderr, "#%d ", aep->index);
- break;
- } //else
- //fprintf(stderr, "*%d ", aep->index);
-
- if (aep->current > ADC_COUNT_CURRENT_CLIP_LIMIT)
- fprintf(stderr, "\n*** %d.2: %s Shunt diff voltage %fV above"
- " %fV limit: clipping *** \n",
- aep->index, aep->ch[2].channel_name,
- (double)aep->current / ADC_COUNTS_PER_VOLT_CH2,
- (double)ADC_COUNT_CURRENT_CLIP_LIMIT /
- ADC_COUNTS_PER_VOLT_CH2);
-
- return process_sample(aep, 2);
-
- }
- }
-
- return 0;
-}
-
-static void init_aep(struct aep_context *aep_context, struct aep *aep, const char *device_filepath)
-{
- int n, m;
- struct aep_channel *ch;
-
- // fprintf(stderr, "***** init_aep *****\n");
-
- aep->head = 0;
- aep->tail = 0;
- aep->predicted_frame = 0;
- aep->state = APP_INIT_MAGIC;
- aep->invalid = 0;
- aep->counter = 0;
- aep->started = 0;
- aep->done_config = 0;
-
- aep->aep_context = aep_context;
-
- strncpy(aep->dev_filepath, device_filepath,
- sizeof aep->dev_filepath - 1);
- aep->dev_filepath[sizeof aep->dev_filepath - 1] = '\0';
-
- for (n = 0; n < CHANNELS_PER_PROBE; n++) {
- ch = &aep->ch[n];
-
- ch->ignore = 0;
- ch->triggered = 0;
- ch->requested = 0;
- ch->summary[0] = '\0';
- ch->aep = aep;
- ch->trigger_slave = NULL;
- ch->out_head = ch->out_tail = 0;
- ch->voffset[0] = 0;
- ch->vnoise[0] = 0;
- ch->voffset[1] = 0;
- ch->vnoise[1] = 0;
- ch->rshunt = 0;
- sprintf(ch->channel_name, "%s-%d", device_filepath, n);
- ch->pretrig_ring = NULL;
- ch->ring_samples = 0;
- ch->trigger_filter = 0;
- ch->pretrigger_samples_taken = 0;
- avg_mean_us_init(&ch->avg_mean_voltage, aep->aep_context->average_len);
- avg_mean_us_init(&ch->avg_mean_current, aep->aep_context->average_len);
- ch->decimation_counter = 0;
- for (m = 0; m < sizeof(ch->min) / sizeof(ch->min[0]); m++) {
- ch->min[m] = 999;
- ch->max[m] = 0;
- }
- ch->samples_seen = 0;
- ch->simple_avg[0] = 0.0;
- ch->simple_avg[1] = 0.0;
- ch->simple_avg[2] = 0.0;
- ch->avg_count = 0;
- ch->samples = 0;
- strcpy(ch->supply, "none");
- sprintf(ch->colour, "#%06X", rand() & 0xffffff);
- }
-}
-
-
-static void select_map(struct aep_channel *ch)
-{
- int m;
- int sel = -1;
- double delta = 999999;
-
- for (m = 0; m < (sizeof interp_tables / sizeof interp_tables[0]); m++) {
- if (ch->percentage_error_ref <= interp_tables[m].percentage_error_ref) {
- if (delta > (interp_tables[m].percentage_error_ref - ch->percentage_error_ref)) {
- delta = interp_tables[m].percentage_error_ref - ch->percentage_error_ref;
- sel = m;
- }
- } else {
- if (delta > (ch->percentage_error_ref - interp_tables[m].percentage_error_ref)) {
- delta = ch->percentage_error_ref - interp_tables[m].percentage_error_ref;
- sel = m;
- }
- }
- }
- if (ch->aep->aep_context->verbose)
- fprintf(stderr, "%s = corr map %d %f%%\n",
- ch->channel_name, sel, ch->percentage_error_ref);
- ch->map_table = &interp_tables[sel];
-}
-
-void probe_close(struct aep *aep)
-{
- unsigned char c = AEPC_STOP;
- int n;
-
- write(aep->fd, &c, 1);
-
- for (n = 0; n < CHANNELS_PER_PROBE; n++) {
- if (aep->ch[n].pretrig_ring)
- free(aep->ch[n].pretrig_ring);
-
- avg_mean_us_free(&aep->ch[n].avg_mean_voltage);
- avg_mean_us_free(&aep->ch[n].avg_mean_current);
- }
-
- if (aep->aep_context->verbose)
- fprintf(stderr, "closing %d\n", aep->fd);
- close(aep->fd);
-}
-
-int service_aeps(struct aep_context *aep_context, int fd_with_rx)
-{
- static unsigned char zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
- int fd;
- int budget;
- int len;
- struct timeval tv;
- unsigned char *p;
- unsigned char c;
- char filepath[20];
- struct termios tty;
- struct serial_struct sinfo;
- int n, m, i, chan;
- struct aep *aep;
- struct aep_channel *ch;
- unsigned char buf[AEP_INPUT_QUEUE];
-
- if (fd_with_rx >= 0)
- goto post_start;
-
- gettimeofday(&tv, NULL);
-
- /* look for any new devices appearing */
-
- if (aep_context->aeps[aep_context->scan].fd > 0)
- goto bail;
-
- sprintf(filepath, "/dev/ttyACM%d", aep_context->scan);
- fd = open(filepath, O_RDWR | O_NONBLOCK | O_EXCL | O_NOCTTY);
-
- if (fd < 0)
- goto bail;
-
- if (ioctl(fd, TIOCEXCL) < 0) {
- fprintf(stderr, "Wasn't able to open %s exclusive",
- filepath);
- close(fd);
- goto bail;
- }
-
-
- fprintf(stderr, "+");
-
- tcflush(fd, TCIOFLUSH);
-
- if (ioctl(fd, TIOCGSERIAL, &sinfo) == 0) {
- sinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE;
- ioctl(fd, TIOCSSERIAL, &sinfo);
- }
-
- if (aep_context->verbose)
- fprintf(stderr, "initing %s fd=%d\n", filepath, fd);
-
- /* enforce suitable tty state */
-
- memset (&tty, 0, sizeof tty);
- if (tcgetattr (fd, &tty)) {
- fprintf(stderr, "tcgetattr failed on %s\n", filepath);
- close(fd);
- goto bail;
- }
-
- tty.c_lflag &= ~(ISIG | ICANON | IEXTEN | ECHO | XCASE |
- ECHOE | ECHOK | ECHONL | ECHOCTL | ECHOKE);
- tty.c_iflag &= ~(INLCR | IGNBRK | IGNPAR | IGNCR | ICRNL |
- IMAXBEL | IXON | IXOFF | IXANY | IUCLC);
- tty.c_oflag &= ~(ONLCR | OPOST | OLCUC | OCRNL | ONLRET);
- tty.c_cc[VMIN] = 1;
- tty.c_cc[VTIME] = 0;
- tty.c_cc[VEOF] = 1;
- tty.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | CRTSCTS);
- tty.c_cflag |= (8 | CREAD | 0 | 0 | 1 | CLOCAL);
-
- cfsetispeed(&tty, B115200);
- cfsetospeed(&tty, B115200);
- tcsetattr(fd, TCSANOW, &tty);
-
- init_aep(aep_context, &aep_context->aeps[aep_context->scan], filepath);
-
- if (configure(aep_context, &aep_context->aeps[aep_context->scan], filepath,
- aep_context->config_filepath, NULL) < 0) {
- fprintf(stderr, "config for %s failed\n", filepath);
- close(fd);
- goto bail;
- }
-
- if (write(fd, zero, sizeof(zero)) != sizeof(zero)) {
- close(fd);
- goto bail;
- }
- if (aep_context->verbose)
- fprintf(stderr, "sending reset\n");
- c = AEPC_RESET;
- if (write(fd, &c, 1) != 1) {
- close(fd);
- goto bail;
- }
-
- if (aep_context->verbose)
- fprintf(stderr, "done reset\n");
-
- aep_context->aeps[aep_context->scan].fd = fd;
- aep_context->aeps[aep_context->scan].sec_last_traffic = tv.tv_sec;
- aep_context->aeps[aep_context->scan].index = aep_context->scan;
-
- if (aep_context->scan > aep_context->highest)
- aep_context->highest = aep_context->scan;
-
- add_pollfd(aep_context, fd, POLLIN | POLLERR);
-
- for (n = 0; n < CHANNELS_PER_PROBE; n++) {
- struct aep_channel *ch = &aep_context->aeps[aep_context->scan].ch[n];
-
- select_map(ch);
-
- if (aep_context->original_count_channel_names) {
- for (m = 0; m < aep_context->count_channel_names; m++)
- if (!strcmp(ch->channel_name, aep_context->channel_name[m]))
- break;
-
- if (m == aep_context->count_channel_names)
- continue;
- } else
- if (aep_context->count_channel_names < (aep_context->matched_channel_names + 1))
- aep_context->count_channel_names++;
-
- ch->requested = 1;
- aep_context->matched_channel_names++;
-
- aep_context->awaiting_capture |= 7 << (aep_context->scan * 3);
- }
-
- aep_context->aeps[aep_context->scan].done_config |= 1;
-
-bail:
- aep_context->scans++;
- aep_context->scan++;
- if (aep_context->scan == MAX_PROBES)
- aep_context->scan = 0;
-
- /* if we're waiting to start but saw every channel / probe */
-
-// fprintf(stderr, "* %d %d %d\n", aep_context->has_started, aep_context->count_channel_names, aep_context->matched_channel_names);
-
- if (!aep_context->has_started &&
- aep_context->count_channel_names == aep_context->matched_channel_names) {
- /* nobody is waiting for config completion? */
-
- c = 0;
- for (m = 0; m <= aep_context->highest; m++)
- if (aep_context->aeps[m].fd > 0) {
-// fprintf(stderr, "a %d: %d\n",
-// m, aep_context->aeps[m].done_config);
- c = 1;
- if (aep_context->aeps[m].done_config != 3 || aep_context->aeps[m].invalid) {
-// fprintf(stderr, " done_config is %d\n", aep_context->aeps[m].done_config);
- goto post_start;
- }
- }
-
- if (c == 0)
- goto post_start;
-
- /*
- * in the case we want to start all probes, don't know how many there are
- * allow time to discover and recover from any initial comms error
- */
-
- if (aep_context->scans < (MAX_PROBES * 2))
- goto post_start;
-
- /*
- * the number of guys we would start
- * is all of them, is it? Becuase we need to
- * eliminate cross-channel latency as far as we
- * can
- */
-
- c = 0;
- for (m = 0; m <= aep_context->highest; m++) {
-// fprintf(stderr, "%d: %d %d\n", m, aep_context->aeps[m].fd, aep_context->aeps[m].done_config);
- if (aep_context->aeps[m].fd > 0 && aep_context->aeps[m].done_config == 3) {
- for (i = 0; i < CHANNELS_PER_PROBE; i++)
- if (aep_context->aeps[m].ch[i].requested)
- c++;
- }
- }
-
- if (c != aep_context->matched_channel_names) {
-// fprintf(stderr, "c=%d mcn=%d\n", c, aep_context->matched_channel_names);
- goto post_start;
- }
-
- /* tell everyone to start */
-
- fprintf(stderr, "Starting...\n");
-
- chan = 0;
- for (m = 0; m <= aep_context->highest; m++) {
- if (aep_context->aeps[m].fd <= 0 ||
- aep_context->aeps[m].done_config != 3 ) {
- fprintf(stderr, "not starting %d fd %d done_config %d\n", m, aep_context->aeps[m].fd, aep_context->aeps[m].done_config);
- continue;
- }
-
- if (aep_context->verbose)
- fprintf(stderr, "sending start to %d\n", m);
- c = AEPC_START;
- if (write(aep_context->aeps[m].fd, &c, 1) != 1) {
- fprintf(stderr,
- "Failed to send start\n");
- }
-
- for (i = 0; i < CHANNELS_PER_PROBE; i++) {
- ch = &aep_context->aeps[m].ch[i];
-
- if (!ch->requested)
- continue;
-
- strncpy(aep_context->aep_shared->channel_name[chan], ch->channel_name, sizeof(aep_context->aep_shared->channel_name[0]));
- aep_context->aep_shared->channel_name[chan][sizeof(aep_context->aep_shared->channel_name[0]) - 1] = '\0';
- strncpy(aep_context->aep_shared->channel_name_pretty[chan], ch->channel_name_pretty, sizeof(aep_context->aep_shared->channel_name_pretty[0]));
- aep_context->aep_shared->channel_name_pretty[chan][sizeof(aep_context->aep_shared->channel_name_pretty[0]) - 1] = '\0';
- strncpy(aep_context->aep_shared->supply[chan], ch->supply, sizeof(aep_context->aep_shared->supply[0]));
- aep_context->aep_shared->supply[chan][sizeof(aep_context->aep_shared->supply[0]) - 1] = '\0';
- strncpy(aep_context->aep_shared->colour[chan], ch->colour, sizeof(aep_context->aep_shared->colour[0]));
- aep_context->aep_shared->colour[chan][sizeof(aep_context->aep_shared->colour[0]) - 1] = '\0';
-
- chan++;
- aep_context->aep_shared->chans = chan;
- }
-
- aep_context->aeps[m].started = 1;
- aep_context->has_started = 1;
- aep_context->aeps[m].sec_last_traffic = tv.tv_sec;
- }
-
- }
-post_start:
-
- if (fd_with_rx < 0)
- goto service;
-
- gettimeofday(&tv, NULL);
-
- /* somebody had something for us */
-
- for (m = 0; m <= aep_context->highest; m++) {
-
- aep = &aep_context->aeps[m];
-
- if (aep->fd < 1)
- continue;
-
- /* check for timeout */
-
- if (tv.tv_sec > aep->sec_last_traffic + 2) {
-// fprintf(stderr, "%d: %d %d\n", m, aep_context->aeps[m].done_config, aep_context->aeps[m].started);
- if (aep->done_config != 3 || aep->started) {
- fprintf(stderr, "%s: timeout\n", aep->dev_filepath);
- goto died;
- }
- }
-
- if (aep->fd != fd_with_rx)
- continue;
-
- if (aep_context->verbose)
- fprintf(stderr,"stuff for %d\n", m);
-
- aep->sec_last_traffic = tv.tv_sec;
-
- /* work out how much of the ring we can fill */
-
- if (aep->head <= aep->tail) {
- budget = (aep->head - 1) + (sizeof(aep->ring) - aep->tail);
- p = aep->ring + aep->tail;
- if (!budget)
- continue;
-
- len = read(aep->fd, buf, budget);
- if (len <= 0) {
- fprintf(stderr, "failed to read data\n");
- goto died;
- }
-
- if (aep_context->verbose)
- fprintf(stderr, "%d (a) fetched %d (budget %d) head=%d tail=%d\n", m, len, budget, aep->head, aep->tail);
-
- n = sizeof(aep->ring) - aep->tail;
- if (len < n)
- n = len;
-
- memcpy(p, buf, n);
- aep->tail += n;
- if (aep->tail == sizeof(aep->ring))
- aep->tail = 0;
-
- len -= n;
- if (len) {
- memcpy(aep->ring, &buf[n], len);
- aep->tail += len;
- }
-
- } else {
- budget = aep->head - aep->tail - 1;
- p = aep->ring + aep->tail;
- if (!budget)
- continue;
-
- len = read(aep->fd, p, budget);
- if (len <= 0) {
- fprintf(stderr, "failed to read data\n");
- goto died;
- }
-
- if (aep_context->verbose)
- fprintf(stderr, "%d (b) fetched %d (budget %d) head=%d tail=%d\n", m, len, budget, aep->head, aep->tail);
-
- aep->tail += len;
- }
-
- if (aep->tail == sizeof(aep->ring))
- aep->tail = 0;
-
- continue;
-
-died:
- fprintf(stderr, "removing probe due to error...\n");
- for (i = 0; i < CHANNELS_PER_PROBE; i++)
- if (aep->ch[i].requested) {
- aep_context->awaiting_capture &= ~(1 << (m * 3 + i));
- aep_context->matched_channel_names--;
- }
- probe_close(aep);
- remove_pollfd(aep_context, aep->fd);
- aep->fd = 0;
- m = aep_context->highest;
- }
-
-service:
-
- /*
- * service the existing devices
- * need to limit the amount of time spent in the service
- * otherwise other probes will drop data
- */
-
- for (n = 0; n <= aep_context->highest; n++) {
-
- aep = &aep_context->aeps[n];
-
- if (aep->fd <= 0)
- continue;
- m = service_aep_buffers(aep, MAX_BYTES_PER_AEP_SERVICE);
- if (m >= 0)
- continue;
- if (m < -1) {
- n = aep_context->highest + 1;
- continue;
- }
-
- if (!aep_context->verbose)
- continue;
- fprintf(stderr, "service failed\n");
- for (i = 0; i < CHANNELS_PER_PROBE; i++) {
- if (!aep->ch[i].requested)
- continue;
- aep_context->awaiting_capture &= ~(1 << (n * 3 + i));
- aep_context->matched_channel_names--;
- }
- probe_close(aep);
- remove_pollfd(aep_context, aep->fd);
- aep->fd = 0;
- }
-
- if (aep_context->scans > (5 * MAX_PROBES) &&
- aep_context->awaiting_capture == 0 && aep_context->exit_after_capture) {
- fprintf(stderr, "done all capture\n");
- aep_context->aep_shared->finished = 1;
- return -1;
- }
-
- /* if nothing waiting fail immediately if anything has buffered data to service */
-
- aep_context->poll_timeout_ms = 10;
- for (n = 0; n <= aep_context->highest; n++) {
- if (aep_context->aeps[n].fd <= 0)
- continue;
-
- if (aep_context->aeps[n].head != aep_context->aeps[n].tail)
- aep_context->poll_timeout_ms = 0;
- }
-
- return 0;
-}
-
-static int loop;
-
-void sighandler(int sig)
-{
- loop = 0;
-}
-
-
-int aep_init_and_fork(struct aep_context *aep_context)
-{
- int n, m, i;
- struct aep_channel *ch;
-
- loop = 1;
-
- signal(SIGINT, sighandler);
-
- init_interpolation();
-
- // create our lump of shared memory
- // which is usable by all forked threads
-
- n = open("/dev/zero", O_RDWR);
- aep_context->aep_shared = mmap(NULL, sizeof (struct aep_shared),
- PROT_READ | PROT_WRITE, MAP_SHARED, n, 0);
- close(n);
-
- aep_context->aep_shared->head = 0;
- aep_context->aep_shared->tail = 0;
-
- aep_context->semaphore = sem_open("linaro.aep", O_CREAT | O_RDWR, 0600, 0);
-
- /* fork off aep service loop */
-
- n = fork();
- if (n)
- return n;
-
- /*
- * child process runs independently
- * fills the named pipe fifo with sample packets
- */
-
- aep_context->semaphore = sem_open("linaro.aep", O_CREAT | O_RDWR, 0600, 0);
-
- aep_context->aep_shared->finished = 0;
- aep_context->poll_timeout_ms = 10;
-
- while (!aep_context->aep_shared->finished) {
-
- n = poll(aep_context->pollfds, aep_context->count_pollfds, aep_context->poll_timeout_ms);
- if (n < 0) {
-// fprintf(stderr, "poll returned %d\n", n);
- aep_context->aep_shared->finished = 1;
- }
-
- for (n = 0; n < aep_context->count_pollfds; n++)
- if (aep_context->pollfds[n].revents)
- if (service_aeps(aep_context, aep_context->pollfds[n].fd) < 0) {
-// fprintf(stderr, "service_aeps < 0\n");
- aep_context->aep_shared->finished = 1;
- }
-
- if (service_aeps(aep_context, -1) < 0) {
-// fprintf(stderr, "service_aeps -1 < 0\n");
- aep_context->aep_shared->finished = 1;
- }
-
- }
-
- sem_close(aep_context->semaphore);
-
- /*
- * Compute and stash the averages
- */
- m = 0;
- for (n = 0; n <= aep_context->highest; n++) {
- if (aep_context->aeps[n].fd < 1)
- continue;
-
- for (i = 0; i < CHANNELS_PER_PROBE; i++) {
- ch = &aep_context->aeps[n].ch[i];
-;
- if (configure(aep_context, &aep_context->aeps[n],
- aep_context->aeps[n].dev_filepath,
- aep_context->config_filepath, ch) < 0)
- fprintf(stderr, "failed to update config\n");
-
- aep_context->aep_shared->averages[m][0] = ch->simple_avg[0] / ch->avg_count;
- aep_context->aep_shared->averages[m][1] = ch->simple_avg[1] / ch->avg_count;
- aep_context->aep_shared->averages[m][2] = ch->simple_avg[2] / ch->avg_count;
- aep_context->aep_shared->min[m][0] = ch->min[0];
- aep_context->aep_shared->min[m][1] = ch->min[1];
- aep_context->aep_shared->min[m][2] = ch->min[2];
- aep_context->aep_shared->max[m][0] = ch->max[0];
- aep_context->aep_shared->max[m][1] = ch->max[1];
- aep_context->aep_shared->max[m][2] = ch->max[2];
- m++;
- }
-
- probe_close(&aep_context->aeps[n]);
- }
-
- return 0;
-}
-
-struct aep_result * aep_wait_for_next_result(struct aep_context *aep_context)
-{
- struct timespec ts;
- struct timeval tv;
- struct aep_shared *aep_shared = aep_context->aep_shared;
-
- gettimeofday(&tv, NULL);
- ts.tv_sec = tv.tv_sec + 2;
- ts.tv_nsec = 0;
-
- if (sem_timedwait(aep_context->semaphore, &ts) < 0)
- return NULL;
-
- if (aep_shared->tail == aep_shared->head)
- return NULL;
-
- return &aep_shared->aep_result[aep_shared->tail];
-}
-
-void aep_free_result(struct aep_context *aep_context)
-{
- struct aep_shared *aep_shared = aep_context->aep_shared;
-
- if (aep_shared->tail == sizeof(aep_shared->aep_result) / sizeof(aep_shared->aep_result[0]) - 1)
- aep_shared->tail = 0;
- else
- aep_shared->tail++;
-}
diff --git a/libarmep/service.c b/libarmep/service.c
new file mode 100644
index 0000000..1fcec1a
--- /dev/null
+++ b/libarmep/service.c
@@ -0,0 +1,674 @@
+/*
+ * Author: Andy Green <andy.green@linaro.org>
+ * Copyright (C) 2012 Linaro, LTD
+ *
+ * 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 "libarmep.h"
+
+#include <linux/serial.h>
+#include <sys/mman.h>
+
+void add_pollfd(struct aep_context *aep_context, int fd, int events)
+{
+ aep_context->pollfds[aep_context->count_pollfds].fd = fd;
+ aep_context->pollfds[aep_context->count_pollfds].events = events;
+ aep_context->pollfds[aep_context->count_pollfds++].revents = 0;
+}
+
+void remove_pollfd(struct aep_context *aep_context, int fd)
+{
+ int n;
+
+ for (n = 0; n < aep_context->count_pollfds; n++)
+ if (aep_context->pollfds[n].fd == fd) {
+ while (n < aep_context->count_pollfds) {
+ aep_context->pollfds[n] = aep_context->pollfds[n + 1];
+ n++;
+ }
+ aep_context->count_pollfds--;
+ }
+}
+
+static void init_aep(struct aep_context *aep_context, struct aep *aep, const char *device_filepath)
+{
+ int n, m;
+ struct aep_channel *ch;
+
+ aep->head = 0;
+ aep->tail = 0;
+ aep->predicted_frame = 0;
+ aep->state = APP_INIT_MAGIC;
+ aep->invalid = 0;
+ aep->counter = 0;
+ aep->started = 0;
+ aep->done_config = 0;
+
+ aep->aep_context = aep_context;
+
+ strncpy(aep->dev_filepath, device_filepath,
+ sizeof aep->dev_filepath - 1);
+ aep->dev_filepath[sizeof aep->dev_filepath - 1] = '\0';
+
+ for (n = 0; n < CHANNELS_PER_PROBE; n++) {
+ ch = &aep->ch[n];
+
+ ch->ignore = 0;
+ ch->triggered = 0;
+ ch->requested = 0;
+ ch->summary[0] = '\0';
+ ch->aep = aep;
+ ch->trigger_slave = NULL;
+ ch->out_head = ch->out_tail = 0;
+ ch->voffset[0] = 0;
+ ch->vnoise[0] = 0;
+ ch->voffset[1] = 0;
+ ch->vnoise[1] = 0;
+ ch->rshunt = 0;
+ sprintf(ch->channel_name, "%s-%d", device_filepath, n);
+ ch->pretrig_ring = NULL;
+ ch->ring_samples = 0;
+ ch->trigger_filter = 0;
+ ch->pretrigger_samples_taken = 0;
+ avg_mean_us_init(&ch->avg_mean_voltage, aep->aep_context->average_len);
+ avg_mean_us_init(&ch->avg_mean_current, aep->aep_context->average_len);
+ ch->decimation_counter = 0;
+ for (m = 0; m < sizeof(ch->min) / sizeof(ch->min[0]); m++) {
+ ch->min[m] = 999;
+ ch->max[m] = 0;
+ }
+ ch->samples_seen = 0;
+ ch->simple_avg[0] = 0.0;
+ ch->simple_avg[1] = 0.0;
+ ch->simple_avg[2] = 0.0;
+ ch->avg_count = 0;
+ ch->samples = 0;
+ strcpy(ch->supply, "none");
+ sprintf(ch->colour, "#%06X", rand() & 0xffffff);
+ }
+}
+
+
+static void select_map(struct aep_channel *ch)
+{
+ int m;
+ int sel = -1;
+ double delta = 999999;
+
+ for (m = 0; m < (sizeof interp_tables / sizeof interp_tables[0]); m++) {
+ if (ch->percentage_error_ref <= interp_tables[m].percentage_error_ref) {
+ if (delta > (interp_tables[m].percentage_error_ref - ch->percentage_error_ref)) {
+ delta = interp_tables[m].percentage_error_ref - ch->percentage_error_ref;
+ sel = m;
+ }
+ } else {
+ if (delta > (ch->percentage_error_ref - interp_tables[m].percentage_error_ref)) {
+ delta = ch->percentage_error_ref - interp_tables[m].percentage_error_ref;
+ sel = m;
+ }
+ }
+ }
+ if (ch->aep->aep_context->verbose)
+ fprintf(stderr, "%s = corr map %d %f%%\n",
+ ch->channel_name, sel, ch->percentage_error_ref);
+ ch->map_table = &interp_tables[sel];
+}
+
+void probe_close(struct aep *aep)
+{
+ unsigned char c = AEPC_STOP;
+ int n;
+
+ write(aep->fd, &c, 1);
+
+ for (n = 0; n < CHANNELS_PER_PROBE; n++) {
+ if (aep->ch[n].pretrig_ring)
+ free(aep->ch[n].pretrig_ring);
+
+ avg_mean_us_free(&aep->ch[n].avg_mean_voltage);
+ avg_mean_us_free(&aep->ch[n].avg_mean_current);
+ }
+
+ if (aep->aep_context->verbose)
+ fprintf(stderr, "closing %d\n", aep->fd);
+ close(aep->fd);
+}
+
+int service_aeps(struct aep_context *aep_context, int fd_with_rx)
+{
+ static unsigned char zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
+ int fd;
+ int budget;
+ int len;
+ struct timeval tv;
+ unsigned char *p;
+ unsigned char c;
+ char filepath[20];
+ struct termios tty;
+ struct serial_struct sinfo;
+ int n, m, i, chan;
+ struct aep *aep;
+ struct aep_channel *ch;
+ unsigned char buf[AEP_INPUT_QUEUE];
+
+ if (fd_with_rx >= 0)
+ goto post_start;
+
+ gettimeofday(&tv, NULL);
+
+ /* look for any new devices appearing */
+
+ if (aep_context->aeps[aep_context->scan].fd > 0)
+ goto bail;
+
+ sprintf(filepath, "/dev/ttyACM%d", aep_context->scan);
+ fd = open(filepath, O_RDWR | O_NONBLOCK | O_EXCL | O_NOCTTY);
+
+ if (fd < 0)
+ goto bail;
+
+ if (ioctl(fd, TIOCEXCL) < 0) {
+ fprintf(stderr, "Wasn't able to open %s exclusive",
+ filepath);
+ close(fd);
+ goto bail;
+ }
+
+
+ fprintf(stderr, "+");
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (ioctl(fd, TIOCGSERIAL, &sinfo) == 0) {
+ sinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE;
+ ioctl(fd, TIOCSSERIAL, &sinfo);
+ }
+
+ if (aep_context->verbose)
+ fprintf(stderr, "initing %s fd=%d\n", filepath, fd);
+
+ /* enforce suitable tty state */
+
+ memset (&tty, 0, sizeof tty);
+ if (tcgetattr (fd, &tty)) {
+ fprintf(stderr, "tcgetattr failed on %s\n", filepath);
+ close(fd);
+ goto bail;
+ }
+
+ tty.c_lflag &= ~(ISIG | ICANON | IEXTEN | ECHO | XCASE |
+ ECHOE | ECHOK | ECHONL | ECHOCTL | ECHOKE);
+ tty.c_iflag &= ~(INLCR | IGNBRK | IGNPAR | IGNCR | ICRNL |
+ IMAXBEL | IXON | IXOFF | IXANY | IUCLC);
+ tty.c_oflag &= ~(ONLCR | OPOST | OLCUC | OCRNL | ONLRET);
+ tty.c_cc[VMIN] = 1;
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VEOF] = 1;
+ tty.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | CRTSCTS);
+ tty.c_cflag |= (8 | CREAD | 0 | 0 | 1 | CLOCAL);
+
+ cfsetispeed(&tty, B115200);
+ cfsetospeed(&tty, B115200);
+ tcsetattr(fd, TCSANOW, &tty);
+
+ init_aep(aep_context, &aep_context->aeps[aep_context->scan], filepath);
+
+ if (configure(aep_context, &aep_context->aeps[aep_context->scan], filepath,
+ aep_context->config_filepath, NULL) < 0) {
+ fprintf(stderr, "config for %s failed\n", filepath);
+ close(fd);
+ goto bail;
+ }
+
+ if (write(fd, zero, sizeof(zero)) != sizeof(zero)) {
+ close(fd);
+ goto bail;
+ }
+ if (aep_context->verbose)
+ fprintf(stderr, "sending reset\n");
+ c = AEPC_RESET;
+ if (write(fd, &c, 1) != 1) {
+ close(fd);
+ goto bail;
+ }
+
+ if (aep_context->verbose)
+ fprintf(stderr, "done reset\n");
+
+ aep_context->aeps[aep_context->scan].fd = fd;
+ aep_context->aeps[aep_context->scan].sec_last_traffic = tv.tv_sec;
+ aep_context->aeps[aep_context->scan].index = aep_context->scan;
+
+ if (aep_context->scan > aep_context->highest)
+ aep_context->highest = aep_context->scan;
+
+ add_pollfd(aep_context, fd, POLLIN | POLLERR);
+
+ for (n = 0; n < CHANNELS_PER_PROBE; n++) {
+ struct aep_channel *ch = &aep_context->aeps[aep_context->scan].ch[n];
+
+ select_map(ch);
+
+ if (aep_context->original_count_channel_names) {
+ for (m = 0; m < aep_context->count_channel_names; m++)
+ if (!strcmp(ch->channel_name, aep_context->channel_name[m]))
+ break;
+
+ if (m == aep_context->count_channel_names)
+ continue;
+ } else
+ if (aep_context->count_channel_names < (aep_context->matched_channel_names + 1))
+ aep_context->count_channel_names++;
+
+ ch->requested = 1;
+ aep_context->matched_channel_names++;
+
+ aep_context->awaiting_capture |= 7 << (aep_context->scan * 3);
+ }
+
+ aep_context->aeps[aep_context->scan].done_config |= 1;
+
+bail:
+ aep_context->scans++;
+ aep_context->scan++;
+ if (aep_context->scan == MAX_PROBES)
+ aep_context->scan = 0;
+
+ /* if we're waiting to start but saw every channel / probe */
+
+ if (!aep_context->has_started &&
+ aep_context->count_channel_names == aep_context->matched_channel_names) {
+ /* nobody is waiting for config completion? */
+
+ c = 0;
+ for (m = 0; m <= aep_context->highest; m++)
+ if (aep_context->aeps[m].fd > 0) {
+ c = 1;
+ if (aep_context->aeps[m].done_config != 3 || aep_context->aeps[m].invalid)
+ goto post_start;
+ }
+
+ if (c == 0)
+ goto post_start;
+
+ /*
+ * in the case we want to start all probes, don't know how many there are
+ * allow time to discover and recover from any initial comms error
+ */
+
+ if (aep_context->scans < (MAX_PROBES * 2))
+ goto post_start;
+
+ /*
+ * the number of guys we would start
+ * is all of them, is it? Becuase we need to
+ * eliminate cross-channel latency as far as we
+ * can
+ */
+
+ c = 0;
+ for (m = 0; m <= aep_context->highest; m++)
+ if (aep_context->aeps[m].fd > 0 && aep_context->aeps[m].done_config == 3) {
+ for (i = 0; i < CHANNELS_PER_PROBE; i++)
+ if (aep_context->aeps[m].ch[i].requested)
+ c++;
+ }
+
+ if (c != aep_context->matched_channel_names)
+ goto post_start;
+
+ /* tell everyone to start */
+
+ fprintf(stderr, "Starting...\n");
+
+ chan = 0;
+ for (m = 0; m <= aep_context->highest; m++) {
+ if (aep_context->aeps[m].fd <= 0 ||
+ aep_context->aeps[m].done_config != 3 ) {
+ fprintf(stderr, "not starting %d fd %d done_config %d\n", m, aep_context->aeps[m].fd, aep_context->aeps[m].done_config);
+ continue;
+ }
+
+ if (aep_context->verbose)
+ fprintf(stderr, "sending start to %d\n", m);
+ c = AEPC_START;
+ if (write(aep_context->aeps[m].fd, &c, 1) != 1) {
+ fprintf(stderr,
+ "Failed to send start\n");
+ }
+
+ for (i = 0; i < CHANNELS_PER_PROBE; i++) {
+ ch = &aep_context->aeps[m].ch[i];
+
+ if (!ch->requested)
+ continue;
+
+ strncpy(aep_context->aep_shared->channel_name[chan], ch->channel_name, sizeof(aep_context->aep_shared->channel_name[0]));
+ aep_context->aep_shared->channel_name[chan][sizeof(aep_context->aep_shared->channel_name[0]) - 1] = '\0';
+ strncpy(aep_context->aep_shared->channel_name_pretty[chan], ch->channel_name_pretty, sizeof(aep_context->aep_shared->channel_name_pretty[0]));
+ aep_context->aep_shared->channel_name_pretty[chan][sizeof(aep_context->aep_shared->channel_name_pretty[0]) - 1] = '\0';
+ strncpy(aep_context->aep_shared->supply[chan], ch->supply, sizeof(aep_context->aep_shared->supply[0]));
+ aep_context->aep_shared->supply[chan][sizeof(aep_context->aep_shared->supply[0]) - 1] = '\0';
+ strncpy(aep_context->aep_shared->colour[chan], ch->colour, sizeof(aep_context->aep_shared->colour[0]));
+ aep_context->aep_shared->colour[chan][sizeof(aep_context->aep_shared->colour[0]) - 1] = '\0';
+
+ chan++;
+ aep_context->aep_shared->chans = chan;
+ }
+
+ aep_context->aeps[m].started = 1;
+ aep_context->has_started = 1;
+ aep_context->aeps[m].sec_last_traffic = tv.tv_sec;
+ }
+
+ }
+post_start:
+
+ if (fd_with_rx < 0)
+ goto service;
+
+ gettimeofday(&tv, NULL);
+
+ /* somebody had something for us */
+
+ for (m = 0; m <= aep_context->highest; m++) {
+
+ aep = &aep_context->aeps[m];
+
+ if (aep->fd < 1)
+ continue;
+
+ /* check for timeout */
+
+ if (tv.tv_sec > aep->sec_last_traffic + 2)
+ if (aep->done_config != 3 || aep->started) {
+ fprintf(stderr, "%s: timeout\n", aep->dev_filepath);
+ goto died;
+ }
+
+ if (aep->fd != fd_with_rx)
+ continue;
+
+ if (aep_context->verbose)
+ fprintf(stderr,"stuff for %d\n", m);
+
+ aep->sec_last_traffic = tv.tv_sec;
+
+ /* work out how much of the ring we can fill */
+
+ if (aep->head <= aep->tail) {
+ budget = (aep->head - 1) + (sizeof(aep->ring) - aep->tail);
+ p = aep->ring + aep->tail;
+ if (!budget)
+ continue;
+
+ len = read(aep->fd, buf, budget);
+ if (len <= 0) {
+ fprintf(stderr, "failed to read data\n");
+ goto died;
+ }
+
+ if (aep_context->verbose)
+ fprintf(stderr, "%d (a) fetched %d (budget %d) head=%d tail=%d\n", m, len, budget, aep->head, aep->tail);
+
+ n = sizeof(aep->ring) - aep->tail;
+ if (len < n)
+ n = len;
+
+ memcpy(p, buf, n);
+ aep->tail += n;
+ if (aep->tail == sizeof(aep->ring))
+ aep->tail = 0;
+
+ len -= n;
+ if (len) {
+ memcpy(aep->ring, &buf[n], len);
+ aep->tail += len;
+ }
+
+ } else {
+ budget = aep->head - aep->tail - 1;
+ p = aep->ring + aep->tail;
+ if (!budget)
+ continue;
+
+ len = read(aep->fd, p, budget);
+ if (len <= 0) {
+ fprintf(stderr, "failed to read data\n");
+ goto died;
+ }
+
+ if (aep_context->verbose)
+ fprintf(stderr, "%d (b) fetched %d (budget %d) head=%d tail=%d\n", m, len, budget, aep->head, aep->tail);
+
+ aep->tail += len;
+ }
+
+ if (aep->tail == sizeof(aep->ring))
+ aep->tail = 0;
+
+ continue;
+
+died:
+ fprintf(stderr, "removing probe due to error...\n");
+ for (i = 0; i < CHANNELS_PER_PROBE; i++)
+ if (aep->ch[i].requested) {
+ aep_context->awaiting_capture &= ~(1 << (m * 3 + i));
+ aep_context->matched_channel_names--;
+ }
+ probe_close(aep);
+ remove_pollfd(aep_context, aep->fd);
+ aep->fd = 0;
+ m = aep_context->highest;
+ }
+
+service:
+
+ /*
+ * service the existing devices
+ * need to limit the amount of time spent in the service
+ * otherwise other probes will drop data
+ */
+
+ for (n = 0; n <= aep_context->highest; n++) {
+
+ aep = &aep_context->aeps[n];
+
+ if (aep->fd <= 0)
+ continue;
+ m = aep_protocol_parser(aep, MAX_BYTES_PER_AEP_SERVICE);
+ if (m >= 0)
+ continue;
+ if (m < -1) {
+ n = aep_context->highest + 1;
+ continue;
+ }
+
+ if (!aep_context->verbose)
+ continue;
+ fprintf(stderr, "service failed\n");
+ for (i = 0; i < CHANNELS_PER_PROBE; i++) {
+ if (!aep->ch[i].requested)
+ continue;
+ aep_context->awaiting_capture &= ~(1 << (n * 3 + i));
+ aep_context->matched_channel_names--;
+ }
+ probe_close(aep);
+ remove_pollfd(aep_context, aep->fd);
+ aep->fd = 0;
+ }
+
+ if (aep_context->scans > (5 * MAX_PROBES) &&
+ aep_context->awaiting_capture == 0 && aep_context->exit_after_capture) {
+ fprintf(stderr, "done all capture\n");
+ aep_context->aep_shared->finished = 1;
+ return -1;
+ }
+
+ /* if nothing waiting fail immediately if anything has buffered data to service */
+
+ aep_context->poll_timeout_ms = 10;
+ for (n = 0; n <= aep_context->highest; n++) {
+ if (aep_context->aeps[n].fd <= 0)
+ continue;
+
+ if (aep_context->aeps[n].head != aep_context->aeps[n].tail)
+ aep_context->poll_timeout_ms = 0;
+ }
+
+ return 0;
+}
+
+static int loop;
+
+void sighandler(int sig)
+{
+ loop = 0;
+}
+
+
+int aep_init_and_fork(struct aep_context *aep_context)
+{
+ int n, m, i;
+ struct aep_channel *ch;
+
+ loop = 1;
+
+ signal(SIGINT, sighandler);
+
+ init_interpolation();
+
+ /*
+ * create our lump of shared memory
+ * which is usable by all forked threads
+ */
+
+ n = open("/dev/zero", O_RDWR);
+ aep_context->aep_shared = mmap(NULL, sizeof (struct aep_shared),
+ PROT_READ | PROT_WRITE, MAP_SHARED, n, 0);
+ close(n);
+
+ aep_context->aep_shared->head = 0;
+ aep_context->aep_shared->tail = 0;
+
+ aep_context->semaphore = sem_open("linaro.aep", O_CREAT | O_RDWR, 0600, 0);
+
+ /* fork off aep service loop */
+
+ n = fork();
+ if (n)
+ return n;
+
+ /*
+ * child process runs independently
+ * fills the named pipe fifo with sample packets
+ */
+
+ aep_context->semaphore = sem_open("linaro.aep", O_CREAT | O_RDWR, 0600, 0);
+
+ aep_context->aep_shared->finished = 0;
+ aep_context->poll_timeout_ms = 10;
+
+ while (!aep_context->aep_shared->finished) {
+
+ n = poll(aep_context->pollfds, aep_context->count_pollfds, aep_context->poll_timeout_ms);
+ if (n < 0)
+ aep_context->aep_shared->finished = 1;
+
+ for (n = 0; n < aep_context->count_pollfds; n++)
+ if (aep_context->pollfds[n].revents)
+ if (service_aeps(aep_context, aep_context->pollfds[n].fd) < 0)
+ aep_context->aep_shared->finished = 1;
+
+ if (service_aeps(aep_context, -1) < 0)
+ aep_context->aep_shared->finished = 1;
+ }
+
+ sem_close(aep_context->semaphore);
+
+ /*
+ * Compute and stash the averages
+ */
+ m = 0;
+ for (n = 0; n <= aep_context->highest; n++) {
+ if (aep_context->aeps[n].fd < 1)
+ continue;
+
+ for (i = 0; i < CHANNELS_PER_PROBE; i++) {
+ ch = &aep_context->aeps[n].ch[i];
+;
+ if (configure(aep_context, &aep_context->aeps[n],
+ aep_context->aeps[n].dev_filepath,
+ aep_context->config_filepath, ch) < 0)
+ fprintf(stderr, "failed to update config\n");
+
+ aep_context->aep_shared->averages[m][0] = ch->simple_avg[0] / ch->avg_count;
+ aep_context->aep_shared->averages[m][1] = ch->simple_avg[1] / ch->avg_count;
+ aep_context->aep_shared->averages[m][2] = ch->simple_avg[2] / ch->avg_count;
+ aep_context->aep_shared->min[m][0] = ch->min[0];
+ aep_context->aep_shared->min[m][1] = ch->min[1];
+ aep_context->aep_shared->min[m][2] = ch->min[2];
+ aep_context->aep_shared->max[m][0] = ch->max[0];
+ aep_context->aep_shared->max[m][1] = ch->max[1];
+ aep_context->aep_shared->max[m][2] = ch->max[2];
+ m++;
+ }
+
+ probe_close(&aep_context->aeps[n]);
+ }
+
+ return 0;
+}
+
+/*
+ * helper for user code to block until next aep_result available
+ */
+
+struct aep_result * aep_wait_for_next_result(struct aep_context *aep_context)
+{
+ struct timespec ts;
+ struct timeval tv;
+ struct aep_shared *aep_shared = aep_context->aep_shared;
+
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec + 2;
+ ts.tv_nsec = 0;
+
+ if (sem_timedwait(aep_context->semaphore, &ts) < 0)
+ return NULL;
+
+ if (aep_shared->tail == aep_shared->head)
+ return NULL;
+
+ return &aep_shared->aep_result[aep_shared->tail];
+}
+
+/*
+ * helper for user code to deal with ringbuffer
+ */
+
+void aep_free_result(struct aep_context *aep_context)
+{
+ struct aep_shared *aep_shared = aep_context->aep_shared;
+
+ if (aep_shared->tail == sizeof(aep_shared->aep_result) / sizeof(aep_shared->aep_result[0]) - 1)
+ aep_shared->tail = 0;
+ else
+ aep_shared->tail++;
+}
+
+