Root/tools/atrf-txrx/atrf-txrx.c

Source at commit 8710be5665ec17da807a848e3286d3940c76dc1d created 6 years 8 months ago.
By Werner Almesberger, tools/atrf-txrx/atrf-txrx.c: add section headers and update clkm comment
1/*
2 * atrf-txrx/atrf-txrx.c - ben-wpan AT86RF230 TX/RX
3 *
4 * Written 2010-2011, 2013 by Werner Almesberger
5 * Copyright 2010-2011, 2013 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <unistd.h>
18#include <string.h>
19#include <math.h>
20#include <signal.h>
21#include <sys/wait.h>
22#include <sys/time.h>
23
24#include "at86rf230.h"
25#include "atrf.h"
26#include "misctxrx.h"
27#include "cwtest.h"
28
29#include "pcap.h"
30
31
32/*
33 * According to IEEE 802.15.4-2003 section E.2.6, channel 15 is the only
34 * channel that falls into the 802.11 guard bands in North America an Europe.
35 */
36
37#define DEFAULT_CHANNEL 15 /* channel 15, 2425 MHz */
38
39#define DEFAULT_TRIM 8 /* trim range is 0-15, see also ECN0002 */
40
41
42/*
43 * Transmit power, dBm. IEEE 802.15.4-2003 section E.3.1.3 specifies a transmit
44 * power of 0 dBm for IEEE 802.15.4. We assume an antenna gain of 3 dB or
45 * better.
46 */
47
48#define DEFAULT_POWER -3.2 /* transmit power, dBm */
49
50
51struct ping {
52    uint32_t seq; /* sequence number from originator, > 0 */
53    uint32_t ack; /* last sequence number received, 0 if none */
54    uint8_t pad[117]; /* pad to 127 bytes */
55    uint16_t crc;
56} __attribute__((__packed__));
57
58enum rx_res {
59    rx_exit,
60    rx_good,
61    rx_bad,
62    rx_timeout,
63};
64
65enum mode {
66    mode_msg,
67    mode_hmac,
68    mode_per,
69    mode_ping,
70    mode_cont_tx,
71};
72
73
74static volatile int run = 1;
75
76
77/* ----- Helper functions -------------------------------------------------- */
78
79
80/*
81 * mhz: 0 disable CLKM
82 * >0 output specified clock
83 */
84
85static struct atrf_dsc *init_txrx(const char *driver, int trim, unsigned mhz)
86{
87    struct atrf_dsc *dsc;
88
89    dsc = atrf_open(driver);
90    if (!dsc)
91        exit(1);
92    
93    atrf_reset_rf(dsc);
94    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TRX_OFF);
95
96#if 1 // def HAVE_USB /* @@@ yeah, ugly */
97    atrf_reg_write(dsc, REG_XOSC_CTRL,
98        (XTAL_MODE_INT << XTAL_MODE_SHIFT) | trim);
99#else
100    atrf_reg_write(dsc, REG_XOSC_CTRL, XTAL_MODE_EXT << XTAL_MODE_SHIFT);
101#endif
102
103    if (!atrf_set_clkm(dsc, mhz))
104        if (mhz) {
105            atrf_close(dsc);
106            exit(1);
107        }
108
109    /* We want to see all interrupts, not only the ones we're expecting. */
110    atrf_reg_write(dsc, REG_IRQ_MASK, 0xff);
111
112    flush_interrupts(dsc);
113    if (atrf_identify(dsc) == artf_at86rf231)
114        wait_for_interrupt(dsc, IRQ_CCA_ED_DONE, IRQ_CCA_ED_DONE, 1);
115            /* according to table 7-1, 37 us max */
116
117    return dsc;
118}
119
120
121static void set_channel(struct atrf_dsc *dsc, int channel)
122{
123    atrf_reg_write(dsc, REG_PHY_CC_CCA, (1 << CCA_MODE_SHIFT) | channel);
124}
125
126
127static void set_rate(struct atrf_dsc *dsc, uint8_t rate)
128{
129    if (!rate)
130        return;
131    switch (atrf_identify(dsc)) {
132    case artf_at86rf230:
133        fprintf(stderr, "AT86RF230 only supports 250 kbps\n");
134        break;
135    case artf_at86rf231:
136        atrf_reg_write(dsc, REG_TRX_CTRL_2, rate);
137        break;
138    default:
139        abort();
140    }
141}
142
143
144/* ----- Message transmit/receive ------------------------------------------ */
145
146
147static void receive_message(struct atrf_dsc *dsc)
148{
149    uint8_t buf[MAX_PSDU+1]; /* PSDU+LQI */
150    int n, ok, i;
151    uint8_t ed, lqi;
152
153    fprintf(stderr, "Ready.\n");
154    wait_for_interrupt(dsc, IRQ_TRX_END,
155        IRQ_TRX_END | IRQ_RX_START | IRQ_AMI, 0);
156    if (!run)
157        return;
158
159    n = atrf_buf_read(dsc, buf, sizeof(buf));
160    if (n < 0)
161        exit(1);
162    if (n < 3) {
163        fprintf(stderr, "%d bytes received\n", n);
164        exit(1);
165    }
166    ed = atrf_reg_read(dsc, REG_PHY_ED_LEVEL);
167    ok = !!(atrf_reg_read(dsc, REG_PHY_RSSI) & RX_CRC_VALID);
168    lqi = buf[n-1];
169    fprintf(stderr, "%d bytes payload, CRC %s, LQI %u, ED %d dBm\n",
170        n-3, ok ? "OK" : "BAD", lqi, -91+ed);
171    for (i = 0; i != n-3; i++)
172        putchar(buf[i] < ' ' || buf[i] > '~' ? '?' : buf[i]);
173    putchar('\n');
174}
175
176
177static void write_pcap_hdr(FILE *file)
178{
179    struct pcap_file_header hdr = {
180        .magic = PCAP_FILE_MAGIC,
181        .version_major = 2,
182        .version_minor = 4,
183        .thiszone = 0,
184        .sigfigs = 0,
185        .snaplen = MAX_PSDU,
186        .linktype = DLT_IEEE802_15_4
187    };
188
189    if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) {
190        perror("fwrite");
191        exit(1);
192    }
193}
194
195
196static void write_pcap_rec(FILE *file, const struct timeval *tv,
197    const void *buf, int n)
198{
199    struct pcap_pkthdr hdr = {
200        .ts_sec = tv->tv_sec,
201        .ts_usec = tv->tv_usec,
202        .caplen = n,
203        .len = n
204    };
205
206    if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) {
207        perror("fwrite");
208        exit(1);
209    }
210    if (fwrite(buf, n, 1, file) != 1) {
211        perror("fwrite");
212        exit(1);
213    }
214}
215
216
217static void receive_pcap(struct atrf_dsc *dsc, const char *name)
218{
219    FILE *file;
220    uint8_t buf[MAX_PSDU+1]; /* PSDU+LQI */
221    struct timeval now;
222    int n;
223    int count = 0;
224
225    file = fopen(name, "w");
226    if (!file) {
227        perror(name);
228        exit(1);
229    }
230    write_pcap_hdr(file);
231    while (run) {
232        wait_for_interrupt(dsc,
233            IRQ_TRX_END, IRQ_TRX_END | IRQ_RX_START | IRQ_AMI, 0);
234        if (!run)
235            break;
236        gettimeofday(&now, NULL);
237        n = atrf_buf_read(dsc, buf, sizeof(buf));
238        if (n < 0)
239            exit(1);
240        if (n < 2) {
241            fprintf(stderr, "%d bytes received\n", n);
242            continue;
243        }
244        write_pcap_rec(file, &now, buf, n-1);
245        (void) write(2, ".", 1);
246        count++;
247    }
248    if (fclose(file) == EOF) {
249        perror(name);
250        exit(1);
251    }
252    fprintf(stderr, "%sreceived %d message%s\n", count ? "\n" : "",
253        count, count == 1 ? "" : "s");
254}
255
256
257static void receive(struct atrf_dsc *dsc, const char *name)
258{
259    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_RX_ON);
260    /*
261     * 180 us, according to AVR2001 section 4.2. We time out after
262     * nominally 200 us.
263     */
264    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 1);
265
266    if (name)
267        receive_pcap(dsc, name);
268    else
269        receive_message(dsc);
270}
271
272
273static void transmit(struct atrf_dsc *dsc, const char *msg, int times)
274{
275    uint8_t buf[MAX_PSDU];
276
277    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
278    /*
279     * 180 us, according to AVR2001 section 4.3. We time out after
280     * nominally 200 us.
281     */
282    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 1);
283
284    /*
285     * We need to copy the message to append the CRC placeholders.
286     */
287    strcpy((void *) buf, msg);
288    atrf_buf_write(dsc, buf, strlen(msg)+2);
289
290    while (run && times--) {
291        /* @@@ should wait for clear channel */
292        atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START);
293
294        /* wait up to 10 ms (nominally) */
295        wait_for_interrupt(dsc, IRQ_TRX_END,
296           IRQ_TRX_END | IRQ_PLL_LOCK, 10);
297    }
298}
299
300
301static void receive_hmac(struct atrf_dsc *dsc)
302{
303    uint8_t buf[MAX_PSDU];
304    uint8_t lqi;
305    int n, i;
306
307    atrf_rx_mode(dsc, 1);
308    n = atrf_rx(dsc, buf, sizeof(buf), 0, &lqi);
309    atrf_rx_mode(dsc, 0);
310
311    if (n < 2) {
312        fprintf(stderr, "%d bytes received\n", n);
313        exit(1);
314    }
315    for (i = 0; i != n-2; i++)
316        putchar(buf[i] < ' ' || buf[i] > '~' ? '?' : buf[i]);
317    putchar('\n');
318}
319
320
321static void transmit_hmac(struct atrf_dsc *dsc, const char *msg)
322{
323    atrf_rx_mode(dsc, 1);
324    atrf_tx(dsc, msg, strlen(msg));
325    atrf_rx_mode(dsc, 0);
326}
327
328
329/* ----- PER test ---------------------------------------------------------- */
330
331
332static void transmit_pattern(struct atrf_dsc *dsc, double pause_s, int times)
333{
334    uint8_t buf[MAX_PSDU];
335    uint8_t n = 0;
336    int us = fmod(pause_s, 1)*1000000;
337
338    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
339    /*
340     * 180 us, according to AVR2001 section 4.3. We time out after
341     * nominally 200 us.
342     */
343    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 1);
344
345    while (run) {
346        memset(buf, n, sizeof(buf));
347        atrf_buf_write(dsc, buf, sizeof(buf));
348
349        atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START);
350
351        /* wait up to 10 ms (nominally) */
352        wait_for_interrupt(dsc, IRQ_TRX_END,
353           IRQ_TRX_END | IRQ_PLL_LOCK, 10);
354
355        if (pause_s >= 1)
356            sleep(pause_s);
357        if (us)
358            usleep(us);
359
360        if (times && !--times)
361            break;
362        n++;
363    }
364}
365
366
367/* ----- Ping -------------------------------------------------------------- */
368
369
370static void ping_tx(struct atrf_dsc *dsc, const struct ping *pck)
371{
372    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
373    /*
374     * 180 us, according to AVR2001 section 4.3. We time out after
375     * nominally 200 us.
376     */
377    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 1);
378
379    atrf_buf_write(dsc, pck, sizeof(*pck));
380    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START);
381
382    /* wait up to 10 ms (nominally) */
383    wait_for_interrupt(dsc, IRQ_TRX_END,
384       IRQ_TRX_END | IRQ_PLL_LOCK, 10);
385}
386
387
388static enum rx_res ping_rx(struct atrf_dsc *dsc, struct ping *pck, int wait_ms)
389{
390    uint8_t irq;
391    int n;
392
393    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_RX_ON);
394    irq = wait_for_interrupt(dsc, IRQ_TRX_END,
395        IRQ_TRX_END | IRQ_RX_START | IRQ_PLL_LOCK, wait_ms);
396    if (!run)
397        return rx_exit;
398    if (!irq)
399        return rx_timeout;
400
401    n = atrf_buf_read(dsc, pck, sizeof(*pck));
402    if (n < 0)
403        exit(1);
404    if (n != sizeof(*pck)) {
405        fprintf(stderr, "%d bytes received\n", n);
406        return rx_bad;
407    }
408    return atrf_reg_read(dsc, REG_PHY_RSSI) & RX_CRC_VALID ?
409        rx_good : rx_bad;
410}
411
412
413static void ping(struct atrf_dsc *dsc, double max_wait_s, int master)
414{
415    static int first = 1;
416    struct ping tx_pck = {
417        .seq = 0,
418        .ack = 0,
419    };
420    struct ping rx_pck;
421    enum rx_res res;
422
423    while (run) {
424        tx_pck.seq++;
425        if (master || !first) {
426            ping_tx(dsc, &tx_pck);
427            if (!run)
428                break;
429        }
430        first = 0;
431        res = ping_rx(dsc, &rx_pck, master ? max_wait_s*1000 : 0);
432        switch (res) {
433        case rx_good:
434            tx_pck.ack = rx_pck.seq;
435            if (tx_pck.seq == rx_pck.ack)
436                write(2, ".", 1);
437            else
438                write(2, "*", 1);
439            break;
440        case rx_bad:
441            write(2, "-", 1);
442            break;
443        case rx_timeout:
444            write(2, "+", 1);
445            break;
446        case rx_exit:
447            return;
448        default:
449            abort();
450        }
451    }
452}
453
454
455/* ----- Continuous wave test ---------------------------------------------- */
456
457
458static int test_mode(struct atrf_dsc *dsc, uint8_t cont_tx, const char *cmd)
459{
460    int status = 0;
461
462    cw_test_begin(dsc, cont_tx);
463
464    if (cmd)
465        status = system(cmd);
466    else {
467        while (run)
468            sleep(1);
469    }
470
471    cw_test_end(dsc);
472
473    return status;
474}
475
476
477/* ----- Command-line processing ------------------------------------------- */
478
479
480static void die(int sig)
481{
482    run = 0;
483}
484
485
486static void usage(const char *name)
487{
488    fprintf(stderr,
489"usage: %s [common_options] [message [repetitions]]\n"
490" %s [common_options] -H [message]\n"
491" %s [common_options] -E pause_s [repetitions]\n"
492" %s [common_options] -P [max_wait_s]\n"
493" %s [common_options] -T offset [command]\n\n"
494" text message mode:\n"
495" message message string to send (if absent, receive)\n"
496" repetitions number of times the message is sent (default 1)\n\n"
497" text message mode (hard MAC):\n"
498" -H use hard MAC mode\n"
499" message message string to send (if absent, receive)\n"
500" PER test mode (transmit only):\n"
501" -E pause_s seconds to pause between frames (floating-point)\n"
502" repetitions number of messages to send (default: infinite)\n\n"
503" Ping-pong mode:\n"
504" -P exchange packets between two stations\n"
505" max_wait_s generate a new packet if no response is received (master)\n\n"
506" constant wave test mode (transmit only):\n"
507" -T offset test mode. offset is the frequency offset of the constant\n"
508" wave in MHz: -2, -0.5, or +0.5\n"
509" command shell command to run while transmitting (default: wait for\n"
510" SIGINT instead)\n\n"
511" common options: [-c channel|-f freq] [-C mhz] [-d driver[:arg]] [-o file]\n"
512" [-p power] [-r rate] [-t trim]\n"
513" -c channel channel number, 11 to 26 (default %d)\n"
514" -C mhz output clock at 1, 2, 4, 8, or 16 MHz (default: off)\n"
515" -d driver[:arg]\n"
516" use the specified driver (default: %s)\n"
517" -f freq frequency in MHz, 2405 to 2480 (default %d)\n"
518" -o file write received data to a file in pcap format\n"
519" -p power transmit power, -17.2 to 3.0 dBm (default %.1f)\n"
520" -r rate data rate, 250k, 500k, 1M, or 2M (default: 250k)\n"
521" -t trim trim capacitor, 0 to 15 (default %d)\n"
522        , name, name, name, name, name,
523        DEFAULT_CHANNEL, atrf_default_driver_name(),
524        2405+5*(DEFAULT_CHANNEL-11), DEFAULT_POWER,
525        DEFAULT_TRIM);
526    exit(1);
527}
528
529
530static void set_mode(enum mode *mode, enum mode new)
531{
532    if (*mode == mode_msg) {
533        *mode = new;
534        return;
535    }
536    fprintf(stderr, "multiple mode selections\n");
537    exit(1);
538}
539
540
541int main(int argc, char *const *argv)
542{
543    enum mode mode = mode_msg;
544    const char *driver = NULL;
545    int channel = DEFAULT_CHANNEL;
546    double power = DEFAULT_POWER;
547    uint8_t rate = OQPSK_DATA_RATE_250;
548    int trim = DEFAULT_TRIM, times = 1;
549    uint8_t cont_tx = 0;
550    double pause_s = 0;
551    char *end;
552    int c, freq;
553    unsigned clkm = 0;
554    int status = 0;
555    const char *pcap_file = NULL;
556    struct atrf_dsc *dsc;
557
558    while ((c = getopt(argc, argv, "c:C:d:f:Ho:p:r:E:Pt:T:")) != EOF)
559        switch (c) {
560        case 'c':
561            channel = strtoul(optarg, &end, 0);
562            if (*end)
563                usage(*argv);
564            if (channel < 11 || channel > 26)
565                usage(*argv);
566            break;
567        case 'd':
568            driver = optarg;
569            break;
570        case 'f':
571            freq = strtoul(optarg, &end, 0);
572            if (*end)
573                usage(*argv);
574            if (freq % 5)
575                usage(*argv);
576            channel = (freq-2405)/5+11;
577            if (channel < 11 || channel > 26)
578                usage(*argv);
579            break;
580        case 'H':
581            set_mode(&mode, mode_hmac);
582            break;
583        case 'o':
584            pcap_file = optarg;
585            break;
586        case 'p':
587            power = strtod(optarg, &end);
588            if (*end)
589                usage(*argv);
590            break;
591        case 'r':
592            if (!strcmp(optarg, "250k"))
593                rate = OQPSK_DATA_RATE_250;
594            else if (!strcmp(optarg, "500k"))
595                rate = OQPSK_DATA_RATE_500;
596            else if (!strcmp(optarg, "1M"))
597                rate = OQPSK_DATA_RATE_1000;
598            else if (!strcmp(optarg, "2M"))
599                rate = OQPSK_DATA_RATE_2000;
600            else
601                usage(*argv);
602            break;
603        case 't':
604            trim = strtoul(optarg, &end, 0);
605            if (*end)
606                usage(*argv);
607            if (trim > 15)
608                usage(*argv);
609            break;
610        case 'C':
611            clkm = strtol(optarg, &end, 0);
612            if (*end)
613                usage(*argv);
614            if (!clkm)
615                usage(*argv);
616            break;
617        case 'E':
618            set_mode(&mode, mode_per);
619            pause_s = strtof(optarg, &end);
620            if (*end)
621                usage(*argv);
622            break;
623        case 'P':
624            set_mode(&mode, mode_ping);
625            break;
626        case 'T':
627            set_mode(&mode, mode_cont_tx);
628            if (!strcmp(optarg, "-2"))
629                cont_tx = CONT_TX_M2M;
630            else if (!strcmp(optarg, "-0.5"))
631                cont_tx = CONT_TX_M500K;
632            else if (!strcmp(optarg, "+0.5"))
633                cont_tx = CONT_TX_P500K;
634            else
635                usage(*argv);
636            break;
637        default:
638            usage(*argv);
639        }
640
641    signal(SIGINT, die);
642
643    switch (argc-optind) {
644    case 0:
645        dsc = init_txrx(driver, trim, clkm);
646        set_channel(dsc, channel);
647        set_rate(dsc, rate);
648        switch (mode) {
649        case mode_msg:
650            receive(dsc, pcap_file);
651            break;
652        case mode_hmac:
653            receive_hmac(dsc);
654            break;
655        case mode_per:
656            set_power_dBm(dsc, power, 0);
657            transmit_pattern(dsc, pause_s, 0);
658            break;
659        case mode_ping:
660            set_power_dBm(dsc, power, 1);
661            ping(dsc, pause_s, 0);
662            break;
663        case mode_cont_tx:
664            set_power_dBm(dsc, power, 0);
665            status = test_mode(dsc, cont_tx, NULL);
666            break;
667        default:
668            abort();
669        }
670        break;
671    case 2:
672        switch (mode) {
673        case mode_msg:
674        case mode_hmac:
675            break;
676        case mode_per:
677        case mode_ping:
678            /* fall through */
679        case mode_cont_tx:
680            usage(*argv);
681        default:
682            abort();
683        }
684        times = strtoul(argv[optind+1], &end, 0);
685        if (*end)
686            usage(*argv);
687        /* fall through */
688    case 1:
689        dsc = init_txrx(driver, trim, clkm);
690        set_channel(dsc, channel);
691        set_rate(dsc, rate);
692        switch (mode) {
693        case mode_msg:
694            set_power_dBm(dsc, power, 1);
695            transmit(dsc, argv[optind], times);
696            break;
697        case mode_hmac:
698            set_power_dBm(dsc, power, 1);
699            transmit_hmac(dsc, argv[optind]);
700            break;
701        case mode_per:
702            times = strtoul(argv[optind], &end, 0);
703            if (*end)
704                usage(*argv);
705            set_power_dBm(dsc, power, 0);
706            transmit_pattern(dsc, pause_s, times);
707            break;
708        case mode_ping:
709            pause_s = strtof(argv[optind], &end);
710            if (*end)
711                usage(*argv);
712            set_power_dBm(dsc, power, 1);
713            ping(dsc, pause_s, 1);
714            break;
715        case mode_cont_tx:
716            set_power_dBm(dsc, power, 0);
717            status = test_mode(dsc, cont_tx, argv[optind]);
718            break;
719        default:
720            abort();
721        
722        }
723        break;
724    default:
725        usage(*argv);
726    }
727
728    atrf_close(dsc);
729
730    if (status) {
731        if (WIFEXITED(status))
732            return WEXITSTATUS(status);
733        if (WIFSIGNALED(status))
734            raise(WTERMSIG(status));
735        fprintf(stderr, "unexpected exit status %d\n", status);
736        abort();
737    }
738    return 0;
739}
740

Archive Download this file



interactive