From a1fc867bf2cb75f439b6e4095eb5a192ed21eeff Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 13 Apr 2011 18:40:39 -0300 Subject: [PATCH] atrf-path: option -P to load a min/max profile; pass/fail indication in GUI - sweep.h (MIN_DIFF, MAX_DIFF, struct sweep): added min/max profile - sweep.h (do_sweep), atrf-path.c (do_half_sweep, do_sweep): compare result against limits and return pass/fail decision - sweep.h (N_CHAN), atrf-path.c (do_half_sweep, do_sweeps), gui.c (N_CHAN): declare number of channels in one central place instead of scattering it all around the program - atrf-path.c (do_read_profile, read_profile, usage, main): new option -P to read a min/max profile - gui.c (indicate, main): moved indicator to separate function and improved blink logic - gui.c (OVER_RGBA, UNDER_RGBA, indicate, main): change color to indicate pass/fail --- tools/atrf-path/atrf-path.c | 133 ++++++++++++++++++++++++++++++++---- tools/atrf-path/gui.c | 42 +++++++++--- tools/atrf-path/sweep.h | 18 ++++- 3 files changed, 167 insertions(+), 26 deletions(-) diff --git a/tools/atrf-path/atrf-path.c b/tools/atrf-path/atrf-path.c index d121f54..7d10f48 100644 --- a/tools/atrf-path/atrf-path.c +++ b/tools/atrf-path/atrf-path.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "at86rf230.h" @@ -110,28 +111,44 @@ static void sample(const struct sweep *sweep, int cont_tx, } -static void do_half_sweep(const struct sweep *sweep, int cont_tx, +static int do_half_sweep(const struct sweep *sweep, int cont_tx, struct sample *res) { - int chan; + int i, chan; + int fail = 0; if (sweep->cont_tx && sweep->cont_tx != cont_tx) - return; - for (chan = 11; chan <= 26; chan++) { + return 0; + chan = 11; + for (i = 0; i != N_CHAN; i++) { set_channel(sweep->rx, chan); set_channel(sweep->tx, chan); usleep(155); /* table 7-2, tTR19 */ sample(sweep, cont_tx, res, chan == 11 && !sweep->cont_tx); + if (res->avg > sweep->max[i]) + fail = 1; + if (!fail && res->avg < sweep->min[i]) + fail = -1; + res += 2; + chan++; } + return fail; } -void do_sweep(const struct sweep *sweep, struct sample *res) +int do_sweep(const struct sweep *sweep, struct sample *res) { - do_half_sweep(sweep, CONT_TX_M500K, res); - do_half_sweep(sweep, CONT_TX_P500K, res+1); + int fail1, fail2; + + fail1 = do_half_sweep(sweep, CONT_TX_M500K, res); + fail2 = do_half_sweep(sweep, CONT_TX_P500K, res+1); + if (fail1 > 0 || fail2 > 0) + return 1; + if (fail1 < 0 || fail2 < 0) + return -1; + return 0; } @@ -154,7 +171,7 @@ static void print_sweep(const struct sweep *sweep, const struct sample *res) static void do_sweeps(const struct sweep *sweep, int sweeps) { - struct sample res[16*2]; /* 16 channels, 2 offsets */ + struct sample res[N_CHAN*2]; /* 2 offsets per channel */ int i; for (i = 0; i != sweeps; i++) { @@ -166,6 +183,85 @@ static void do_sweeps(const struct sweep *sweep, int sweeps) } +static int do_read_profile(const char *name, struct sweep *sweep) +{ + FILE *file; + char buf[300]; + int got; + char *p; + double min = MIN_DIFF, max = MAX_DIFF; + int n = 0; + + file = fopen(name, "r"); + if (!file) { + perror(name); + exit(1); + } + while (fgets(buf, sizeof(buf), file)) { + p = strchr(buf, '\n'); + if (p) + *p = 0; + p = strchr(buf, '#'); + if (p) + *p = 0; + for (p = buf; *p && isspace(*p); p++); + if (!*p) + continue; + got = sscanf(buf, "%lf %lf", &min, &max); + switch (got) { + case 0: + fprintf(stderr, "can't parse \"%s\"\n", buf); + exit(1); + case 1: + max = MAX_DIFF; + /* fall through */ + case 2: + if (min < MIN_DIFF) { + fprintf(stderr, "minimum is %g dBm\n", + MIN_DIFF); + exit(1); + } + if (max > MAX_DIFF) { + fprintf(stderr, "maximum is %g dBm\n", + MAX_DIFF); + exit(1); + } + if (min > max) { + fprintf(stderr, "lower bound > upper bound\n"); + exit(1); + } + if (n == N_CHAN) { + fprintf(stderr, "too many channels\n"); + exit(1); + } + sweep->min[n] = min; + sweep->max[n] = max; + n++; + break; + default: + abort(); + } + } + fclose(file); + return n; +} + + +static void read_profile(const char *name, struct sweep *sweep) +{ + int n = 0; + + if (name) + n = do_read_profile(name, sweep); + + while (n != N_CHAN) { + sweep->min[n] = MIN_DIFF; + sweep->max[n] = MAX_DIFF; + n++; + } +} + + static void usage(const char *name) { fprintf(stderr, @@ -175,15 +271,16 @@ static void usage(const char *name) "%6s %s -g common_args [[sweeps] samples]\n" #endif "\n" -" common args: [-p power] [-t trim_tx [-t trim_rx]] [-T offset]\n" -" driver_tx[:arg] driver_rx[:arg]\n\n" +" common args: [-p power] [-P profile] [-t trim_tx [-t trim_rx]]\n" +" [-T offset] driver_tx[:arg] driver_rx[:arg]\n\n" #ifdef HAVE_GFX -" -g display results graphically\n" +" -g display results graphically\n" #endif -" -p power transmit power, 0 to 15 (default %d)\n" -" -t trim trim capacitor, 0 to 15 (default %d)\n" -" -T offset constant wave offset in MHz, -0.5 or +0.5 (default: scan both)\n" +" -p power transmit power, 0 to 15 (default %d)\n" +" -P profile load profile for pass/fail decisions\n" +" -t trim trim capacitor, 0 to 15 (default %d)\n" +" -T offset constant wave offset in MHz, -0.5 or +0.5 (default: scan both)\n" , name, #ifdef HAVE_GFX @@ -206,12 +303,13 @@ int main(int argc, char **argv) }; int graphical = 0; int power = DEFAULT_POWER; + const char *profile = NULL; int sweeps = 1; unsigned long tmp; char *end; int c; - while ((c = getopt(argc, argv, "gp:t:T:")) != EOF) + while ((c = getopt(argc, argv, "gp:P:t:T:")) != EOF) switch (c) { case'g': graphical = 1; @@ -223,6 +321,9 @@ int main(int argc, char **argv) usage(*argv); power = tmp; break; + case 'P': + profile = optarg; + break; case 't': tmp = strtoul(optarg, &end, 0); if (*end || tmp > 15) @@ -270,6 +371,8 @@ int main(int argc, char **argv) usage(*argv); } + read_profile(profile, &sweep); + sweep.tx = atrf_open(tx_drv); if (!sweep.tx) return 1; diff --git a/tools/atrf-path/gui.c b/tools/atrf-path/gui.c index b8809cf..cd1e25a 100644 --- a/tools/atrf-path/gui.c +++ b/tools/atrf-path/gui.c @@ -29,11 +29,10 @@ #define XRES 320 #define YRES 240 -#define N_CHAN 16 - - #define FG_RGBA 0xffffffff /* measurement color */ #define OK_RGBA 0x00ff00ff +#define OVER_RGBA 0xffff00ff +#define UNDER_RGBA 0xff0000ff #define CHAN_STEP 20 /* 4 pixels/MHz */ #define SIDE_STEP 2 @@ -84,6 +83,33 @@ static void draw(SDL_Surface *s, const struct sample *res, int cont_tx) } +static void indicate(SDL_Surface *s, int fail) +{ + static uint32_t last = 0; + uint32_t color; + + switch (fail) { + case 0: + color = OK_RGBA; + break; + case 1: + color = OVER_RGBA; + break; + case -1: + color = UNDER_RGBA; + break; + default: + abort(); + } + if (color == last) + color = 0; + last = color; + + filledCircleColor(s, STATUS_X, STATUS_Y, STATUS_R, color); + aacircleColor(s, STATUS_X, STATUS_Y, STATUS_R, color); +} + + static void clear(SDL_Surface *s) { SDL_FillRect(s, NULL, SDL_MapRGB(s->format, 0, 0, 0)); @@ -124,6 +150,7 @@ void gui(const struct sweep *sweep, int sweeps) SDL_Surface *surf; SDL_Event event; int cycle = 0; + int fail; if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "SDL_init: %s\n", SDL_GetError()); @@ -145,19 +172,14 @@ void gui(const struct sweep *sweep, int sweeps) event.type == SDL_QUIT) return; tstart(); - do_sweep(sweep, res); + fail = do_sweep(sweep, res); tstop(); SDL_LockSurface(surf); clear(surf); - if (cycle++ & 1) { - filledCircleColor(surf, STATUS_X, STATUS_Y, STATUS_R, - OK_RGBA); - aacircleColor(surf, STATUS_X, STATUS_Y, STATUS_R, - OK_RGBA); - } + indicate(surf, fail); draw(surf, res, sweep->cont_tx); SDL_UnlockSurface(surf); diff --git a/tools/atrf-path/sweep.h b/tools/atrf-path/sweep.h index 73c89ce..80dcae4 100644 --- a/tools/atrf-path/sweep.h +++ b/tools/atrf-path/sweep.h @@ -19,6 +19,12 @@ #include "atrf.h" +#define N_CHAN 16 + +#define MIN_DIFF -97.0 /* RSSI(min)-TX(max) = -94 - 3 */ +#define MAX_DIFF 7.0 /* RSSI(max)-TX(min) = -10 - (-17) */ + + struct sweep { struct atrf_dsc *tx; struct atrf_dsc *rx; @@ -27,6 +33,8 @@ struct sweep { int power; uint8_t cont_tx; int samples; + double min[N_CHAN]; + double max[N_CHAN]; }; struct sample { @@ -35,6 +43,14 @@ struct sample { }; -void do_sweep(const struct sweep *sweep, struct sample *res); +/* + * do_sweep returns whether the signal is within the limits: + * + * 1: at least one sample is above the maximum + * 0: all samples are between minimum and maximum + * -1: at least one sample below the minimum, and none above the maximum + */ + +int do_sweep(const struct sweep *sweep, struct sample *res); #endif /* !SWEEP_H */