IEEE 802.15.4 subsystem
Sign in or create your account | Project List | Help
IEEE 802.15.4 subsystem Git Source Tree
Root/
Source at commit b3c0b4bf62ba394e85a909d19b8ec71bd6a9b074 created 13 years 3 months ago. By Werner Almesberger, usrp: update filtering and display for uncorrupted measurement setup | |
---|---|
1 | /* |
2 | * atrf-txrx/atrf-txrx.c - ben-wpan AT86RF230 TX/RX |
3 | * |
4 | * Written 2010 by Werner Almesberger |
5 | * Copyright 2010 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 | |
44 | static double tx_pwr[] = { |
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 | |
52 | static volatile int run = 1; |
53 | |
54 | |
55 | static struct atrf_dsc *init_txrx(int trim) |
56 | { |
57 | struct atrf_dsc *dsc; |
58 | |
59 | dsc = atrf_open(); |
60 | if (!dsc) |
61 | exit(1); |
62 | |
63 | atrf_reset_rf(dsc); |
64 | atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TRX_OFF); |
65 | #ifdef HAVE_USB /* @@@ yeah, ugly */ |
66 | atrf_reg_write(dsc, REG_XOSC_CTRL, |
67 | (XTAL_MODE_INT << XTAL_MODE_SHIFT) | trim); |
68 | #else |
69 | atrf_reg_write(dsc, REG_XOSC_CTRL, XTAL_MODE_EXT << XTAL_MODE_SHIFT); |
70 | #endif |
71 | atrf_reg_write(dsc, REG_TRX_CTRL_0, 0); /* disable CLKM */ |
72 | |
73 | (void) atrf_reg_read(dsc, REG_IRQ_STATUS); |
74 | |
75 | return dsc; |
76 | } |
77 | |
78 | |
79 | static void set_channel(struct atrf_dsc *dsc, int channel) |
80 | { |
81 | atrf_reg_write(dsc, REG_PHY_CC_CCA, (1 << CCA_MODE_SHIFT) | channel); |
82 | } |
83 | |
84 | |
85 | static void set_power(struct atrf_dsc *dsc, double power, int crc) |
86 | { |
87 | int n; |
88 | |
89 | for (n = 0; n != sizeof(tx_pwr)/sizeof(*tx_pwr)-1; n++) |
90 | if (tx_pwr[n] <= power) |
91 | break; |
92 | if (fabs(tx_pwr[n]-power) > 0.01) |
93 | fprintf(stderr, "TX power %.1f dBm\n", tx_pwr[n]); |
94 | atrf_reg_write(dsc, REG_PHY_TX_PWR, (crc ? TX_AUTO_CRC_ON : 0) | n); |
95 | } |
96 | |
97 | |
98 | static void receive(struct atrf_dsc *dsc) |
99 | { |
100 | uint8_t buf[MAX_PSDU+1]; /* PSDU+LQI */ |
101 | int n, ok, i; |
102 | uint8_t ed, lqi; |
103 | |
104 | atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_RX_ON); |
105 | /* |
106 | * 180 us, according to AVR2001 section 4.2. We time out after |
107 | * nominally 200 us. |
108 | */ |
109 | wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20); |
110 | |
111 | fprintf(stderr, "Ready.\n"); |
112 | wait_for_interrupt(dsc, IRQ_TRX_END, IRQ_TRX_END | IRQ_RX_START, |
113 | 10, 0); |
114 | if (!run) |
115 | return; |
116 | |
117 | n = atrf_buf_read(dsc, buf, sizeof(buf)); |
118 | if (n < 0) |
119 | exit(1); |
120 | if (n < 3) { |
121 | fprintf(stderr, "%d bytes received\n", n); |
122 | exit(1); |
123 | } |
124 | ed = atrf_reg_read(dsc, REG_PHY_ED_LEVEL); |
125 | ok = !!(atrf_reg_read(dsc, REG_PHY_RSSI) & RX_CRC_VALID); |
126 | lqi = buf[n-1]; |
127 | fprintf(stderr, "%d bytes payload, CRC %s, LQI %u, ED %d dBm\n", |
128 | n-3, ok ? "OK" : "BAD", lqi, -91+ed); |
129 | for (i = 0; i != n-3; i++) |
130 | putchar(buf[i] < ' ' || buf[i] > '~' ? '?' : buf[i]); |
131 | putchar('\n'); |
132 | } |
133 | |
134 | |
135 | static void transmit(struct atrf_dsc *dsc, const char *msg, int times) |
136 | { |
137 | uint8_t buf[MAX_PSDU]; |
138 | |
139 | atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON); |
140 | /* |
141 | * 180 us, according to AVR2001 section 4.3. We time out after |
142 | * nominally 200 us. |
143 | */ |
144 | wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20); |
145 | |
146 | /* |
147 | * We need to copy the message to append the CRC placeholders. |
148 | */ |
149 | strcpy((void *) buf, msg); |
150 | atrf_buf_write(dsc, buf, strlen(msg)+2); |
151 | |
152 | while (run && times--) { |
153 | /* @@@ should wait for clear channel */ |
154 | atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START); |
155 | |
156 | /* wait up to 10 ms (nominally) */ |
157 | wait_for_interrupt(dsc, IRQ_TRX_END, |
158 | IRQ_TRX_END | IRQ_PLL_LOCK, 10, 1000); |
159 | } |
160 | } |
161 | |
162 | |
163 | static int test_mode(struct atrf_dsc *dsc, uint8_t cont_tx, const char *cmd) |
164 | { |
165 | atrf_buf_write(dsc, "", 1); |
166 | atrf_reg_write(dsc, REG_CONT_TX_0, CONT_TX_MAGIC); |
167 | atrf_reg_write(dsc, REG_CONT_TX_1, cont_tx); |
168 | int status = 0; |
169 | |
170 | if (!atrf_test_mode(dsc)) { |
171 | atrf_reset_rf(dsc); |
172 | fprintf(stderr, "device does not support test mode\n"); |
173 | exit(1); |
174 | } |
175 | |
176 | atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON); |
177 | wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 10, 20); |
178 | |
179 | atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TX_START); |
180 | |
181 | if (cmd) |
182 | status = system(cmd); |
183 | else { |
184 | while (run) |
185 | sleep(1); |
186 | } |
187 | |
188 | atrf_reset_rf(dsc); |
189 | |
190 | return status; |
191 | } |
192 | |
193 | |
194 | static void die(int sig) |
195 | { |
196 | run = 0; |
197 | } |
198 | |
199 | |
200 | static void usage(const char *name) |
201 | { |
202 | fprintf(stderr, |
203 | "usage: %s [-c channel|-f freq] [-p power] [-t trim] [message [repetitions]]\n" |
204 | " %s [-c channel|-f freq] [-p power] [-t trim] -T offset [command]\n\n" |
205 | " message message string to send (if absent, receive)\n" |
206 | " repetitions number of times the message is sent (default 1)\n" |
207 | " command shell command to run while transmitting (default: wait for\n" |
208 | " SIGINT instead)\n\n" |
209 | " -c channel channel number, 11 to 26 (default %d)\n" |
210 | " -f freq frequency in MHz, 2405 to 2480 (default %d)\n" |
211 | " -p power transmit power, -17.2 to 3.0 dBm (default %.1f)\n" |
212 | " -t trim trim capacitor, 0 to 15 (default 0)\n" |
213 | " -t trim trim capacitor, 0 to 15 (default 0)\n" |
214 | " -T offset test mode. offset is the frequency offset of the constant\n" |
215 | " wave in MHz: -2, -0.5, or +0.5\n" |
216 | , name, name, DEFAULT_CHANNEL, 2405+5*(DEFAULT_CHANNEL-11), |
217 | DEFAULT_POWER); |
218 | exit(1); |
219 | } |
220 | |
221 | |
222 | int main(int argc, char *const *argv) |
223 | { |
224 | int channel = DEFAULT_CHANNEL; |
225 | double power = DEFAULT_POWER; |
226 | int trim = 0, times = 1; |
227 | uint8_t cont_tx = 0; |
228 | char *end; |
229 | int c, freq; |
230 | int status = 0; |
231 | struct atrf_dsc *dsc; |
232 | |
233 | while ((c = getopt(argc, argv, "c:f:p:t:T:")) != EOF) |
234 | switch (c) { |
235 | case 'c': |
236 | channel = strtoul(optarg, &end, 0); |
237 | if (*end) |
238 | usage(*argv); |
239 | if (channel < 11 || channel > 26) |
240 | usage(*argv); |
241 | break; |
242 | case 'f': |
243 | freq = strtoul(optarg, &end, 0); |
244 | if (*end) |
245 | usage(*argv); |
246 | if (freq % 5) |
247 | usage(*argv); |
248 | channel = (freq-2405)/5+11; |
249 | if (channel < 11 || channel > 26) |
250 | usage(*argv); |
251 | break; |
252 | case 'p': |
253 | power = strtod(optarg, &end); |
254 | if (*end) |
255 | usage(*argv); |
256 | break; |
257 | case 't': |
258 | trim = strtoul(optarg, &end, 0); |
259 | if (*end) |
260 | usage(*argv); |
261 | if (trim > 15) |
262 | usage(*argv); |
263 | break; |
264 | case 'T': |
265 | if (!strcmp(optarg, "-2")) |
266 | cont_tx = CONT_TX_M2M; |
267 | else if (!strcmp(optarg, "-0.5")) |
268 | cont_tx = CONT_TX_M500K; |
269 | else if (!strcmp(optarg, "+0.5")) |
270 | cont_tx = CONT_TX_P500K; |
271 | else |
272 | usage(*argv); |
273 | break; |
274 | default: |
275 | usage(*argv); |
276 | } |
277 | |
278 | signal(SIGINT, die); |
279 | |
280 | switch (argc-optind) { |
281 | case 0: |
282 | dsc = init_txrx(trim); |
283 | set_channel(dsc, channel); |
284 | if (!cont_tx) |
285 | receive(dsc); |
286 | else { |
287 | set_power(dsc, power, 0); |
288 | status = test_mode(dsc, cont_tx, NULL); |
289 | } |
290 | break; |
291 | case 2: |
292 | if (cont_tx) |
293 | usage(*argv); |
294 | times = strtoul(argv[optind+1], &end, 0); |
295 | if (*end) |
296 | usage(*argv); |
297 | /* fall through */ |
298 | case 1: |
299 | dsc = init_txrx(trim); |
300 | set_channel(dsc, channel); |
301 | if (!cont_tx) { |
302 | set_power(dsc, power, 1); |
303 | transmit(dsc, argv[optind], times); |
304 | } else { |
305 | set_power(dsc, power, 0); |
306 | status = test_mode(dsc, cont_tx, argv[optind]); |
307 | } |
308 | break; |
309 | default: |
310 | usage(*argv); |
311 | } |
312 | |
313 | atrf_close(dsc); |
314 | |
315 | if (status) { |
316 | if (WIFEXITED(status)) |
317 | return WEXITSTATUS(status); |
318 | if (WIFSIGNALED(status)) |
319 | raise(WTERMSIG(status)); |
320 | fprintf(stderr, "unexpected exit status %d\n", status); |
321 | abort(); |
322 | } |
323 | return 0; |
324 | } |
325 |