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

Source at commit 999ce5302eacd84742dc11202bbebba848682caa created 9 years 8 months ago.
By Werner Almesberger, atrf-txrx: added BER test pattern transmit mode
1/*
2 * atrf-txrx/atrf-txrx.c - ben-wpan AT86RF230 TX/RX
3 *
4 * Written 2010-2011 by Werner Almesberger
5 * Copyright 2010-2011 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
28#include "pcap.h"
29
30
31/*
32 * According to IEEE 802.15.4-2003 section E.2.6, channel 15 is the only
33 * channel that falls into the 802.11 guard bands in North America an Europe.
34 */
35
36#define DEFAULT_CHANNEL 15 /* channel 15, 2425 MHz */
37
38/*
39 * Transmit power, dBm. IEEE 802.15.4-2003 section E.3.1.3 specifies a transmit
40 * power of 0 dBm for IEEE 802.15.4. We assume an antenna gain of 3 dB or
41 * better.
42 */
43
44#define DEFAULT_POWER -3.2 /* transmit power, dBm */
45
46
47static double tx_pwr_230[] = {
48     3.0, 2.6, 2.1, 1.6,
49     1.1, 0.5, -0.2, -1.2,
50    -2.2, -3.2, -4.2, -5.2,
51    -7.2, -9.2, -12.2, -17.2
52};
53
54
55static double tx_pwr_231[] = {
56     3.0, 2.8, 2.3, 1.8,
57     1.3, 0.7, 0.0, -1,
58    -2, -3, -4, -5,
59    -7, -9, -12, -17
60};
61
62
63static volatile int run = 1;
64
65
66/*
67 * clkm: 0 disable CLKM
68 * >0 output 2^(clkm-1) MHz signal
69 */
70
71static struct atrf_dsc *init_txrx(int trim, unsigned clkm)
72{
73    struct atrf_dsc *dsc;
74
75    dsc = atrf_open();
76    if (!dsc)
77        exit(1);
78    
79    atrf_reset_rf(dsc);
80    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TRX_OFF);
81
82#if 1 // def HAVE_USB /* @@@ yeah, ugly */
83    atrf_reg_write(dsc, REG_XOSC_CTRL,
84        (XTAL_MODE_INT << XTAL_MODE_SHIFT) | trim);
85#else
86    atrf_reg_write(dsc, REG_XOSC_CTRL, XTAL_MODE_EXT << XTAL_MODE_SHIFT);
87#endif
88
89    if (!clkm)
90        atrf_reg_write(dsc, REG_TRX_CTRL_0, 0); /* disable CLKM */
91    else
92        atrf_reg_write(dsc, REG_TRX_CTRL_0,
93            (PAD_IO_8mA << PAD_IO_CLKM_SHIFT) | clkm);
94
95    /* We want to see all interrupts, not only the ones we're expecting. */
96    atrf_reg_write(dsc, REG_IRQ_MASK, 0xff);
97
98    (void) atrf_reg_read(dsc, REG_IRQ_STATUS);
99    if (atrf_identify(dsc) == artf_at86rf231)
100        wait_for_interrupt(dsc, IRQ_CCA_ED_DONE, IRQ_CCA_ED_DONE,
101            10, 50); /* according to table 7-1, 37 us max */
102
103    return dsc;
104}
105
106
107static void set_channel(struct atrf_dsc *dsc, int channel)
108{
109    atrf_reg_write(dsc, REG_PHY_CC_CCA, (1 << CCA_MODE_SHIFT) | channel);
110}
111
112
113static void set_power(struct atrf_dsc *dsc, double power, int crc)
114{
115    const double *tx_pwr;
116    int n;
117    uint8_t tmp;
118
119    switch (atrf_identify(dsc)) {
120    case artf_at86rf230:
121        tx_pwr = tx_pwr_230;
122        break;
123    case artf_at86rf231:
124        tx_pwr = tx_pwr_231;
125        break;
126    default:
127        abort();
128    }
129    
130    for (n = 0; n != sizeof(tx_pwr_230)/sizeof(*tx_pwr_230)-1; n++)
131        if (tx_pwr[n] <= power)
132            break;
133    if (fabs(tx_pwr[n]-power) > 0.01)
134        fprintf(stderr, "TX power %.1f dBm\n", tx_pwr[n]);
135
136    switch (atrf_identify(dsc)) {
137    case artf_at86rf230:
138        atrf_reg_write(dsc, REG_PHY_TX_PWR,
139            (crc ? TX_AUTO_CRC_ON_230 : 0) | n);
140        break;
141    case artf_at86rf231:
142        tmp = atrf_reg_read(dsc, REG_PHY_TX_PWR);
143        tmp = (tmp & ~TX_PWR_MASK) | n;
144        atrf_reg_write(dsc, REG_PHY_TX_PWR, tmp);
145        atrf_reg_write(dsc, REG_TRX_CTRL_1,
146            crc ? TX_AUTO_CRC_ON : 0);
147        break;
148    default:
149        abort();
150    }
151}
152
153
154static void receive_message(struct atrf_dsc *dsc)
155{
156    uint8_t buf[MAX_PSDU+1]; /* PSDU+LQI */
157    int n, ok, i;
158    uint8_t ed, lqi;
159
160    fprintf(stderr, "Ready.\n");
161    wait_for_interrupt(dsc, IRQ_TRX_END, IRQ_TRX_END | IRQ_RX_START,
162        10, 0);
163    if (!run)
164        return;
165
166    n = atrf_buf_read(dsc, buf, sizeof(buf));
167    if (n < 0)
168        exit(1);
169    if (n < 3) {
170        fprintf(stderr, "%d bytes received\n", n);
171        exit(1);
172    }
173    ed = atrf_reg_read(dsc, REG_PHY_ED_LEVEL);
174    ok = !!(atrf_reg_read(dsc, REG_PHY_RSSI) & RX_CRC_VALID);
175    lqi = buf[n-1];
176    fprintf(stderr, "%d bytes payload, CRC %s, LQI %u, ED %d dBm\n",
177        n-3, ok ? "OK" : "BAD", lqi, -91+ed);
178    for (i = 0; i != n-3; i++)
179        putchar(buf[i] < ' ' || buf[i] > '~' ? '?' : buf[i]);
180    putchar('\n');
181}
182
183
184static void write_pcap_hdr(FILE *file)
185{
186    struct pcap_file_header hdr = {
187        .magic = 0xa1b2c3d4,
188        .version_major = 2,
189        .version_minor = 4,
190        .thiszone = 0,
191        .sigfigs = 0,
192        .snaplen = MAX_PSDU,
193        .linktype = DLT_IEEE802_15_4
194    };
195
196    if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) {
197        perror("fwrite");
198        exit(1);
199    }
200}
201
202
203static void write_pcap_rec(FILE *file, const struct timeval *tv,
204    const void *buf, int n)
205{
206    struct pcap_pkthdr hdr = {
207        .ts_sec = tv->tv_sec,
208        .ts_usec = tv->tv_usec,
209        .caplen = n,
210        .len = n
211    };
212
213    if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) {
214        perror("fwrite");
215        exit(1);
216    }
217    if (fwrite(buf, n, 1, file) != 1) {
218        perror("fwrite");
219        exit(1);
220    }
221}
222
223
224static void receive_pcap(struct atrf_dsc *dsc, const char *name)
225{
226    FILE *file;
227    uint8_t buf[MAX_PSDU+1]; /* PSDU+LQI */
228    struct timeval now;
229    int n;
230    int count = 0;
231
232    file = fopen(name, "w");
233    if (!file) {
234        perror(name);
235        exit(1);
236    }
237    write_pcap_hdr(file);
238    while (run) {
239        wait_for_interrupt(dsc,
240            IRQ_TRX_END, IRQ_TRX_END | IRQ_RX_START,
241            10, 0);
242        if (!run)
243            break;
244        gettimeofday(&now, NULL);
245        n = atrf_buf_read(dsc, buf, sizeof(buf));
246        if (n < 0)
247            exit(1);
248        if (n < 2) {
249            fprintf(stderr, "%d bytes received\n", n);
250            continue;
251        }
252        write_pcap_rec(file, &now, buf, n-1);
253        (void) write(2, ".", 1);
254        count++;
255    }
256    if (fclose(file) == EOF) {
257        perror(name);
258        exit(1);
259    }
260    fprintf(stderr, "%sreceived %d message%s\n", count ? "\n" : "",
261        count, count == 1 ? "" : "s");
262}
263
264
265static void receive(struct atrf_dsc *dsc, const char *name)
266{
267    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_RX_ON);
268    /*
269     * 180 us, according to AVR2001 section 4.2. We time out after
270     * nominally 200 us.
271     */
272    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20);
273
274    if (name)
275        receive_pcap(dsc, name);
276    else
277        receive_message(dsc);
278}
279
280
281static void transmit(struct atrf_dsc *dsc, const char *msg, int times)
282{
283    uint8_t buf[MAX_PSDU];
284
285    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
286    /*
287     * 180 us, according to AVR2001 section 4.3. We time out after
288     * nominally 200 us.
289     */
290    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20);
291
292    /*
293     * We need to copy the message to append the CRC placeholders.
294     */
295    strcpy((void *) buf, msg);
296    atrf_buf_write(dsc, buf, strlen(msg)+2);
297
298    while (run && times--) {
299        /* @@@ should wait for clear channel */
300        atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START);
301
302        /* wait up to 10 ms (nominally) */
303        wait_for_interrupt(dsc, IRQ_TRX_END,
304           IRQ_TRX_END | IRQ_PLL_LOCK, 10, 1000);
305    }
306}
307
308
309static void enter_test_mode_230(struct atrf_dsc *dsc, uint8_t cont_tx)
310{
311    atrf_buf_write(dsc, "", 1);
312    atrf_reg_write(dsc, REG_CONT_TX_0, CONT_TX_MAGIC);
313    atrf_reg_write(dsc, REG_CONT_TX_1, cont_tx);
314
315    if (!atrf_test_mode(dsc)) {
316        atrf_reset_rf(dsc);
317        fprintf(stderr, "device does not support test mode\n");
318        exit(1);
319    }
320
321    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
322    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20);
323
324    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START);
325}
326
327
328static void enter_test_mode_231(struct atrf_dsc *dsc, uint8_t cont_tx)
329{
330    uint8_t buf[127];
331    uint8_t status;
332
333    switch (cont_tx) {
334    case CONT_TX_M2M:
335        fprintf(stderr,
336            "-2 MHz mode is not supported by the AT86RF231\n");
337        atrf_close(dsc);
338        exit(1);
339    case CONT_TX_M500K:
340        memset(buf, 0, sizeof(buf));
341        break;
342    case CONT_TX_P500K:
343        memset(buf, 0xff, sizeof(buf));
344        break;
345    default:
346        abort();
347    }
348
349    atrf_reg_write(dsc, REG_IRQ_MASK, IRQ_PLL_LOCK); /* 2 */
350    atrf_reg_write(dsc, REG_TRX_CTRL_1, 0); /* 3 */
351    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_FORCE_TRX_OFF); /* 4 */
352    /* deleted step 5 - we don't need to enable CLKM */
353
354    status = atrf_reg_read(dsc, REG_TRX_STATUS) & TRX_STATUS_MASK; /* 8 */
355    if (status != TRX_STATUS_TRX_OFF) {
356        fprintf(stderr, "expected status 0x%02x, got 0x%02x\n",
357            TRX_STATUS_TRX_OFF, status);
358        exit(1);
359    }
360
361    atrf_reg_write(dsc, REG_CONT_TX_0, CONT_TX_MAGIC); /* 9 */
362    atrf_reg_write(dsc, REG_TRX_CTRL_2, OQPSK_DATA_RATE_2000); /*10 */
363    atrf_reg_write(dsc, REG_RX_CTRL, 0xa7); /*11 */
364
365    atrf_buf_write(dsc, buf, sizeof(buf)); /*12 */
366
367    atrf_reg_write(dsc, REG_PART_NUM, 0x54); /*13 */
368    atrf_reg_write(dsc, REG_PART_NUM, 0x46); /*14 */
369    
370    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON); /*15 */
371    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 0); /*16 */
372
373    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START); /*17 */
374}
375
376
377static void transmit_pattern(struct atrf_dsc *dsc, double pause_s, int times)
378{
379    uint8_t buf[MAX_PSDU];
380    uint8_t n = 0;
381    int us = fmod(pause_s, 1)*1000000;
382
383    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
384    /*
385     * 180 us, according to AVR2001 section 4.3. We time out after
386     * nominally 200 us.
387     */
388    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20);
389
390    while (run) {
391        memset(buf, n, sizeof(buf));
392        atrf_buf_write(dsc, buf, sizeof(buf));
393
394        atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START);
395
396        /* wait up to 10 ms (nominally) */
397        wait_for_interrupt(dsc, IRQ_TRX_END,
398           IRQ_TRX_END | IRQ_PLL_LOCK, 10, 1000);
399
400        if (pause_s >= 1)
401            sleep(pause_s);
402        if (us)
403            usleep(us);
404
405        if (times && !--times)
406            break;
407        n++;
408    }
409}
410
411
412static int test_mode(struct atrf_dsc *dsc, uint8_t cont_tx, const char *cmd)
413{
414    int status = 0;
415
416    switch (atrf_identify(dsc)) {
417    case artf_at86rf230:
418        enter_test_mode_230(dsc, cont_tx);
419        break;
420    case artf_at86rf231:
421        enter_test_mode_231(dsc, cont_tx);
422        break;
423    default:
424        abort();
425    }
426
427    if (cmd)
428        status = system(cmd);
429    else {
430        while (run)
431            sleep(1);
432    }
433
434    if (atrf_identify(dsc) == artf_at86rf231)
435        atrf_reg_write(dsc, REG_PART_NUM, 0);
436    
437    atrf_reset_rf(dsc);
438
439    return status;
440}
441
442
443static void die(int sig)
444{
445    run = 0;
446}
447
448
449static void usage(const char *name)
450{
451    fprintf(stderr,
452"usage: %s [common_options] [message [repetitions]]\n"
453" %s [common_options] -B pause_s [repetitions]\n"
454" %s [common_options] -T offset [command]\n\n"
455" text message mode:\n"
456" message message string to send (if absent, receive)\n"
457" repetitions number of times the message is sent (default 1)\n\n"
458" BER test mode (transmit only):\n"
459" -B pause_s seconds to pause between frames (floating-point)\n"
460" repetitions number of messages to send (default: infinite)\n\n"
461" constant wave test mode (transmit only):\n"
462" -T offset test mode. offset is the frequency offset of the constant\n"
463" wave in MHz: -2, -0.5, or +0.5\n"
464" command shell command to run while transmitting (default: wait for\n"
465" SIGINT instead)\n\n"
466" common options: [-c channel|-f freq] [-C mhz] [-o file] [-p power] "
467"[-t trim]\n"
468" -c channel channel number, 11 to 26 (default %d)\n"
469" -C mhz output clock at 1, 2, 4, 8, or 16 MHz (default: off)\n"
470" -f freq frequency in MHz, 2405 to 2480 (default %d)\n"
471" -o file write received data to a file in pcap format\n"
472" -p power transmit power, -17.2 to 3.0 dBm (default %.1f)\n"
473" -t trim trim capacitor, 0 to 15 (default 0)\n"
474        , name, name, name, DEFAULT_CHANNEL, 2405+5*(DEFAULT_CHANNEL-11),
475        DEFAULT_POWER);
476    exit(1);
477}
478
479
480int main(int argc, char *const *argv)
481{
482    enum {
483        mode_msg,
484        mode_ber,
485        mode_cont_tx,
486    } mode = mode_msg;
487    int channel = DEFAULT_CHANNEL;
488    double power = DEFAULT_POWER;
489    int trim = 0, times = 1;
490    uint8_t cont_tx = 0;
491    double pause_s = 0;
492    char *end;
493    int c, freq;
494    unsigned tmp, clkm = 0;
495    int status = 0;
496    const char *pcap_file = NULL;
497    struct atrf_dsc *dsc;
498
499    while ((c = getopt(argc, argv, "B:c:C:f:o:p:t:T:")) != EOF)
500        switch (c) {
501        case 'c':
502            channel = strtoul(optarg, &end, 0);
503            if (*end)
504                usage(*argv);
505            if (channel < 11 || channel > 26)
506                usage(*argv);
507            break;
508        case 'f':
509            freq = strtoul(optarg, &end, 0);
510            if (*end)
511                usage(*argv);
512            if (freq % 5)
513                usage(*argv);
514            channel = (freq-2405)/5+11;
515            if (channel < 11 || channel > 26)
516                usage(*argv);
517            break;
518        case 'o':
519            pcap_file = optarg;
520            break;
521        case 'p':
522            power = strtod(optarg, &end);
523            if (*end)
524                usage(*argv);
525            break;
526        case 't':
527            trim = strtoul(optarg, &end, 0);
528            if (*end)
529                usage(*argv);
530            if (trim > 15)
531                usage(*argv);
532            break;
533        case 'B':
534            mode = mode_ber;
535            pause_s = strtof(optarg, &end);
536            if (*end)
537                usage(*argv);
538            break;
539        case 'C':
540            tmp = strtol(optarg, &end, 0);
541            if (*end)
542                usage(*argv);
543            if (!tmp)
544                usage(*argv);
545            for (clkm = 1; !(tmp & 1); tmp >>= 1)
546                clkm++;
547            if (tmp != 1 || clkm > 5)
548                usage(*argv);
549            break;
550        case 'T':
551            mode = mode_cont_tx;
552            if (!strcmp(optarg, "-2"))
553                cont_tx = CONT_TX_M2M;
554            else if (!strcmp(optarg, "-0.5"))
555                cont_tx = CONT_TX_M500K;
556            else if (!strcmp(optarg, "+0.5"))
557                cont_tx = CONT_TX_P500K;
558            else
559                usage(*argv);
560            break;
561        default:
562            usage(*argv);
563        }
564
565    signal(SIGINT, die);
566
567    switch (argc-optind) {
568    case 0:
569        dsc = init_txrx(trim, clkm);
570        set_channel(dsc, channel);
571        switch (mode) {
572        case mode_msg:
573            receive(dsc, pcap_file);
574            break;
575        case mode_ber:
576            set_power(dsc, power, 0);
577            transmit_pattern(dsc, pause_s, 0);
578            break;
579        case mode_cont_tx:
580            set_power(dsc, power, 0);
581            status = test_mode(dsc, cont_tx, NULL);
582            break;
583        default:
584            abort();
585        }
586        break;
587    case 2:
588        switch (mode) {
589        case mode_msg:
590            break;
591        case mode_ber:
592            /* fall through */
593        case mode_cont_tx:
594            usage(*argv);
595        default:
596            abort();
597        }
598        times = strtoul(argv[optind+1], &end, 0);
599        if (*end)
600            usage(*argv);
601        /* fall through */
602    case 1:
603        dsc = init_txrx(trim, clkm);
604        set_channel(dsc, channel);
605        switch (mode) {
606        case mode_msg:
607            set_power(dsc, power, 1);
608            transmit(dsc, argv[optind], times);
609            break;
610        case mode_ber:
611            times = strtoul(argv[optind+1], &end, 0);
612            if (*end)
613                usage(*argv);
614            set_power(dsc, power, 0);
615            transmit_pattern(dsc, pause_s, times);
616            break;
617        case mode_cont_tx:
618            set_power(dsc, power, 0);
619            status = test_mode(dsc, cont_tx, argv[optind]);
620            break;
621        default:
622            abort();
623        
624        }
625        break;
626    default:
627        usage(*argv);
628    }
629
630    atrf_close(dsc);
631
632    if (status) {
633        if (WIFEXITED(status))
634            return WEXITSTATUS(status);
635        if (WIFSIGNALED(status))
636            raise(WTERMSIG(status));
637        fprintf(stderr, "unexpected exit status %d\n", status);
638        abort();
639    }
640    return 0;
641}
642

Archive Download this file



interactive