altos: Clean up radio CRC handling
[fw/altos] / src / drivers / ao_cc1120.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_cc1120.h>
20 #include <ao_exti.h>
21 #include <ao_fec.h>
22 #include <ao_packet.h>
23
24 uint8_t ao_radio_wake;
25 uint8_t ao_radio_mutex;
26 uint8_t ao_radio_abort;
27 uint8_t ao_radio_in_recv;
28
29 #define CC1120_DEBUG    AO_FEC_DEBUG
30 #define CC1120_TRACE    0
31
32 const uint32_t  ao_radio_cal = 0x6ca333;
33
34 #define FOSC    32000000
35
36 #define ao_radio_select()       ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_1MHz)
37 #define ao_radio_deselect()     ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
38 #define ao_radio_spi_send(d,l)  ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
39 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
40 #define ao_radio_spi_recv(d,l)  ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
41 #define ao_radio_duplex(o,i,l)  ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS)
42
43 static uint8_t
44 ao_radio_reg_read(uint16_t addr)
45 {
46         uint8_t data[2];
47         uint8_t d;
48
49 #if CC1120_TRACE
50         printf("\t\tao_radio_reg_read (%04x): ", addr); flush();
51 #endif
52         if (CC1120_IS_EXTENDED(addr)) {
53                 data[0] = ((1 << CC1120_READ)  |
54                            (0 << CC1120_BURST) |
55                            CC1120_EXTENDED);
56                 data[1] = addr;
57                 d = 2;
58         } else {
59                 data[0] = ((1 << CC1120_READ)  |
60                            (0 << CC1120_BURST) |
61                            addr);
62                 d = 1;
63         }
64         ao_radio_select();
65         ao_radio_spi_send(data, d);
66         ao_radio_spi_recv(data, 1);
67         ao_radio_deselect();
68 #if CC1120_TRACE
69         printf (" %02x\n", data[0]);
70 #endif
71         return data[0];
72 }
73
74 static void
75 ao_radio_reg_write(uint16_t addr, uint8_t value)
76 {
77         uint8_t data[3];
78         uint8_t d;
79
80 #if CC1120_TRACE
81         printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value);
82 #endif
83         if (CC1120_IS_EXTENDED(addr)) {
84                 data[0] = ((0 << CC1120_READ)  |
85                            (0 << CC1120_BURST) |
86                            CC1120_EXTENDED);
87                 data[1] = addr;
88                 d = 2;
89         } else {
90                 data[0] = ((0 << CC1120_READ)  |
91                            (0 << CC1120_BURST) |
92                            addr);
93                 d = 1;
94         }
95         data[d] = value;
96         ao_radio_select();
97         ao_radio_spi_send(data, d+1);
98         ao_radio_deselect();
99 }
100
101 static void
102 ao_radio_burst_read_start (uint16_t addr)
103 {
104         uint8_t data[2];
105         uint8_t d;
106
107         if (CC1120_IS_EXTENDED(addr)) {
108                 data[0] = ((1 << CC1120_READ)  |
109                            (1 << CC1120_BURST) |
110                            CC1120_EXTENDED);
111                 data[1] = addr;
112                 d = 2;
113         } else {
114                 data[0] = ((1 << CC1120_READ)  |
115                            (1 << CC1120_BURST) |
116                            addr);
117                 d = 1;
118         }
119         ao_radio_select();
120         ao_radio_spi_send(data, d);
121 }
122
123 static void
124 ao_radio_burst_read_stop (void)
125 {
126         ao_radio_deselect();
127 }
128
129
130 static uint8_t
131 ao_radio_strobe(uint8_t addr)
132 {
133         uint8_t in;
134
135 #if CC1120_TRACE
136         printf("\t\tao_radio_strobe (%02x): ", addr); flush();
137 #endif
138         ao_radio_select();
139         ao_radio_duplex(&addr, &in, 1);
140         ao_radio_deselect();
141 #if CC1120_TRACE
142         printf("%02x\n", in); flush();
143 #endif
144         return in;
145 }
146
147 static uint8_t
148 ao_radio_fifo_read(uint8_t *data, uint8_t len)
149 {
150         uint8_t addr = ((1 << CC1120_READ)  |
151                         (1 << CC1120_BURST) |
152                         CC1120_FIFO);
153         uint8_t status;
154
155         ao_radio_select();
156         ao_radio_duplex(&addr, &status, 1);
157         ao_radio_spi_recv(data, len);
158         ao_radio_deselect();
159         return status;
160 }
161
162 static uint8_t
163 ao_radio_fifo_write(uint8_t *data, uint8_t len)
164 {
165         uint8_t addr = ((0 << CC1120_READ)  |
166                         (1 << CC1120_BURST) |
167                         CC1120_FIFO);
168         uint8_t status;
169
170         ao_radio_select();
171         ao_radio_duplex(&addr, &status, 1);
172         ao_radio_spi_send(data, len);
173         ao_radio_deselect();
174         return status;
175 }
176
177 static uint8_t
178 ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)
179 {
180         uint8_t addr = ((0 << CC1120_READ)  |
181                         (1 << CC1120_BURST) |
182                         CC1120_FIFO);
183         uint8_t status;
184
185         ao_radio_select();
186         ao_radio_duplex(&addr, &status, 1);
187         ao_radio_spi_send_fixed(data, len);
188         ao_radio_deselect();
189         return status;
190 }
191
192 static uint8_t
193 ao_radio_tx_fifo_space(void)
194 {
195         return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
196 }
197
198 static uint8_t
199 ao_radio_status(void)
200 {
201         return ao_radio_strobe (CC1120_SNOP);
202 }
203
204 void
205 ao_radio_recv_abort(void)
206 {
207         ao_radio_abort = 1;
208         ao_wakeup(&ao_radio_wake);
209 }
210
211 #define ao_radio_rdf_value 0x55
212
213 static uint8_t
214 ao_radio_marc_status(void)
215 {
216         return ao_radio_reg_read(CC1120_MARC_STATUS1);
217 }
218
219 static void
220 ao_radio_tx_isr(void)
221 {
222         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
223         ao_radio_wake = 1;
224         ao_wakeup(&ao_radio_wake);
225 }
226
227 static void
228 ao_radio_start_tx(void)
229 {
230         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr);
231         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
232         ao_radio_strobe(CC1120_STX);
233 }
234
235 static void
236 ao_radio_idle(void)
237 {
238         for (;;) {
239                 uint8_t state = ao_radio_strobe(CC1120_SIDLE);
240                 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
241                         break;
242         }
243 }
244
245 /*
246  * Packet deviation is 20.5kHz
247  *
248  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
249  *
250  *      32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
251  */
252
253 #define PACKET_DEV_E    5
254 #define PACKET_DEV_M    80
255
256 /*
257  * For our packet data, set the symbol rate to 38360 Baud
258  *
259  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
260  *      Rdata = -------------------------------------- * fosc
261  *                           2 ** 39
262  *
263  *
264  *      DATARATE_M = 239914
265  *      DATARATE_E = 9
266  */
267 #define PACKET_DRATE_E  9
268 #define PACKET_DRATE_M  239914
269
270 static const uint16_t packet_setup[] = {
271         CC1120_DEVIATION_M,     PACKET_DEV_M,
272         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
273                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
274                                  (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
275         CC1120_DRATE2,          ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
276                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
277         CC1120_DRATE1,          ((PACKET_DRATE_M >> 8) & 0xff),
278         CC1120_DRATE0,          ((PACKET_DRATE_M >> 0) & 0xff),
279         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
280                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
281         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
282                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
283                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
284                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
285         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
286                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
287                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
288                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
289                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
290 };
291
292 static const uint16_t packet_tx_setup[] = {
293         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
294                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
295         CC1120_IOCFG2,          CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
296 };
297
298 static const uint16_t packet_rx_setup[] = {
299         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
300                                  (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
301         CC1120_IOCFG2,          CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
302 };
303
304 /*
305  * RDF deviation is 5kHz
306  *
307  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
308  *
309  *      32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
310  */
311
312 #define RDF_DEV_E       3
313 #define RDF_DEV_M       71
314 #define RDF_PACKET_LEN  50
315
316 /*
317  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
318  *
319  *              (2**20 - DATARATE_M) * 2 ** DATARATE_E
320  *      Rdata = -------------------------------------- * fosc
321  *                           2 ** 39
322  *
323  *      DATARATE_M = 511705
324  *      DATARATE_E = 6
325  *
326  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
327  */
328 #define RDF_DRATE_E     5
329 #define RDF_DRATE_M     25166
330 #define RDF_PACKET_LEN  50
331
332 static const uint16_t rdf_setup[] = {
333         CC1120_DEVIATION_M,     RDF_DEV_M,
334         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
335                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
336                                  (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
337         CC1120_DRATE2,          ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
338                                  (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
339         CC1120_DRATE1,          ((RDF_DRATE_M >> 8) & 0xff),
340         CC1120_DRATE0,          ((RDF_DRATE_M >> 0) & 0xff),
341         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
342                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
343         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
344                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
345                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
346                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
347         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
348                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
349                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
350                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
351                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
352 };
353
354 static uint8_t ao_radio_mode;
355
356 #define AO_RADIO_MODE_BITS_PACKET       1
357 #define AO_RADIO_MODE_BITS_PACKET_TX    2
358 #define AO_RADIO_MODE_BITS_TX_BUF       4
359 #define AO_RADIO_MODE_BITS_TX_FINISH    8
360 #define AO_RADIO_MODE_BITS_PACKET_RX    16
361 #define AO_RADIO_MODE_BITS_RDF          32
362
363 #define AO_RADIO_MODE_NONE              0
364 #define AO_RADIO_MODE_PACKET_TX_BUF     (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
365 #define AO_RADIO_MODE_PACKET_TX_FINISH  (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
366 #define AO_RADIO_MODE_PACKET_RX         (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
367 #define AO_RADIO_MODE_RDF               (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
368
369 static void
370 ao_radio_set_mode(uint8_t new_mode)
371 {
372         uint8_t changes;
373         int i;
374
375         if (new_mode == ao_radio_mode)
376                 return;
377
378         changes = new_mode & (~ao_radio_mode);
379         if (changes & AO_RADIO_MODE_BITS_PACKET)
380                 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
381                         ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
382
383         if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
384                 for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2)
385                         ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
386                 
387         if (changes & AO_RADIO_MODE_BITS_TX_BUF)
388                 ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
389
390         if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
391                 ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
392
393         if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
394                 for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
395                         ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]);
396                 
397         if (changes & AO_RADIO_MODE_BITS_RDF)
398                 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
399                         ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
400         ao_radio_mode = new_mode;
401 }
402
403 static const uint16_t radio_setup[] = {
404 #include "ao_cc1120_CC1120.h"
405 };
406
407 static uint8_t  ao_radio_configured = 0;
408
409 static void
410 ao_radio_setup(void)
411 {
412         int     i;
413
414         ao_radio_strobe(CC1120_SRES);
415
416         for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
417                 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
418
419         ao_radio_mode = 0;
420
421         ao_config_get();
422
423         ao_radio_configured = 1;
424 }
425
426 static void
427 ao_radio_get(uint8_t len)
428 {
429         static uint32_t last_radio_setting;
430         static uint8_t  last_len;
431
432         ao_mutex_get(&ao_radio_mutex);
433         if (!ao_radio_configured)
434                 ao_radio_setup();
435         if (ao_config.radio_setting != last_radio_setting) {
436                 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
437                 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
438                 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
439                 last_radio_setting = ao_config.radio_setting;
440         }
441         if (len != last_len) {
442                 ao_radio_reg_write(CC1120_PKT_LEN, len);
443                 last_len = len;
444         }
445 }
446
447 #define ao_radio_put()  ao_mutex_put(&ao_radio_mutex)
448
449 void
450 ao_radio_rdf(uint8_t len)
451 {
452         int i;
453
454         ao_radio_abort = 0;
455         ao_radio_get(len);
456
457         ao_radio_set_mode(AO_RADIO_MODE_RDF);
458         ao_radio_wake = 0;
459
460         ao_radio_fifo_write_fixed(ao_radio_rdf_value, len);
461
462         ao_radio_start_tx();
463
464         cli();
465         while (!ao_radio_wake && !ao_radio_abort)
466                 ao_sleep(&ao_radio_wake);
467         sei();
468         if (!ao_radio_wake)
469                 ao_radio_idle();
470         ao_radio_put();
471 }
472
473 void
474 ao_radio_rdf_abort(void)
475 {
476         ao_radio_abort = 1;
477         ao_wakeup(&ao_radio_wake);
478 }
479
480 static void
481 ao_radio_test(void)
482 {
483         uint8_t mode = 2;
484         uint8_t radio_on;
485         ao_cmd_white();
486         if (ao_cmd_lex_c != '\n') {
487                 ao_cmd_decimal();
488                 mode = (uint8_t) ao_cmd_lex_u32;
489         }
490         mode++;
491         if ((mode & 2) && !radio_on) {
492 #if HAS_MONITOR
493                 ao_monitor_disable();
494 #endif
495 #if PACKET_HAS_SLAVE
496                 ao_packet_slave_stop();
497 #endif
498                 ao_radio_get(0xff);
499                 ao_radio_strobe(CC1120_STX);
500 #if CC1120_TRACE
501                 { int t; 
502                         for (t = 0; t < 10; t++) {
503                                 printf ("status: %02x\n", ao_radio_status());
504                                 ao_delay(AO_MS_TO_TICKS(100));
505                         }
506                 }
507 #endif
508                 radio_on = 1;
509         }
510         if (mode == 3) {
511                 printf ("Hit a character to stop..."); flush();
512                 getchar();
513                 putchar('\n');
514         }
515         if ((mode & 1) && radio_on) {
516                 ao_radio_idle();
517                 ao_radio_put();
518                 radio_on = 0;
519 #if HAS_MONITOR
520                 ao_monitor_enable();
521 #endif
522         }
523 }
524
525 void
526 ao_radio_send(const void *d, uint8_t size)
527 {
528         uint8_t         marc_status;
529         static uint8_t  encode[256];
530         uint8_t         *e = encode;
531         uint8_t         encode_len;
532         uint8_t         this_len;
533         uint8_t         started = 0;
534         uint8_t         fifo_space;
535
536         encode_len = ao_fec_encode(d, size, encode);
537
538         ao_radio_get(encode_len);
539
540         started = 0;
541         fifo_space = CC1120_FIFO_SIZE;
542         while (encode_len) {
543                 this_len = encode_len;
544
545                 if (this_len > fifo_space) {
546                         this_len = fifo_space;
547                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
548                 } else {
549                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
550                 }
551
552                 ao_radio_fifo_write(e, this_len);
553                 e += this_len;
554                 encode_len -= this_len;
555
556                 if (!started) {
557                         ao_radio_start_tx();
558                         started = 1;
559                 } else {
560                         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
561                 }
562                         
563                 do {
564                         ao_radio_wake = 0;
565                         cli();
566                         while (!ao_radio_wake)
567                                 ao_sleep(&ao_radio_wake);
568                         sei();
569                         if (!encode_len)
570                                 break;
571                         fifo_space = ao_radio_tx_fifo_space();
572                 } while (!fifo_space);
573         }
574         ao_radio_put();
575 }
576
577 #define AO_RADIO_MAX_RECV       90
578
579 static uint8_t  rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
580 static uint16_t rx_data_count;
581 static uint16_t rx_data_consumed;
582 static uint16_t rx_data_cur;
583 static uint8_t  rx_ignore;
584 static uint8_t  rx_waiting;
585
586 #if AO_PROFILE
587 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
588
589 uint32_t        ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
590
591 #include <ao_profile.h>
592 #endif
593
594 static void
595 ao_radio_rx_isr(void)
596 {
597         uint8_t d;
598
599         d = stm_spi2.dr;
600         stm_spi2.dr = 0;
601         if (rx_ignore == 0) {
602                 if (rx_data_cur >= rx_data_count)
603                         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
604                 else
605                         rx_data[rx_data_cur++] = d;
606                 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
607 #if AO_PROFILE
608                         if (rx_data_consumed == 0)
609                                 rx_packet_tick = ao_profile_tick();
610 #endif
611                         rx_waiting = 0;
612                         ao_wakeup(&ao_radio_wake);
613                 }
614         } else {
615                 --rx_ignore;
616         }
617 }
618
619 static uint16_t
620 ao_radio_rx_wait(void)
621 {
622         cli();
623         rx_waiting = 1;
624         while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
625                !ao_radio_abort) {
626                 ao_sleep(&ao_radio_wake);
627         }
628         rx_waiting = 0;
629         sei();
630         if (ao_radio_abort)
631                 return 0;
632         rx_data_consumed += AO_FEC_DECODE_BLOCK;
633         return AO_FEC_DECODE_BLOCK;
634 }
635
636 uint8_t
637 ao_radio_recv(__xdata void *d, uint8_t size)
638 {
639         uint8_t         len;
640         uint16_t        i;
641         uint8_t         rssi;
642         uint8_t         ret;
643         static int been_here = 0;
644
645         size -= 2;                      /* status bytes */
646         if (size > AO_RADIO_MAX_RECV) {
647                 ao_delay(AO_SEC_TO_TICKS(1));
648                 return 0;
649         }
650 #if AO_PROFILE
651         rx_start_tick = ao_profile_tick();
652 #endif
653         len = size + 2;                 /* CRC bytes */
654         len += 1 + ~(len & 1);          /* 1 or two pad bytes */
655         len *= 2;                       /* 1/2 rate convolution */
656         rx_data_count = len * 8;        /* bytes to bits */
657         rx_data_cur = 0;
658         rx_data_consumed = 0;
659         rx_ignore = 2;
660
661         ao_radio_abort = 0;
662         ao_radio_in_recv = 1;
663         /* configure interrupt pin */
664         ao_radio_get(len);
665         ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
666
667         ao_radio_wake = 0;
668
669         stm_spi2.cr2 = 0;
670
671         /* clear any RXNE */
672         (void) stm_spi2.dr;
673
674         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
675         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
676
677         ao_radio_strobe(CC1120_SRX);
678
679         ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
680
681         ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
682
683         ao_radio_burst_read_stop();
684
685         ao_radio_strobe(CC1120_SIDLE);
686
687         /* Convert from 'real' rssi to cc1111-style values */
688
689         rssi = (((int8_t) ao_radio_reg_read(CC1120_RSSI1)) + 74) * 2;
690
691         ao_radio_put();
692
693         /* Store the received RSSI value; the crc-OK byte is already done */
694
695         ((uint8_t *) d)[size] = (uint8_t) rssi;
696
697         ao_radio_in_recv = 0;
698
699         if (ao_radio_abort)
700                 ao_delay(1);
701
702 #if AO_PROFILE
703         rx_last_done_tick = rx_done_tick;
704         rx_done_tick = ao_profile_tick();
705
706         ao_rx_start_tick = rx_start_tick;
707         ao_rx_packet_tick = rx_packet_tick;
708         ao_rx_done_tick = rx_done_tick;
709         ao_rx_last_done_tick = rx_last_done_tick;
710 #endif
711
712         return ret;
713 }
714
715
716 #if CC1120_DEBUG
717 static char *cc1120_state_name[] = {
718         [CC1120_STATUS_STATE_IDLE] = "IDLE",
719         [CC1120_STATUS_STATE_RX] = "RX",
720         [CC1120_STATUS_STATE_TX] = "TX",
721         [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
722         [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
723         [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
724         [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
725         [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
726 };
727
728 struct ao_cc1120_reg {
729         uint16_t        addr;
730         char            *name;
731 };
732
733 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
734         { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
735         { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
736         { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
737         { .addr = CC1120_IOCFG0,        .name = "IOCFG0" },
738         { .addr = CC1120_SYNC3, .name = "SYNC3" },
739         { .addr = CC1120_SYNC2, .name = "SYNC2" },
740         { .addr = CC1120_SYNC1, .name = "SYNC1" },
741         { .addr = CC1120_SYNC0, .name = "SYNC0" },
742         { .addr = CC1120_SYNC_CFG1,     .name = "SYNC_CFG1" },
743         { .addr = CC1120_SYNC_CFG0,     .name = "SYNC_CFG0" },
744         { .addr = CC1120_DEVIATION_M,   .name = "DEVIATION_M" },
745         { .addr = CC1120_MODCFG_DEV_E,  .name = "MODCFG_DEV_E" },
746         { .addr = CC1120_DCFILT_CFG,    .name = "DCFILT_CFG" },
747         { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
748         { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
749         { .addr = CC1120_FREQ_IF_CFG,   .name = "FREQ_IF_CFG" },
750         { .addr = CC1120_IQIC,  .name = "IQIC" },
751         { .addr = CC1120_CHAN_BW,       .name = "CHAN_BW" },
752         { .addr = CC1120_MDMCFG1,       .name = "MDMCFG1" },
753         { .addr = CC1120_MDMCFG0,       .name = "MDMCFG0" },
754         { .addr = CC1120_DRATE2,        .name = "DRATE2" },
755         { .addr = CC1120_DRATE1,        .name = "DRATE1" },
756         { .addr = CC1120_DRATE0,        .name = "DRATE0" },
757         { .addr = CC1120_AGC_REF,       .name = "AGC_REF" },
758         { .addr = CC1120_AGC_CS_THR,    .name = "AGC_CS_THR" },
759         { .addr = CC1120_AGC_GAIN_ADJUST,       .name = "AGC_GAIN_ADJUST" },
760         { .addr = CC1120_AGC_CFG3,      .name = "AGC_CFG3" },
761         { .addr = CC1120_AGC_CFG2,      .name = "AGC_CFG2" },
762         { .addr = CC1120_AGC_CFG1,      .name = "AGC_CFG1" },
763         { .addr = CC1120_AGC_CFG0,      .name = "AGC_CFG0" },
764         { .addr = CC1120_FIFO_CFG,      .name = "FIFO_CFG" },
765         { .addr = CC1120_DEV_ADDR,      .name = "DEV_ADDR" },
766         { .addr = CC1120_SETTLING_CFG,  .name = "SETTLING_CFG" },
767         { .addr = CC1120_FS_CFG,        .name = "FS_CFG" },
768         { .addr = CC1120_WOR_CFG1,      .name = "WOR_CFG1" },
769         { .addr = CC1120_WOR_CFG0,      .name = "WOR_CFG0" },
770         { .addr = CC1120_WOR_EVENT0_MSB,        .name = "WOR_EVENT0_MSB" },
771         { .addr = CC1120_WOR_EVENT0_LSB,        .name = "WOR_EVENT0_LSB" },
772         { .addr = CC1120_PKT_CFG2,      .name = "PKT_CFG2" },
773         { .addr = CC1120_PKT_CFG1,      .name = "PKT_CFG1" },
774         { .addr = CC1120_PKT_CFG0,      .name = "PKT_CFG0" },
775         { .addr = CC1120_RFEND_CFG1,    .name = "RFEND_CFG1" },
776         { .addr = CC1120_RFEND_CFG0,    .name = "RFEND_CFG0" },
777         { .addr = CC1120_PA_CFG2,       .name = "PA_CFG2" },
778         { .addr = CC1120_PA_CFG1,       .name = "PA_CFG1" },
779         { .addr = CC1120_PA_CFG0,       .name = "PA_CFG0" },
780         { .addr = CC1120_PKT_LEN,       .name = "PKT_LEN" },
781         { .addr = CC1120_IF_MIX_CFG,    .name = "IF_MIX_CFG" },
782         { .addr = CC1120_FREQOFF_CFG,   .name = "FREQOFF_CFG" },
783         { .addr = CC1120_TOC_CFG,       .name = "TOC_CFG" },
784         { .addr = CC1120_MARC_SPARE,    .name = "MARC_SPARE" },
785         { .addr = CC1120_ECG_CFG,       .name = "ECG_CFG" },
786         { .addr = CC1120_SOFT_TX_DATA_CFG,      .name = "SOFT_TX_DATA_CFG" },
787         { .addr = CC1120_EXT_CTRL,      .name = "EXT_CTRL" },
788         { .addr = CC1120_RCCAL_FINE,    .name = "RCCAL_FINE" },
789         { .addr = CC1120_RCCAL_COARSE,  .name = "RCCAL_COARSE" },
790         { .addr = CC1120_RCCAL_OFFSET,  .name = "RCCAL_OFFSET" },
791         { .addr = CC1120_FREQOFF1,      .name = "FREQOFF1" },
792         { .addr = CC1120_FREQOFF0,      .name = "FREQOFF0" },
793         { .addr = CC1120_FREQ2, .name = "FREQ2" },
794         { .addr = CC1120_FREQ1, .name = "FREQ1" },
795         { .addr = CC1120_FREQ0, .name = "FREQ0" },
796         { .addr = CC1120_IF_ADC2,       .name = "IF_ADC2" },
797         { .addr = CC1120_IF_ADC1,       .name = "IF_ADC1" },
798         { .addr = CC1120_IF_ADC0,       .name = "IF_ADC0" },
799         { .addr = CC1120_FS_DIG1,       .name = "FS_DIG1" },
800         { .addr = CC1120_FS_DIG0,       .name = "FS_DIG0" },
801         { .addr = CC1120_FS_CAL3,       .name = "FS_CAL3" },
802         { .addr = CC1120_FS_CAL2,       .name = "FS_CAL2" },
803         { .addr = CC1120_FS_CAL1,       .name = "FS_CAL1" },
804         { .addr = CC1120_FS_CAL0,       .name = "FS_CAL0" },
805         { .addr = CC1120_FS_CHP,        .name = "FS_CHP" },
806         { .addr = CC1120_FS_DIVTWO,     .name = "FS_DIVTWO" },
807         { .addr = CC1120_FS_DSM1,       .name = "FS_DSM1" },
808         { .addr = CC1120_FS_DSM0,       .name = "FS_DSM0" },
809         { .addr = CC1120_FS_DVC1,       .name = "FS_DVC1" },
810         { .addr = CC1120_FS_DVC0,       .name = "FS_DVC0" },
811         { .addr = CC1120_FS_LBI,        .name = "FS_LBI" },
812         { .addr = CC1120_FS_PFD,        .name = "FS_PFD" },
813         { .addr = CC1120_FS_PRE,        .name = "FS_PRE" },
814         { .addr = CC1120_FS_REG_DIV_CML,        .name = "FS_REG_DIV_CML" },
815         { .addr = CC1120_FS_SPARE,      .name = "FS_SPARE" },
816         { .addr = CC1120_FS_VCO4,       .name = "FS_VCO4" },
817         { .addr = CC1120_FS_VCO3,       .name = "FS_VCO3" },
818         { .addr = CC1120_FS_VCO2,       .name = "FS_VCO2" },
819         { .addr = CC1120_FS_VCO1,       .name = "FS_VCO1" },
820         { .addr = CC1120_FS_VCO0,       .name = "FS_VCO0" },
821         { .addr = CC1120_GBIAS6,        .name = "GBIAS6" },
822         { .addr = CC1120_GBIAS5,        .name = "GBIAS5" },
823         { .addr = CC1120_GBIAS4,        .name = "GBIAS4" },
824         { .addr = CC1120_GBIAS3,        .name = "GBIAS3" },
825         { .addr = CC1120_GBIAS2,        .name = "GBIAS2" },
826         { .addr = CC1120_GBIAS1,        .name = "GBIAS1" },
827         { .addr = CC1120_GBIAS0,        .name = "GBIAS0" },
828         { .addr = CC1120_IFAMP, .name = "IFAMP" },
829         { .addr = CC1120_LNA,   .name = "LNA" },
830         { .addr = CC1120_RXMIX, .name = "RXMIX" },
831         { .addr = CC1120_XOSC5, .name = "XOSC5" },
832         { .addr = CC1120_XOSC4, .name = "XOSC4" },
833         { .addr = CC1120_XOSC3, .name = "XOSC3" },
834         { .addr = CC1120_XOSC2, .name = "XOSC2" },
835         { .addr = CC1120_XOSC1, .name = "XOSC1" },
836         { .addr = CC1120_XOSC0, .name = "XOSC0" },
837         { .addr = CC1120_ANALOG_SPARE,  .name = "ANALOG_SPARE" },
838         { .addr = CC1120_PA_CFG3,       .name = "PA_CFG3" },
839         { .addr = CC1120_WOR_TIME1,     .name = "WOR_TIME1" },
840         { .addr = CC1120_WOR_TIME0,     .name = "WOR_TIME0" },
841         { .addr = CC1120_WOR_CAPTURE1,  .name = "WOR_CAPTURE1" },
842         { .addr = CC1120_WOR_CAPTURE0,  .name = "WOR_CAPTURE0" },
843         { .addr = CC1120_BIST,  .name = "BIST" },
844         { .addr = CC1120_DCFILTOFFSET_I1,       .name = "DCFILTOFFSET_I1" },
845         { .addr = CC1120_DCFILTOFFSET_I0,       .name = "DCFILTOFFSET_I0" },
846         { .addr = CC1120_DCFILTOFFSET_Q1,       .name = "DCFILTOFFSET_Q1" },
847         { .addr = CC1120_DCFILTOFFSET_Q0,       .name = "DCFILTOFFSET_Q0" },
848         { .addr = CC1120_IQIE_I1,       .name = "IQIE_I1" },
849         { .addr = CC1120_IQIE_I0,       .name = "IQIE_I0" },
850         { .addr = CC1120_IQIE_Q1,       .name = "IQIE_Q1" },
851         { .addr = CC1120_IQIE_Q0,       .name = "IQIE_Q0" },
852         { .addr = CC1120_RSSI1, .name = "RSSI1" },
853         { .addr = CC1120_RSSI0, .name = "RSSI0" },
854         { .addr = CC1120_MARCSTATE,     .name = "MARCSTATE" },
855         { .addr = CC1120_LQI_VAL,       .name = "LQI_VAL" },
856         { .addr = CC1120_PQT_SYNC_ERR,  .name = "PQT_SYNC_ERR" },
857         { .addr = CC1120_DEM_STATUS,    .name = "DEM_STATUS" },
858         { .addr = CC1120_FREQOFF_EST1,  .name = "FREQOFF_EST1" },
859         { .addr = CC1120_FREQOFF_EST0,  .name = "FREQOFF_EST0" },
860         { .addr = CC1120_AGC_GAIN3,     .name = "AGC_GAIN3" },
861         { .addr = CC1120_AGC_GAIN2,     .name = "AGC_GAIN2" },
862         { .addr = CC1120_AGC_GAIN1,     .name = "AGC_GAIN1" },
863         { .addr = CC1120_AGC_GAIN0,     .name = "AGC_GAIN0" },
864         { .addr = CC1120_SOFT_RX_DATA_OUT,      .name = "SOFT_RX_DATA_OUT" },
865         { .addr = CC1120_SOFT_TX_DATA_IN,       .name = "SOFT_TX_DATA_IN" },
866         { .addr = CC1120_ASK_SOFT_RX_DATA,      .name = "ASK_SOFT_RX_DATA" },
867         { .addr = CC1120_RNDGEN,        .name = "RNDGEN" },
868         { .addr = CC1120_MAGN2, .name = "MAGN2" },
869         { .addr = CC1120_MAGN1, .name = "MAGN1" },
870         { .addr = CC1120_MAGN0, .name = "MAGN0" },
871         { .addr = CC1120_ANG1,  .name = "ANG1" },
872         { .addr = CC1120_ANG0,  .name = "ANG0" },
873         { .addr = CC1120_CHFILT_I2,     .name = "CHFILT_I2" },
874         { .addr = CC1120_CHFILT_I1,     .name = "CHFILT_I1" },
875         { .addr = CC1120_CHFILT_I0,     .name = "CHFILT_I0" },
876         { .addr = CC1120_CHFILT_Q2,     .name = "CHFILT_Q2" },
877         { .addr = CC1120_CHFILT_Q1,     .name = "CHFILT_Q1" },
878         { .addr = CC1120_CHFILT_Q0,     .name = "CHFILT_Q0" },
879         { .addr = CC1120_GPIO_STATUS,   .name = "GPIO_STATUS" },
880         { .addr = CC1120_FSCAL_CTRL,    .name = "FSCAL_CTRL" },
881         { .addr = CC1120_PHASE_ADJUST,  .name = "PHASE_ADJUST" },
882         { .addr = CC1120_PARTNUMBER,    .name = "PARTNUMBER" },
883         { .addr = CC1120_PARTVERSION,   .name = "PARTVERSION" },
884         { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
885         { .addr = CC1120_RX_STATUS,     .name = "RX_STATUS" },
886         { .addr = CC1120_TX_STATUS,     .name = "TX_STATUS" },
887         { .addr = CC1120_MARC_STATUS1,  .name = "MARC_STATUS1" },
888         { .addr = CC1120_MARC_STATUS0,  .name = "MARC_STATUS0" },
889         { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
890         { .addr = CC1120_FSRF_TEST,     .name = "FSRF_TEST" },
891         { .addr = CC1120_PRE_TEST,      .name = "PRE_TEST" },
892         { .addr = CC1120_PRE_OVR,       .name = "PRE_OVR" },
893         { .addr = CC1120_ADC_TEST,      .name = "ADC_TEST" },
894         { .addr = CC1120_DVC_TEST,      .name = "DVC_TEST" },
895         { .addr = CC1120_ATEST, .name = "ATEST" },
896         { .addr = CC1120_ATEST_LVDS,    .name = "ATEST_LVDS" },
897         { .addr = CC1120_ATEST_MODE,    .name = "ATEST_MODE" },
898         { .addr = CC1120_XOSC_TEST1,    .name = "XOSC_TEST1" },
899         { .addr = CC1120_XOSC_TEST0,    .name = "XOSC_TEST0" },
900         { .addr = CC1120_RXFIRST,       .name = "RXFIRST" },
901         { .addr = CC1120_TXFIRST,       .name = "TXFIRST" },
902         { .addr = CC1120_RXLAST,        .name = "RXLAST" },
903         { .addr = CC1120_TXLAST,        .name = "TXLAST" },
904         { .addr = CC1120_NUM_TXBYTES,   .name = "NUM_TXBYTES" },
905         { .addr = CC1120_NUM_RXBYTES,   .name = "NUM_RXBYTES" },
906         { .addr = CC1120_FIFO_NUM_TXBYTES,      .name = "FIFO_NUM_TXBYTES" },
907         { .addr = CC1120_FIFO_NUM_RXBYTES,      .name = "FIFO_NUM_RXBYTES" },
908 };
909
910 #define AO_NUM_CC1120_REG       (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
911
912 static void ao_radio_show(void) {
913         uint8_t status = ao_radio_status();
914         int     i;
915
916         ao_radio_get(0xff);
917         status = ao_radio_status();
918         printf ("Status:   %02x\n", status);
919         printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
920         printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
921         printf ("MARC:     %02x\n", ao_radio_marc_status());
922
923         for (i = 0; i < AO_NUM_CC1120_REG; i++)
924                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
925         ao_radio_put();
926 }
927
928 static void ao_radio_beep(void) {
929         ao_radio_rdf(RDF_PACKET_LEN);
930 }
931
932 static void ao_radio_packet(void) {
933         static const uint8_t packet[] = {
934 #if 1
935                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
936                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
937                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
938                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
939 #else
940                 3, 1, 2, 3
941 #endif
942         };
943
944         ao_radio_send(packet, sizeof (packet));
945 }
946
947 void
948 ao_radio_test_recv()
949 {
950         uint8_t bytes[34];
951         uint8_t b;
952
953         if (ao_radio_recv(bytes, 34)) {
954                 if (bytes[33] & 0x80)
955                         printf ("CRC OK");
956                 else
957                         printf ("CRC BAD");
958                 printf (" RSSI %d", (int16_t) ((int8_t) bytes[32] >> 1) - 74);
959                 for (b = 0; b < 32; b++)
960                         printf (" %02x", bytes[b]);
961                 printf ("\n");
962         }
963 }
964
965 #endif
966
967 static const struct ao_cmds ao_radio_cmds[] = {
968         { ao_radio_test,        "C <1 start, 0 stop, none both>\0Radio carrier test" },
969 #if CC1120_DEBUG
970         { ao_radio_show,        "R\0Show CC1120 status" },
971         { ao_radio_beep,        "b\0Emit an RDF beacon" },
972         { ao_radio_packet,      "p\0Send a test packet" },
973         { ao_radio_test_recv,   "q\0Recv a test packet" },
974 #endif
975         { 0, NULL }
976 };
977
978 void
979 ao_radio_init(void)
980 {
981         int     i;
982
983         ao_radio_configured = 0;
984         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
985
986         AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
987         for (i = 0; i < 10000; i++) {
988                 if ((SPI_2_GPIO->idr & (1 << SPI_2_MISO)) == 0)
989                         break;
990         }
991         AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
992         if (i == 10000)
993                 ao_panic(AO_PANIC_SELF_TEST);
994
995         /* Enable the EXTI interrupt for the appropriate pin */
996         ao_enable_port(AO_CC1120_INT_PORT);
997         ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
998                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
999                       ao_radio_tx_isr);
1000
1001         ao_cmd_register(&ao_radio_cmds[0]);
1002 }