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

Source at commit ebe667197a3c09a1f9b3005efcf7729c8b12da84 created 8 years 9 months ago.
By Werner Almesberger, dirtly made the atrf tools run with the new atusd board
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
23#include "at86rf230.h"
24#include "atrf.h"
25#include "misctxrx.h"
26
27
28/*
29 * According to IEEE 802.15.4-2003 section E.2.6, channel 15 is the only
30 * channel that falls into the 802.11 guard bands in North America an Europe.
31 */
32
33#define DEFAULT_CHANNEL 15 /* channel 15, 2425 MHz */
34
35/*
36 * Transmit power, dBm. IEEE 802.15.4-2003 section E.3.1.3 specifies a transmit
37 * power of 0 dBm for IEEE 802.15.4. We assume an antenna gain of 3 dB or
38 * better.
39 */
40
41#define DEFAULT_POWER -3.2 /* transmit power, dBm */
42
43
44static double tx_pwr_230[] = {
45     3.0, 2.6, 2.1, 1.6,
46     1.1, 0.5, -0.2, -1.2,
47    -2.2, -3.2, -4.2, -5.2,
48    -7.2, -9.2, -12.2, -17.2
49};
50
51
52static double tx_pwr_231[] = {
53     3.0, 2.8, 2.3, 1.8,
54     1.3, 0.7, 0.0, -1,
55    -2, -3, -4, -5,
56    -7, -9, -12, -17
57};
58
59
60static volatile int run = 1;
61
62
63/*
64 * clkm: 0 disable CLKM
65 * >0 output 2^(clkm-1) MHz signal
66 */
67
68static struct atrf_dsc *init_txrx(int trim, unsigned clkm)
69{
70    struct atrf_dsc *dsc;
71
72    dsc = atrf_open();
73    if (!dsc)
74        exit(1);
75    
76    atrf_reset_rf(dsc);
77    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TRX_OFF);
78
79#if 1 // def HAVE_USB /* @@@ yeah, ugly */
80    atrf_reg_write(dsc, REG_XOSC_CTRL,
81        (XTAL_MODE_INT << XTAL_MODE_SHIFT) | trim);
82#else
83    atrf_reg_write(dsc, REG_XOSC_CTRL, XTAL_MODE_EXT << XTAL_MODE_SHIFT);
84#endif
85
86    if (!clkm)
87        atrf_reg_write(dsc, REG_TRX_CTRL_0, 0); /* disable CLKM */
88    else
89        atrf_reg_write(dsc, REG_TRX_CTRL_0,
90            (PAD_IO_8mA << PAD_IO_CLKM_SHIFT) | clkm);
91
92    /* We want to see all interrupts, not only the ones we're expecting. */
93    atrf_reg_write(dsc, REG_IRQ_MASK, 0xff);
94
95    (void) atrf_reg_read(dsc, REG_IRQ_STATUS);
96    if (atrf_identify(dsc) == artf_at86rf231)
97        wait_for_interrupt(dsc, IRQ_CCA_ED_DONE, IRQ_CCA_ED_DONE,
98            10, 50); /* according to table 7-1, 37 us max */
99
100    return dsc;
101}
102
103
104static void set_channel(struct atrf_dsc *dsc, int channel)
105{
106    atrf_reg_write(dsc, REG_PHY_CC_CCA, (1 << CCA_MODE_SHIFT) | channel);
107}
108
109
110static void set_power(struct atrf_dsc *dsc, double power, int crc)
111{
112    const double *tx_pwr;
113    int n;
114    uint8_t tmp;
115
116    switch (atrf_identify(dsc)) {
117    case artf_at86rf230:
118        tx_pwr = tx_pwr_230;
119        break;
120    case artf_at86rf231:
121        tx_pwr = tx_pwr_231;
122        break;
123    default:
124        abort();
125    }
126    
127    for (n = 0; n != sizeof(tx_pwr_230)/sizeof(*tx_pwr_230)-1; n++)
128        if (tx_pwr[n] <= power)
129            break;
130    if (fabs(tx_pwr[n]-power) > 0.01)
131        fprintf(stderr, "TX power %.1f dBm\n", tx_pwr[n]);
132
133    switch (atrf_identify(dsc)) {
134    case artf_at86rf230:
135        atrf_reg_write(dsc, REG_PHY_TX_PWR,
136            (crc ? TX_AUTO_CRC_ON_230 : 0) | n);
137        break;
138    case artf_at86rf231:
139        tmp = atrf_reg_read(dsc, REG_PHY_TX_PWR);
140        tmp = (tmp & ~TX_PWR_MASK) | n;
141        atrf_reg_write(dsc, REG_PHY_TX_PWR, tmp);
142        atrf_reg_write(dsc, REG_TRX_CTRL_1,
143            crc ? TX_AUTO_CRC_ON : 0);
144        break;
145    default:
146        abort();
147    }
148}
149
150
151static void receive(struct atrf_dsc *dsc)
152{
153    uint8_t buf[MAX_PSDU+1]; /* PSDU+LQI */
154    int n, ok, i;
155    uint8_t ed, lqi;
156
157    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_RX_ON);
158    /*
159     * 180 us, according to AVR2001 section 4.2. We time out after
160     * nominally 200 us.
161     */
162    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20);
163
164    fprintf(stderr, "Ready.\n");
165    wait_for_interrupt(dsc, IRQ_TRX_END, IRQ_TRX_END | IRQ_RX_START,
166        10, 0);
167    if (!run)
168        return;
169
170    n = atrf_buf_read(dsc, buf, sizeof(buf));
171    if (n < 0)
172        exit(1);
173    if (n < 3) {
174        fprintf(stderr, "%d bytes received\n", n);
175        exit(1);
176    }
177    ed = atrf_reg_read(dsc, REG_PHY_ED_LEVEL);
178    ok = !!(atrf_reg_read(dsc, REG_PHY_RSSI) & RX_CRC_VALID);
179    lqi = buf[n-1];
180    fprintf(stderr, "%d bytes payload, CRC %s, LQI %u, ED %d dBm\n",
181        n-3, ok ? "OK" : "BAD", lqi, -91+ed);
182    for (i = 0; i != n-3; i++)
183        putchar(buf[i] < ' ' || buf[i] > '~' ? '?' : buf[i]);
184    putchar('\n');
185}
186
187
188static void transmit(struct atrf_dsc *dsc, const char *msg, int times)
189{
190    uint8_t buf[MAX_PSDU];
191
192    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
193    /*
194     * 180 us, according to AVR2001 section 4.3. We time out after
195     * nominally 200 us.
196     */
197    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20);
198
199    /*
200     * We need to copy the message to append the CRC placeholders.
201     */
202    strcpy((void *) buf, msg);
203    atrf_buf_write(dsc, buf, strlen(msg)+2);
204
205    while (run && times--) {
206        /* @@@ should wait for clear channel */
207        atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START);
208
209        /* wait up to 10 ms (nominally) */
210        wait_for_interrupt(dsc, IRQ_TRX_END,
211           IRQ_TRX_END | IRQ_PLL_LOCK, 10, 1000);
212    }
213}
214
215
216static void enter_test_mode_230(struct atrf_dsc *dsc, uint8_t cont_tx)
217{
218    atrf_buf_write(dsc, "", 1);
219    atrf_reg_write(dsc, REG_CONT_TX_0, CONT_TX_MAGIC);
220    atrf_reg_write(dsc, REG_CONT_TX_1, cont_tx);
221
222    if (!atrf_test_mode(dsc)) {
223        atrf_reset_rf(dsc);
224        fprintf(stderr, "device does not support test mode\n");
225        exit(1);
226    }
227
228    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
229    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20);
230
231    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START);
232}
233
234
235static void enter_test_mode_231(struct atrf_dsc *dsc, uint8_t cont_tx)
236{
237    uint8_t buf[127];
238    uint8_t status;
239
240    switch (cont_tx) {
241    case CONT_TX_M2M:
242        fprintf(stderr,
243            "-2 MHz mode is not supported by the AT86RF231\n");
244        atrf_close(dsc);
245        exit(1);
246    case CONT_TX_M500K:
247        memset(buf, 0, sizeof(buf));
248        break;
249    case CONT_TX_P500K:
250        memset(buf, 0xff, sizeof(buf));
251        break;
252    default:
253        abort();
254    }
255
256    atrf_reg_write(dsc, REG_IRQ_MASK, IRQ_PLL_LOCK); /* 2 */
257    atrf_reg_write(dsc, REG_TRX_CTRL_1, 0); /* 3 */
258    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_FORCE_TRX_OFF); /* 4 */
259    /* deleted step 5 - we don't need to enable CLKM */
260
261    status = atrf_reg_read(dsc, REG_TRX_STATUS) & TRX_STATUS_MASK; /* 8 */
262    if (status != TRX_STATUS_TRX_OFF) {
263        fprintf(stderr, "expected status 0x%02x, got 0x%02x\n",
264            TRX_STATUS_TRX_OFF, status);
265        exit(1);
266    }
267
268    atrf_reg_write(dsc, REG_CONT_TX_0, CONT_TX_MAGIC); /* 9 */
269    atrf_reg_write(dsc, REG_TRX_CTRL_2, OQPSK_DATA_RATE_2000); /*10 */
270    atrf_reg_write(dsc, REG_RX_CTRL, 0xa7); /*11 */
271
272    atrf_buf_write(dsc, buf, sizeof(buf)); /*12 */
273
274    atrf_reg_write(dsc, REG_PART_NUM, 0x54); /*13 */
275    atrf_reg_write(dsc, REG_PART_NUM, 0x46); /*14 */
276    
277    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON); /*15 */
278    wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 0); /*16 */
279
280    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START); /*17 */
281}
282
283
284
285static int test_mode(struct atrf_dsc *dsc, uint8_t cont_tx, const char *cmd)
286{
287    int status = 0;
288
289    switch (atrf_identify(dsc)) {
290    case artf_at86rf230:
291        enter_test_mode_230(dsc, cont_tx);
292        break;
293    case artf_at86rf231:
294        enter_test_mode_231(dsc, cont_tx);
295        break;
296    default:
297        abort();
298    }
299
300    if (cmd)
301        status = system(cmd);
302    else {
303        while (run)
304            sleep(1);
305    }
306
307    if (atrf_identify(dsc) == artf_at86rf231)
308        atrf_reg_write(dsc, REG_PART_NUM, 0);
309    
310    atrf_reset_rf(dsc);
311
312    return status;
313}
314
315
316static void die(int sig)
317{
318    run = 0;
319}
320
321
322static void usage(const char *name)
323{
324    fprintf(stderr,
325"usage: %s [-c channel|-f freq] [-p power] [-t trim] [message [repetitions]]\n"
326" %s [-c channel|-f freq] [-p power] [-t trim] -T offset [command]\n\n"
327" message message string to send (if absent, receive)\n"
328" repetitions number of times the message is sent (default 1)\n"
329" command shell command to run while transmitting (default: wait for\n"
330" SIGINT instead)\n\n"
331" -c channel channel number, 11 to 26 (default %d)\n"
332" -C mhz output clock at 1, 2, 4, 8, or 16 MHz (default: off)\n"
333" -f freq frequency in MHz, 2405 to 2480 (default %d)\n"
334" -p power transmit power, -17.2 to 3.0 dBm (default %.1f)\n"
335" -t trim trim capacitor, 0 to 15 (default 0)\n"
336" -t trim trim capacitor, 0 to 15 (default 0)\n"
337" -T offset test mode. offset is the frequency offset of the constant\n"
338" wave in MHz: -2, -0.5, or +0.5\n"
339        , name, name, DEFAULT_CHANNEL, 2405+5*(DEFAULT_CHANNEL-11),
340        DEFAULT_POWER);
341    exit(1);
342}
343
344
345int main(int argc, char *const *argv)
346{
347    int channel = DEFAULT_CHANNEL;
348    double power = DEFAULT_POWER;
349    int trim = 0, times = 1;
350    uint8_t cont_tx = 0;
351    char *end;
352    int c, freq;
353    unsigned tmp, clkm = 0;
354    int status = 0;
355    struct atrf_dsc *dsc;
356
357    while ((c = getopt(argc, argv, "c:C:f:p:t:T:")) != EOF)
358        switch (c) {
359        case 'c':
360            channel = strtoul(optarg, &end, 0);
361            if (*end)
362                usage(*argv);
363            if (channel < 11 || channel > 26)
364                usage(*argv);
365            break;
366        case 'f':
367            freq = strtoul(optarg, &end, 0);
368            if (*end)
369                usage(*argv);
370            if (freq % 5)
371                usage(*argv);
372            channel = (freq-2405)/5+11;
373            if (channel < 11 || channel > 26)
374                usage(*argv);
375            break;
376        case 'p':
377            power = strtod(optarg, &end);
378            if (*end)
379                usage(*argv);
380            break;
381        case 't':
382            trim = strtoul(optarg, &end, 0);
383            if (*end)
384                usage(*argv);
385            if (trim > 15)
386                usage(*argv);
387            break;
388        case 'C':
389            tmp = strtol(optarg, &end, 0);
390            if (*end)
391                usage(*argv);
392            if (!tmp)
393                usage(*argv);
394            for (clkm = 1; !(tmp & 1); tmp >>= 1)
395                clkm++;
396            if (tmp != 1 || clkm > 5)
397                usage(*argv);
398            break;
399        case 'T':
400            if (!strcmp(optarg, "-2"))
401                cont_tx = CONT_TX_M2M;
402            else if (!strcmp(optarg, "-0.5"))
403                cont_tx = CONT_TX_M500K;
404            else if (!strcmp(optarg, "+0.5"))
405                cont_tx = CONT_TX_P500K;
406            else
407                usage(*argv);
408            break;
409        default:
410            usage(*argv);
411        }
412
413    signal(SIGINT, die);
414
415    switch (argc-optind) {
416    case 0:
417        dsc = init_txrx(trim, clkm);
418        set_channel(dsc, channel);
419        if (!cont_tx)
420            receive(dsc);
421        else {
422            set_power(dsc, power, 0);
423            status = test_mode(dsc, cont_tx, NULL);
424        }
425        break;
426    case 2:
427        if (cont_tx)
428            usage(*argv);
429        times = strtoul(argv[optind+1], &end, 0);
430        if (*end)
431            usage(*argv);
432        /* fall through */
433    case 1:
434        dsc = init_txrx(trim, clkm);
435        set_channel(dsc, channel);
436        if (!cont_tx) {
437            set_power(dsc, power, 1);
438            transmit(dsc, argv[optind], times);
439        } else {
440            set_power(dsc, power, 0);
441            status = test_mode(dsc, cont_tx, argv[optind]);
442        }
443        break;
444    default:
445        usage(*argv);
446    }
447
448    atrf_close(dsc);
449
450    if (status) {
451        if (WIFEXITED(status))
452            return WEXITSTATUS(status);
453        if (WIFSIGNALED(status))
454            raise(WTERMSIG(status));
455        fprintf(stderr, "unexpected exit status %d\n", status);
456        abort();
457    }
458    return 0;
459}
460

Archive Download this file



interactive