diff options
author | Andy Green <andy.green@linaro.org> | 2012-10-06 12:51:05 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2012-10-06 12:51:05 +0800 |
commit | 7865c5bd9a6dca340b400b754b9d87e11d7367c2 (patch) | |
tree | 987dfb46470ce412d0d6f830facab5e2b1f0d0a1 /arm-probe | |
parent | b8bd63c81b0082e40bb6d7ea59f0523abbab07a7 (diff) |
introduce autotools libarmep
Signed-off-by: Andy Green <andy.green@linaro.org>
Diffstat (limited to 'arm-probe')
-rw-r--r-- | arm-probe/Makefile.am | 6 | ||||
-rw-r--r-- | arm-probe/arm-probe.c | 495 |
2 files changed, 501 insertions, 0 deletions
diff --git a/arm-probe/Makefile.am b/arm-probe/Makefile.am new file mode 100644 index 0000000..426ff71 --- /dev/null +++ b/arm-probe/Makefile.am @@ -0,0 +1,6 @@ +bin_PROGRAMS=arm-probe +arm_probe_SOURCES=arm-probe.c +arm_probe_CFLAGS=-fPIC -Wall -std=gnu99 -pedantic +arm_probe_LDFLAGS=-fPIC +arm_probe_LDADD=-L../libarmep -larmep + diff --git a/arm-probe/arm-probe.c b/arm-probe/arm-probe.c new file mode 100644 index 0000000..1d8c6c7 --- /dev/null +++ b/arm-probe/arm-probe.c @@ -0,0 +1,495 @@ +/* + * Author: Daniel Lezcano <daniel.lezcano@linaro.org> (Initial version) + * : 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/libarmep.h" + +int just_power = 0; +char stdinbuf[512]; +char stdinline[512] = ""; +int stdinpos = 0; +int stdinlen = 0; +double do_average = 0; + +static void issue_samples(enum samples_actions sa, struct aep_channel *ch, + double voltage, double current); + + +struct aep_context aep_context = { + .samples = issue_samples, + .config_filepath = "./config", + .highest = -1, + .decimate = 1, + .mv_min = 400, + .trigger_filter_us = 400, + .end_trigger_filter_us = 500000, + .average_len = 1, + .configuration_name = "default_configuration", +}; + +void pull_stdin_if_needed(void) +{ + int n; + + if (stdinpos != stdinlen) + return; + + n = read(0, stdinbuf, sizeof stdinbuf); + if (n < 0) { + if (aep_context.verbose) + fprintf(stderr, "pull_stdin_if_needed: n=%d\n", n); + return; + } + if (n == 0 && aep_context.verbose) + fprintf(stderr, "pull_stdin_if_needed n = 0\n"); + stdinpos = 0; + stdinlen = n; +} + +int get_stdin_line(char *buf, int maxlen) +{ + while (maxlen--) { + if (stdinpos == stdinlen) { + pull_stdin_if_needed(); + if (stdinpos == stdinlen) + return -1; + } + *buf++ = stdinbuf[stdinpos++]; + if (buf[-1] == '\n') { + buf[-1] = '\0'; + return 0; + } + } + return -1; +} + +/* + * this is the callback where the results appear + */ + +static void issue_samples(enum samples_actions sa, struct aep_channel *ch, + double voltage, double current) +{ + static int periodic; + static char titles[4096]; + static int pos; + + switch (sa) { + + case AEPSA_DATA_STARTING: + printf("#\n"); + pos = 0; + if (!stdinline[0]) + break; + printf("%s", stdinline); + get_stdin_line(stdinline, sizeof stdinline); + + break; + case AEPSA_DATA_STARTING_CHANNELS: + + printf("# %s\t%s\t%s\n", + ch->channel_name, ch->channel_name_pretty, ch->supply); + + if (just_power) + pos += sprintf(&titles[pos], " %s(W)", + ch->channel_name_pretty); + else + pos += sprintf(&titles[pos]," %s(V) %s(A) %s(W)", + ch->channel_name_pretty, + ch->channel_name_pretty, + ch->channel_name_pretty); + break; + + case AEPSA_DATA_STARTING_DONE: + printf("#\nsample"); + puts(titles); + break; + + case AEPSA_START_PRE: + periodic++; + if (periodic & 0x1ff) + break; + fprintf(stderr, "ARMED "); + break; + case AEPSA_SAMPLE_PRE: + if (periodic & 0x1ff) + break; + if (just_power) + fprintf(stderr, " %.5f", voltage * current); + else + fprintf(stderr, " %.2f %.4f %.5f", + voltage, current, voltage * current); + break; + case AEPSA_END_PRE: + if (periodic & 0x1ff) + break; + fprintf(stderr, "\n"); + break; + + case AEPSA_START: + periodic++; + if (stdinline[0]) { + printf("%s", stdinline); + if (get_stdin_line(stdinline, sizeof stdinline)) + stdinline[0] = '\0'; + } else + printf("%f", voltage); + if (periodic & 0x1ff) + break; + fprintf(stderr, "TRIGD "); + break; + case AEPSA_SAMPLE: + if (just_power) + printf(" %.5f", voltage * current); + else + printf(" %.2f %.4f %.5f", + voltage, current, voltage * current); + if (periodic & 0x1ff) + break; + if (just_power) + fprintf(stderr, " %.5f", voltage * current); + else + fprintf(stderr, " %.2f %.4f %.5f", + voltage, current, voltage * current); + break; + case AEPSA_END: + printf("\n"); + if (periodic & 0x1ff) + break; + fprintf(stderr, "\n"); + break; + } +} + + + + +static struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { "raw", no_argument, NULL, 'r' }, + { "mean", required_argument, NULL, 'm' }, + { "decimate", required_argument, NULL, 'd' }, + { "mvtrigger", required_argument, NULL, 'q' }, + { "mwtrigger", required_argument, NULL, 'w' }, + { "channel", required_argument, NULL, 'c' }, + { "mstrighold", required_argument, NULL, 't' }, + { "ustrigfilter", required_argument, NULL, 'f' }, + { "mslength", required_argument, NULL, 'l' }, + { "exitoncap", no_argument, NULL, 'x' }, + { "justpower", no_argument, NULL, 'j' }, + { "config", required_argument, NULL, 'C' }, + { "offexit", no_argument, NULL, 'o' }, + { "mspretrigger", required_argument, NULL, 'p' }, + { "nocorrection", no_argument, NULL, 'n' }, + { "autozero", no_argument, NULL, 'z' }, + { "average", required_argument, NULL, 'a' }, + { NULL, 0, 0, 0 } +}; + +static int loop; + +void sighandler(int sig) +{ + loop = 0; +} + +int main(int argc, char *argv[]) +{ + time_t t; + struct tm *tmp; + char hostname[200]; + char date[200]; + int n = 0; + struct aep_channel *ch; + double tt; + int m; + int i; + + loop = 1; + + signal(SIGINT, sighandler); + + while (n >= 0) { + n = getopt_long(argc, argv, "xl:t:c:q:hvm:jC:w:f:op:rd:nza:", + options, NULL); + if (n < 0) + continue; + switch (n) { + case 'a': + do_average = atof(optarg); + break; + case 'z': + fprintf(stderr, "\n\n *** Note: for autozero, you " + "should short both sides of the " + "\n channel sense " + "leads to 0V... in some cases a powered-down " + "target will do ***\n\n"); + aep_context.no_correction = 1; + aep_context.mv_min = 0; + aep_context.mw_min = 0; + aep_context.auto_zero = 1; + aep_context.average_len = 50000; + aep_context.ms_capture = aep_context.average_len / 10; + aep_context.decimate = aep_context.average_len; + aep_context.exit_after_capture = 1; + break; + case 'n': + aep_context.no_correction = 1; + break; + case 'd': + aep_context.decimate = atoi(optarg); + break; + case 'r': + aep_context.show_raw = 1; + break; + case 'p': + aep_context.ms_pretrigger = atoi(optarg); + break; + case 'o': + aep_context.require_off = 1; + break; + case 'f': + aep_context.trigger_filter_us = atoi(optarg); + break; + case 'w': + aep_context.mw_min = atoi(optarg); + if (aep_context.mw_min) + aep_context.mw_min_plus_hyst = + aep_context.mw_min + (aep_context.mw_min / 10); + break; + case 'j': + just_power = 1; + break; + case 'C': + strncpy(aep_context.config_filepath, optarg, + sizeof aep_context.config_filepath - 1); + aep_context.config_filepath[ + sizeof aep_context.config_filepath - 1] = '\0'; + break; + case 't': + aep_context.ms_holdoff = atoi(optarg); + break; + case 'l': + aep_context.ms_capture = atoi(optarg); + break; + case 'c': + if (aep_context.count_channel_names == MAX_PROBES) { + fprintf(stderr, "too many channels named\n"); + return -1; + } + strncpy(aep_context.channel_name[aep_context.count_channel_names], optarg, + sizeof aep_context.channel_name[0] - 1); + aep_context.channel_name[aep_context.count_channel_names] + [sizeof aep_context.channel_name[0] - 1] = '\0'; + aep_context.count_channel_names++; + break; + case 'q': + aep_context.mv_min = atoi(optarg); + break; + case 'm': + aep_context.average_len = atoi(optarg); + break; + case 'v': + aep_context.verbose++; + break; + case 'x': + aep_context.exit_after_capture = 1; + break; + default: + case 'h': + fprintf(stderr, "Usage: arm-probe \n" + " [--verbose -v] Increase debug on stderr\n" + " [--config -C <file>] use alternate config " + "(default ./config)\n" + " [--mean -m <averagng depth>] (default 1)\n" + " [--decimate -d <report interval>] only " + "output every n samples\n" + " [--mvtrigger -q <min mV>] suppress output " + "below this voltage (defaut 400mV)\n" + " [--mwtrigger -w <min mW>] suppress output " + "below this power (default 0mW)\n" + " [--channel -c <name>] select channel\n" + " [--mstrighold -t <ms>] delay in ms after " + "power seen before capture\n" + " [--ustrigfilter -f <us>] require trigger " + "threshold to be exceeded for at " + "least this amount of time\n" + " [--mspretrigger -p <ms>] at trigger, issue " + "this many samples from BEFORE " + "trigger first\n" + " [--length -l <ms>] period to capture after " + "trigger (+holdoff if any)\n" + " [--exitoncap -x] after requested capture " + "(-l) completes on all channels, " + "exit app\n" + " [--offexit -o] wait for voltage to reduce " + "below trigger before exiting\n" + " [--justpower -j] just write power\n" + " [--autozero -z] measure channel and store " + "result as zero offset\n" + " [--average -a <float>] at the end of the " + "capture, add a simple mean average " + "to the \n" + " stdout dataset, starting at " + "<float> seconds\n" + ); + exit(1); + } + } + + aep_context.original_count_channel_names = aep_context.count_channel_names; + + if (!isatty(0)) { + + m = 1; + n = 0; + while (m) { + n++; + if (n > 1000) { + fprintf(stderr, "problem with stdin format\n"); + return 1; + } + if (get_stdin_line(stdinline, sizeof stdinline)) { + fprintf(stderr, "get_stdin_line failed\n"); + m = 0; + continue; + } + if (stdinline[0] != '#') { + if (aep_context.verbose) + fprintf(stderr, "seen '%s'\n", stdinline); + puts("#"); + m = 0; + continue; + } + puts(stdinline); + } + } + + configure(&aep_context, NULL, "xx", aep_context.config_filepath, NULL); + + printf("# configuration: %s\n", aep_context.config_filepath); + printf("# config_name: %s\n", aep_context.configuration_name); + printf("# trigger: %fV (hyst %fV) %fW (hyst %fW) %uus\n", + aep_context.mv_min / 1000.0, TRIG_HYSTERESIS_MV / 1000.0, + aep_context.mw_min / 1000.0, TRIG_HYSTERESIS_MV / 1000.0, + aep_context.trigger_filter_us); + + fprintf(stderr, "Configuration: %s\n", aep_context.configuration_name); + + t = time(NULL); + tmp = localtime(&t); + if (tmp) { + if (strftime(date, sizeof date, "%a, %d %b %Y %T %z", tmp)) + printf("# date: %s\n", date); + } + + if (!gethostname(hostname, sizeof hostname)) + printf("# host: %s\n", hostname); + + printf("#\n"); + + /* + * the main service loop + */ + + while (loop) + if (service_aeps(&aep_context) < 0) + loop = 0; + + /* + * we are finished if we reach here... + * append simple average to results if requested + */ + + if (aep_context.awaiting_capture == 0 && + aep_context.exit_after_capture && do_average) { + + tt = do_average; + + for (m = 0; m < 2; m++) { + + if (stdinline[0]) { + printf("%s", stdinline); + if (get_stdin_line(stdinline, sizeof stdinline)) + stdinline[0] = '\0'; + } else + printf("%f", tt); + + for (n = 0; n <= aep_context.highest; n++) { + for (i = 0; i < CHANNELS_PER_PROBE; i++) { + ch = &aep_context.aeps[n].ch[i]; + if (just_power) + printf(" %.5f", ch->simple_avg[2] / ch->avg_count); + else + printf(" %.2f %.4f %.5f", + ch->simple_avg[0] / ch->avg_count, + ch->simple_avg[1] / ch->avg_count, + ch->simple_avg[2] / ch->avg_count); + } + } + printf("\n"); + + tt += do_average / 3; + } + } + + /* + * dump a summary of extents and mean of all channels now we are done + */ + + fprintf(stderr, "\n\n"); + + for (m = 0; m <= aep_context.highest; m++) { + int i; + + if (aep_context.aeps[m].fd <= 0) + continue; + + + for (i = 0; i < CHANNELS_PER_PROBE; i++) { + ch = &aep_context.aeps[m].ch[i]; + if (configure(&aep_context, &aep_context.aeps[m], + aep_context.aeps[m].dev_filepath, + aep_context.config_filepath, ch) < 0) + fprintf(stderr, "failed to update config\n"); + + if (ch->min[0] == 999) + continue; + + fprintf(stderr, "%12s: %4.2fV < %4.3fVavg < %4.2fV, " + "%6.4fA < %6.5fAavg < %6.4fA, " + "%9.6fW < %9.6fWavg < %9.6fW\n", + ch->channel_name, ch->min[0], + ch->simple_avg[0] / ch->avg_count, ch->max[0], + ch->min[1], + ch->simple_avg[1] / ch->avg_count, ch->max[1], + ch->min[2], + ch->simple_avg[2] / ch->avg_count, ch->max[2]); + } + probe_close(&aep_context.aeps[m]); + } + + fprintf(stderr, "exited\n"); + + return 0; +} + |