diff options
author | Andy Green <andy.green@linaro.org> | 2012-10-12 09:03:59 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2012-10-12 09:18:17 +0800 |
commit | 0ed496e702cb52ba5eee23864ba4643c4407824d (patch) | |
tree | 5458b7c2ed60dbc2c16b0cdc693309f42897f082 | |
parent | 020f93df6d6354a18e05a65707967ce53bba26e5 (diff) |
refactor sample.c into protocol.c and service.c
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r-- | libarmep/Makefile.am | 2 | ||||
-rw-r--r-- | libarmep/libarmep.h | 23 | ||||
-rw-r--r-- | libarmep/protocol.c | 430 | ||||
-rw-r--r-- | libarmep/sample.c | 1113 | ||||
-rw-r--r-- | libarmep/service.c | 674 |
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++; +} + + |