2 * Copyright © 2012 Keith Packard <keithp@keithp.com>
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.
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.
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.
19 #include <ao_cc1120.h>
22 #include <ao_packet.h>
24 #define AO_RADIO_MAX_RECV sizeof(struct ao_packet)
25 #define AO_RADIO_MAX_SEND sizeof(struct ao_packet)
27 uint8_t ao_radio_wake;
28 uint8_t ao_radio_mutex;
29 uint8_t ao_radio_abort;
30 uint8_t ao_radio_in_recv;
32 #define CC1120_DEBUG AO_FEC_DEBUG
33 #define CC1120_TRACE 0
35 extern const uint32_t ao_radio_cal;
39 #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)
40 #define ao_radio_deselect() ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
41 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
42 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
43 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
44 #define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS)
47 ao_radio_reg_read(uint16_t addr)
53 printf("\t\tao_radio_reg_read (%04x): ", addr); flush();
55 if (CC1120_IS_EXTENDED(addr)) {
56 data[0] = ((1 << CC1120_READ) |
62 data[0] = ((1 << CC1120_READ) |
68 ao_radio_spi_send(data, d);
69 ao_radio_spi_recv(data, 1);
72 printf (" %02x\n", data[0]);
78 ao_radio_reg_write(uint16_t addr, uint8_t value)
84 printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value);
86 if (CC1120_IS_EXTENDED(addr)) {
87 data[0] = ((0 << CC1120_READ) |
93 data[0] = ((0 << CC1120_READ) |
100 ao_radio_spi_send(data, d+1);
105 ao_radio_burst_read_start (uint16_t addr)
110 if (CC1120_IS_EXTENDED(addr)) {
111 data[0] = ((1 << CC1120_READ) |
112 (1 << CC1120_BURST) |
117 data[0] = ((1 << CC1120_READ) |
118 (1 << CC1120_BURST) |
123 ao_radio_spi_send(data, d);
127 ao_radio_burst_read_stop (void)
134 ao_radio_strobe(uint8_t addr)
139 printf("\t\tao_radio_strobe (%02x): ", addr); flush();
142 ao_radio_duplex(&addr, &in, 1);
145 printf("%02x\n", in); flush();
151 ao_radio_fifo_read(uint8_t *data, uint8_t len)
153 uint8_t addr = ((1 << CC1120_READ) |
154 (1 << CC1120_BURST) |
159 ao_radio_duplex(&addr, &status, 1);
160 ao_radio_spi_recv(data, len);
166 ao_radio_fifo_write_start(void)
168 uint8_t addr = ((0 << CC1120_READ) |
169 (1 << CC1120_BURST) |
174 ao_radio_duplex(&addr, &status, 1);
178 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
184 ao_radio_fifo_write(uint8_t *data, uint8_t len)
186 uint8_t status = ao_radio_fifo_write_start();
187 ao_radio_spi_send(data, len);
188 return ao_radio_fifo_write_stop(status);
192 ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)
194 uint8_t status = ao_radio_fifo_write_start();
195 ao_radio_spi_send_fixed(data, len);
196 return ao_radio_fifo_write_stop(status);
200 ao_radio_tx_fifo_space(void)
202 return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
206 ao_radio_status(void)
208 return ao_radio_strobe (CC1120_SNOP);
212 ao_radio_recv_abort(void)
215 ao_wakeup(&ao_radio_wake);
218 #define ao_radio_rdf_value 0x55
221 ao_radio_marc_status(void)
223 return ao_radio_reg_read(CC1120_MARC_STATUS1);
227 ao_radio_tx_isr(void)
229 ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
231 ao_wakeup(&ao_radio_wake);
235 ao_radio_start_tx(void)
237 ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr);
238 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
239 ao_radio_strobe(CC1120_STX);
246 uint8_t state = ao_radio_strobe(CC1120_SIDLE);
247 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
253 * Packet deviation is 20.5kHz
255 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
257 * 32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
260 #define PACKET_DEV_E 5
261 #define PACKET_DEV_M 80
264 * For our packet data, set the symbol rate to 38400 Baud
266 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
267 * Rdata = -------------------------------------- * fosc
271 * DATARATE_M = 239914
274 #define PACKET_DRATE_E 9
275 #define PACKET_DRATE_M 239914
277 static const uint16_t packet_setup[] = {
278 CC1120_DEVIATION_M, PACKET_DEV_M,
279 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
280 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
281 (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
282 CC1120_DRATE2, ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
283 (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
284 CC1120_DRATE1, ((PACKET_DRATE_M >> 8) & 0xff),
285 CC1120_DRATE0, ((PACKET_DRATE_M >> 0) & 0xff),
286 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
287 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
288 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
289 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
290 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
291 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
292 CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) |
293 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
294 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
295 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
296 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
299 static const uint16_t packet_tx_setup[] = {
300 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
301 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
302 CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
305 static const uint16_t packet_rx_setup[] = {
306 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
307 (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
308 CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
312 * RDF deviation is 5kHz
314 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
316 * 32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
321 #define RDF_PACKET_LEN 50
324 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
326 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
327 * Rdata = -------------------------------------- * fosc
333 * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
335 #define RDF_DRATE_E 5
336 #define RDF_DRATE_M 25166
337 #define RDF_PACKET_LEN 50
339 static const uint16_t rdf_setup[] = {
340 CC1120_DEVIATION_M, RDF_DEV_M,
341 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
342 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
343 (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
344 CC1120_DRATE2, ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
345 (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
346 CC1120_DRATE1, ((RDF_DRATE_M >> 8) & 0xff),
347 CC1120_DRATE0, ((RDF_DRATE_M >> 0) & 0xff),
348 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
349 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
350 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
351 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
352 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
353 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
354 CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) |
355 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
356 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
357 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
358 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
362 * APRS deviation is 5kHz
364 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
366 * 32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
370 #define APRS_DEV_M 71
371 #define APRS_PACKET_LEN 50
374 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
376 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
377 * Rdata = -------------------------------------- * fosc
380 * DATARATE_M = 239914
383 * Rdata = 9599.998593330383301
386 #define APRS_DRATE_E 7
387 #define APRS_DRATE_M 239914
389 static const uint16_t aprs_setup[] = {
390 CC1120_DEVIATION_M, APRS_DEV_M,
391 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
392 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
393 (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
394 CC1120_DRATE2, ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
395 (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
396 CC1120_DRATE1, ((APRS_DRATE_M >> 8) & 0xff),
397 CC1120_DRATE0, ((APRS_DRATE_M >> 0) & 0xff),
398 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
399 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
400 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
401 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
402 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
403 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
406 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) | \
407 (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
408 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) | \
409 (0 << CC1120_PKT_CFG0_UART_MODE_EN) | \
410 (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
412 #define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) | \
413 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
414 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) | \
415 (0 << CC1120_PKT_CFG0_UART_MODE_EN) | \
416 (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
418 static uint16_t ao_radio_mode;
420 #define AO_RADIO_MODE_BITS_PACKET 1
421 #define AO_RADIO_MODE_BITS_PACKET_TX 2
422 #define AO_RADIO_MODE_BITS_TX_BUF 4
423 #define AO_RADIO_MODE_BITS_TX_FINISH 8
424 #define AO_RADIO_MODE_BITS_PACKET_RX 16
425 #define AO_RADIO_MODE_BITS_RDF 32
426 #define AO_RADIO_MODE_BITS_APRS 64
427 #define AO_RADIO_MODE_BITS_INFINITE 128
428 #define AO_RADIO_MODE_BITS_FIXED 256
430 #define AO_RADIO_MODE_NONE 0
431 #define AO_RADIO_MODE_PACKET_TX_BUF (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
432 #define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
433 #define AO_RADIO_MODE_PACKET_RX (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
434 #define AO_RADIO_MODE_RDF (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
435 #define AO_RADIO_MODE_APRS_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
436 #define AO_RADIO_MODE_APRS_LAST_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
437 #define AO_RADIO_MODE_APRS_FINISH (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
440 ao_radio_set_mode(uint16_t new_mode)
445 if (new_mode == ao_radio_mode)
448 changes = new_mode & (~ao_radio_mode);
449 if (changes & AO_RADIO_MODE_BITS_PACKET)
450 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
451 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
453 if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
454 for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2)
455 ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
457 if (changes & AO_RADIO_MODE_BITS_TX_BUF)
458 ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
460 if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
461 ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
463 if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
464 for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
465 ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]);
467 if (changes & AO_RADIO_MODE_BITS_RDF)
468 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
469 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
471 if (changes & AO_RADIO_MODE_BITS_APRS)
472 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
473 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
475 if (changes & AO_RADIO_MODE_BITS_INFINITE)
476 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
478 if (changes & AO_RADIO_MODE_BITS_FIXED)
479 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
481 ao_radio_mode = new_mode;
484 static const uint16_t radio_setup[] = {
485 #include "ao_cc1120_CC1120.h"
488 static uint8_t ao_radio_configured = 0;
495 ao_radio_strobe(CC1120_SRES);
497 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
498 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
504 ao_radio_configured = 1;
508 ao_radio_set_len(uint8_t len)
510 static uint8_t last_len;
512 if (len != last_len) {
513 ao_radio_reg_write(CC1120_PKT_LEN, len);
519 ao_radio_get(uint8_t len)
521 static uint32_t last_radio_setting;
523 ao_mutex_get(&ao_radio_mutex);
524 if (!ao_radio_configured)
526 if (ao_config.radio_setting != last_radio_setting) {
527 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
528 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
529 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
530 last_radio_setting = ao_config.radio_setting;
532 ao_radio_set_len(len);
535 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
538 ao_rdf_start(uint8_t len)
543 ao_radio_set_mode(AO_RADIO_MODE_RDF);
553 ao_arch_block_interrupts();
554 while (!ao_radio_wake && !ao_radio_abort)
555 ao_sleep(&ao_radio_wake);
556 ao_arch_release_interrupts();
565 ao_rdf_start(AO_RADIO_RDF_LEN);
567 ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
573 ao_radio_continuity(uint8_t c)
578 ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
580 status = ao_radio_fifo_write_start();
581 for (i = 0; i < 3; i++) {
582 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
584 ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN);
586 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN);
588 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
589 status = ao_radio_fifo_write_stop(status);
595 ao_radio_rdf_abort(void)
598 ao_wakeup(&ao_radio_wake);
602 ao_radio_test_cmd(void)
605 static uint8_t radio_on;
607 if (ao_cmd_lex_c != '\n') {
609 mode = (uint8_t) ao_cmd_lex_u32;
612 if ((mode & 2) && !radio_on) {
614 ao_monitor_disable();
617 ao_packet_slave_stop();
620 ao_radio_strobe(CC1120_STX);
623 for (t = 0; t < 10; t++) {
624 printf ("status: %02x\n", ao_radio_status());
625 ao_delay(AO_MS_TO_TICKS(100));
632 printf ("Hit a character to stop..."); flush();
636 if ((mode & 1) && radio_on) {
647 ao_radio_wait_isr(void)
650 ao_arch_block_interrupts();
651 while (!ao_radio_wake)
652 ao_sleep(&ao_radio_wake);
653 ao_arch_release_interrupts();
657 ao_radio_wait_tx(uint8_t wait_fifo)
659 uint8_t fifo_space = 0;
665 fifo_space = ao_radio_tx_fifo_space();
666 } while (!fifo_space);
670 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
673 ao_radio_send(const void *d, uint8_t size)
676 uint8_t *e = tx_data;
682 encode_len = ao_fec_encode(d, size, tx_data);
684 ao_radio_get(encode_len);
687 fifo_space = CC1120_FIFO_SIZE;
689 this_len = encode_len;
691 if (this_len > fifo_space) {
692 this_len = fifo_space;
693 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
695 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
698 ao_radio_fifo_write(e, this_len);
700 encode_len -= this_len;
706 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
709 fifo_space = ao_radio_wait_tx(encode_len != 0);
714 #define AO_RADIO_LOTS 64
717 ao_radio_send_lots(ao_radio_fill_func fill)
719 uint8_t buf[AO_RADIO_LOTS], *b;
727 fifo_space = CC1120_FIFO_SIZE;
729 cnt = (*fill)(buf, sizeof(buf));
736 /* At the last buffer, set the total length */
738 ao_radio_set_len(total & 0xff);
742 uint8_t this_len = cnt;
744 /* Wait for some space in the fifo */
745 while ((fifo_space = ao_radio_tx_fifo_space()) == 0) {
747 ao_arch_block_interrupts();
748 while (!ao_radio_wake)
749 ao_sleep(&ao_radio_wake);
750 ao_arch_release_interrupts();
752 if (this_len > fifo_space)
753 this_len = fifo_space;
759 ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
761 ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
763 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
765 ao_radio_fifo_write(b, this_len);
772 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
774 /* Wait for the transmitter to go idle */
780 static uint8_t rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
781 static uint16_t rx_data_count;
782 static uint16_t rx_data_consumed;
783 static uint16_t rx_data_cur;
784 static uint8_t rx_ignore;
785 static uint8_t rx_waiting;
788 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
790 uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
792 #include <ao_profile.h>
796 ao_radio_rx_isr(void)
802 if (rx_ignore == 0) {
803 if (rx_data_cur >= rx_data_count)
804 ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
806 rx_data[rx_data_cur++] = d;
807 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
810 rx_packet_tick = ao_profile_tick();
811 if (rx_data_cur < rx_data_count)
815 ao_wakeup(&ao_radio_wake);
823 ao_radio_rx_wait(void)
825 ao_arch_block_interrupts();
827 while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
829 ao_sleep(&ao_radio_wake);
832 ao_arch_release_interrupts();
835 rx_data_consumed += AO_FEC_DECODE_BLOCK;
837 return rx_data_cur - rx_data_consumed;
839 return AO_FEC_DECODE_BLOCK;
843 ao_radio_recv(__xdata void *d, uint8_t size)
849 static int been_here = 0;
851 size -= 2; /* status bytes */
852 if (size > AO_RADIO_MAX_RECV) {
853 ao_delay(AO_SEC_TO_TICKS(1));
857 rx_start_tick = ao_profile_tick();
860 len = size + 2; /* CRC bytes */
861 len += 1 + ~(len & 1); /* 1 or two pad bytes */
862 len *= 2; /* 1/2 rate convolution */
863 rx_data_count = len * 8; /* bytes to bits */
865 rx_data_consumed = 0;
869 ao_radio_in_recv = 1;
870 /* configure interrupt pin */
872 ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
881 ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
882 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
884 ao_radio_strobe(CC1120_SRX);
886 ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
888 ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
890 ao_radio_burst_read_stop();
892 ao_radio_strobe(CC1120_SIDLE);
894 /* Convert from 'real' rssi to cc1111-style values */
896 rssi = AO_RADIO_FROM_RSSI(ao_radio_reg_read(CC1120_RSSI1));
900 /* Store the received RSSI value; the crc-OK byte is already done */
902 ((uint8_t *) d)[size] = (uint8_t) rssi;
904 ao_radio_in_recv = 0;
910 rx_last_done_tick = rx_done_tick;
911 rx_done_tick = ao_profile_tick();
913 ao_rx_start_tick = rx_start_tick;
914 ao_rx_packet_tick = rx_packet_tick;
915 ao_rx_done_tick = rx_done_tick;
916 ao_rx_last_done_tick = rx_last_done_tick;
924 static char *cc1120_state_name[] = {
925 [CC1120_STATUS_STATE_IDLE] = "IDLE",
926 [CC1120_STATUS_STATE_RX] = "RX",
927 [CC1120_STATUS_STATE_TX] = "TX",
928 [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
929 [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
930 [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
931 [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
932 [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
935 struct ao_cc1120_reg {
940 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
941 { .addr = CC1120_IOCFG3, .name = "IOCFG3" },
942 { .addr = CC1120_IOCFG2, .name = "IOCFG2" },
943 { .addr = CC1120_IOCFG1, .name = "IOCFG1" },
944 { .addr = CC1120_IOCFG0, .name = "IOCFG0" },
945 { .addr = CC1120_SYNC3, .name = "SYNC3" },
946 { .addr = CC1120_SYNC2, .name = "SYNC2" },
947 { .addr = CC1120_SYNC1, .name = "SYNC1" },
948 { .addr = CC1120_SYNC0, .name = "SYNC0" },
949 { .addr = CC1120_SYNC_CFG1, .name = "SYNC_CFG1" },
950 { .addr = CC1120_SYNC_CFG0, .name = "SYNC_CFG0" },
951 { .addr = CC1120_DEVIATION_M, .name = "DEVIATION_M" },
952 { .addr = CC1120_MODCFG_DEV_E, .name = "MODCFG_DEV_E" },
953 { .addr = CC1120_DCFILT_CFG, .name = "DCFILT_CFG" },
954 { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
955 { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
956 { .addr = CC1120_FREQ_IF_CFG, .name = "FREQ_IF_CFG" },
957 { .addr = CC1120_IQIC, .name = "IQIC" },
958 { .addr = CC1120_CHAN_BW, .name = "CHAN_BW" },
959 { .addr = CC1120_MDMCFG1, .name = "MDMCFG1" },
960 { .addr = CC1120_MDMCFG0, .name = "MDMCFG0" },
961 { .addr = CC1120_DRATE2, .name = "DRATE2" },
962 { .addr = CC1120_DRATE1, .name = "DRATE1" },
963 { .addr = CC1120_DRATE0, .name = "DRATE0" },
964 { .addr = CC1120_AGC_REF, .name = "AGC_REF" },
965 { .addr = CC1120_AGC_CS_THR, .name = "AGC_CS_THR" },
966 { .addr = CC1120_AGC_GAIN_ADJUST, .name = "AGC_GAIN_ADJUST" },
967 { .addr = CC1120_AGC_CFG3, .name = "AGC_CFG3" },
968 { .addr = CC1120_AGC_CFG2, .name = "AGC_CFG2" },
969 { .addr = CC1120_AGC_CFG1, .name = "AGC_CFG1" },
970 { .addr = CC1120_AGC_CFG0, .name = "AGC_CFG0" },
971 { .addr = CC1120_FIFO_CFG, .name = "FIFO_CFG" },
972 { .addr = CC1120_DEV_ADDR, .name = "DEV_ADDR" },
973 { .addr = CC1120_SETTLING_CFG, .name = "SETTLING_CFG" },
974 { .addr = CC1120_FS_CFG, .name = "FS_CFG" },
975 { .addr = CC1120_WOR_CFG1, .name = "WOR_CFG1" },
976 { .addr = CC1120_WOR_CFG0, .name = "WOR_CFG0" },
977 { .addr = CC1120_WOR_EVENT0_MSB, .name = "WOR_EVENT0_MSB" },
978 { .addr = CC1120_WOR_EVENT0_LSB, .name = "WOR_EVENT0_LSB" },
979 { .addr = CC1120_PKT_CFG2, .name = "PKT_CFG2" },
980 { .addr = CC1120_PKT_CFG1, .name = "PKT_CFG1" },
981 { .addr = CC1120_PKT_CFG0, .name = "PKT_CFG0" },
982 { .addr = CC1120_RFEND_CFG1, .name = "RFEND_CFG1" },
983 { .addr = CC1120_RFEND_CFG0, .name = "RFEND_CFG0" },
984 { .addr = CC1120_PA_CFG2, .name = "PA_CFG2" },
985 { .addr = CC1120_PA_CFG1, .name = "PA_CFG1" },
986 { .addr = CC1120_PA_CFG0, .name = "PA_CFG0" },
987 { .addr = CC1120_PKT_LEN, .name = "PKT_LEN" },
988 { .addr = CC1120_IF_MIX_CFG, .name = "IF_MIX_CFG" },
989 { .addr = CC1120_FREQOFF_CFG, .name = "FREQOFF_CFG" },
990 { .addr = CC1120_TOC_CFG, .name = "TOC_CFG" },
991 { .addr = CC1120_MARC_SPARE, .name = "MARC_SPARE" },
992 { .addr = CC1120_ECG_CFG, .name = "ECG_CFG" },
993 { .addr = CC1120_SOFT_TX_DATA_CFG, .name = "SOFT_TX_DATA_CFG" },
994 { .addr = CC1120_EXT_CTRL, .name = "EXT_CTRL" },
995 { .addr = CC1120_RCCAL_FINE, .name = "RCCAL_FINE" },
996 { .addr = CC1120_RCCAL_COARSE, .name = "RCCAL_COARSE" },
997 { .addr = CC1120_RCCAL_OFFSET, .name = "RCCAL_OFFSET" },
998 { .addr = CC1120_FREQOFF1, .name = "FREQOFF1" },
999 { .addr = CC1120_FREQOFF0, .name = "FREQOFF0" },
1000 { .addr = CC1120_FREQ2, .name = "FREQ2" },
1001 { .addr = CC1120_FREQ1, .name = "FREQ1" },
1002 { .addr = CC1120_FREQ0, .name = "FREQ0" },
1003 { .addr = CC1120_IF_ADC2, .name = "IF_ADC2" },
1004 { .addr = CC1120_IF_ADC1, .name = "IF_ADC1" },
1005 { .addr = CC1120_IF_ADC0, .name = "IF_ADC0" },
1006 { .addr = CC1120_FS_DIG1, .name = "FS_DIG1" },
1007 { .addr = CC1120_FS_DIG0, .name = "FS_DIG0" },
1008 { .addr = CC1120_FS_CAL3, .name = "FS_CAL3" },
1009 { .addr = CC1120_FS_CAL2, .name = "FS_CAL2" },
1010 { .addr = CC1120_FS_CAL1, .name = "FS_CAL1" },
1011 { .addr = CC1120_FS_CAL0, .name = "FS_CAL0" },
1012 { .addr = CC1120_FS_CHP, .name = "FS_CHP" },
1013 { .addr = CC1120_FS_DIVTWO, .name = "FS_DIVTWO" },
1014 { .addr = CC1120_FS_DSM1, .name = "FS_DSM1" },
1015 { .addr = CC1120_FS_DSM0, .name = "FS_DSM0" },
1016 { .addr = CC1120_FS_DVC1, .name = "FS_DVC1" },
1017 { .addr = CC1120_FS_DVC0, .name = "FS_DVC0" },
1018 { .addr = CC1120_FS_LBI, .name = "FS_LBI" },
1019 { .addr = CC1120_FS_PFD, .name = "FS_PFD" },
1020 { .addr = CC1120_FS_PRE, .name = "FS_PRE" },
1021 { .addr = CC1120_FS_REG_DIV_CML, .name = "FS_REG_DIV_CML" },
1022 { .addr = CC1120_FS_SPARE, .name = "FS_SPARE" },
1023 { .addr = CC1120_FS_VCO4, .name = "FS_VCO4" },
1024 { .addr = CC1120_FS_VCO3, .name = "FS_VCO3" },
1025 { .addr = CC1120_FS_VCO2, .name = "FS_VCO2" },
1026 { .addr = CC1120_FS_VCO1, .name = "FS_VCO1" },
1027 { .addr = CC1120_FS_VCO0, .name = "FS_VCO0" },
1028 { .addr = CC1120_GBIAS6, .name = "GBIAS6" },
1029 { .addr = CC1120_GBIAS5, .name = "GBIAS5" },
1030 { .addr = CC1120_GBIAS4, .name = "GBIAS4" },
1031 { .addr = CC1120_GBIAS3, .name = "GBIAS3" },
1032 { .addr = CC1120_GBIAS2, .name = "GBIAS2" },
1033 { .addr = CC1120_GBIAS1, .name = "GBIAS1" },
1034 { .addr = CC1120_GBIAS0, .name = "GBIAS0" },
1035 { .addr = CC1120_IFAMP, .name = "IFAMP" },
1036 { .addr = CC1120_LNA, .name = "LNA" },
1037 { .addr = CC1120_RXMIX, .name = "RXMIX" },
1038 { .addr = CC1120_XOSC5, .name = "XOSC5" },
1039 { .addr = CC1120_XOSC4, .name = "XOSC4" },
1040 { .addr = CC1120_XOSC3, .name = "XOSC3" },
1041 { .addr = CC1120_XOSC2, .name = "XOSC2" },
1042 { .addr = CC1120_XOSC1, .name = "XOSC1" },
1043 { .addr = CC1120_XOSC0, .name = "XOSC0" },
1044 { .addr = CC1120_ANALOG_SPARE, .name = "ANALOG_SPARE" },
1045 { .addr = CC1120_PA_CFG3, .name = "PA_CFG3" },
1046 { .addr = CC1120_WOR_TIME1, .name = "WOR_TIME1" },
1047 { .addr = CC1120_WOR_TIME0, .name = "WOR_TIME0" },
1048 { .addr = CC1120_WOR_CAPTURE1, .name = "WOR_CAPTURE1" },
1049 { .addr = CC1120_WOR_CAPTURE0, .name = "WOR_CAPTURE0" },
1050 { .addr = CC1120_BIST, .name = "BIST" },
1051 { .addr = CC1120_DCFILTOFFSET_I1, .name = "DCFILTOFFSET_I1" },
1052 { .addr = CC1120_DCFILTOFFSET_I0, .name = "DCFILTOFFSET_I0" },
1053 { .addr = CC1120_DCFILTOFFSET_Q1, .name = "DCFILTOFFSET_Q1" },
1054 { .addr = CC1120_DCFILTOFFSET_Q0, .name = "DCFILTOFFSET_Q0" },
1055 { .addr = CC1120_IQIE_I1, .name = "IQIE_I1" },
1056 { .addr = CC1120_IQIE_I0, .name = "IQIE_I0" },
1057 { .addr = CC1120_IQIE_Q1, .name = "IQIE_Q1" },
1058 { .addr = CC1120_IQIE_Q0, .name = "IQIE_Q0" },
1059 { .addr = CC1120_RSSI1, .name = "RSSI1" },
1060 { .addr = CC1120_RSSI0, .name = "RSSI0" },
1061 { .addr = CC1120_MARCSTATE, .name = "MARCSTATE" },
1062 { .addr = CC1120_LQI_VAL, .name = "LQI_VAL" },
1063 { .addr = CC1120_PQT_SYNC_ERR, .name = "PQT_SYNC_ERR" },
1064 { .addr = CC1120_DEM_STATUS, .name = "DEM_STATUS" },
1065 { .addr = CC1120_FREQOFF_EST1, .name = "FREQOFF_EST1" },
1066 { .addr = CC1120_FREQOFF_EST0, .name = "FREQOFF_EST0" },
1067 { .addr = CC1120_AGC_GAIN3, .name = "AGC_GAIN3" },
1068 { .addr = CC1120_AGC_GAIN2, .name = "AGC_GAIN2" },
1069 { .addr = CC1120_AGC_GAIN1, .name = "AGC_GAIN1" },
1070 { .addr = CC1120_AGC_GAIN0, .name = "AGC_GAIN0" },
1071 { .addr = CC1120_SOFT_RX_DATA_OUT, .name = "SOFT_RX_DATA_OUT" },
1072 { .addr = CC1120_SOFT_TX_DATA_IN, .name = "SOFT_TX_DATA_IN" },
1073 { .addr = CC1120_ASK_SOFT_RX_DATA, .name = "ASK_SOFT_RX_DATA" },
1074 { .addr = CC1120_RNDGEN, .name = "RNDGEN" },
1075 { .addr = CC1120_MAGN2, .name = "MAGN2" },
1076 { .addr = CC1120_MAGN1, .name = "MAGN1" },
1077 { .addr = CC1120_MAGN0, .name = "MAGN0" },
1078 { .addr = CC1120_ANG1, .name = "ANG1" },
1079 { .addr = CC1120_ANG0, .name = "ANG0" },
1080 { .addr = CC1120_CHFILT_I2, .name = "CHFILT_I2" },
1081 { .addr = CC1120_CHFILT_I1, .name = "CHFILT_I1" },
1082 { .addr = CC1120_CHFILT_I0, .name = "CHFILT_I0" },
1083 { .addr = CC1120_CHFILT_Q2, .name = "CHFILT_Q2" },
1084 { .addr = CC1120_CHFILT_Q1, .name = "CHFILT_Q1" },
1085 { .addr = CC1120_CHFILT_Q0, .name = "CHFILT_Q0" },
1086 { .addr = CC1120_GPIO_STATUS, .name = "GPIO_STATUS" },
1087 { .addr = CC1120_FSCAL_CTRL, .name = "FSCAL_CTRL" },
1088 { .addr = CC1120_PHASE_ADJUST, .name = "PHASE_ADJUST" },
1089 { .addr = CC1120_PARTNUMBER, .name = "PARTNUMBER" },
1090 { .addr = CC1120_PARTVERSION, .name = "PARTVERSION" },
1091 { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1092 { .addr = CC1120_RX_STATUS, .name = "RX_STATUS" },
1093 { .addr = CC1120_TX_STATUS, .name = "TX_STATUS" },
1094 { .addr = CC1120_MARC_STATUS1, .name = "MARC_STATUS1" },
1095 { .addr = CC1120_MARC_STATUS0, .name = "MARC_STATUS0" },
1096 { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1097 { .addr = CC1120_FSRF_TEST, .name = "FSRF_TEST" },
1098 { .addr = CC1120_PRE_TEST, .name = "PRE_TEST" },
1099 { .addr = CC1120_PRE_OVR, .name = "PRE_OVR" },
1100 { .addr = CC1120_ADC_TEST, .name = "ADC_TEST" },
1101 { .addr = CC1120_DVC_TEST, .name = "DVC_TEST" },
1102 { .addr = CC1120_ATEST, .name = "ATEST" },
1103 { .addr = CC1120_ATEST_LVDS, .name = "ATEST_LVDS" },
1104 { .addr = CC1120_ATEST_MODE, .name = "ATEST_MODE" },
1105 { .addr = CC1120_XOSC_TEST1, .name = "XOSC_TEST1" },
1106 { .addr = CC1120_XOSC_TEST0, .name = "XOSC_TEST0" },
1107 { .addr = CC1120_RXFIRST, .name = "RXFIRST" },
1108 { .addr = CC1120_TXFIRST, .name = "TXFIRST" },
1109 { .addr = CC1120_RXLAST, .name = "RXLAST" },
1110 { .addr = CC1120_TXLAST, .name = "TXLAST" },
1111 { .addr = CC1120_NUM_TXBYTES, .name = "NUM_TXBYTES" },
1112 { .addr = CC1120_NUM_RXBYTES, .name = "NUM_RXBYTES" },
1113 { .addr = CC1120_FIFO_NUM_TXBYTES, .name = "FIFO_NUM_TXBYTES" },
1114 { .addr = CC1120_FIFO_NUM_RXBYTES, .name = "FIFO_NUM_RXBYTES" },
1117 #define AO_NUM_CC1120_REG (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1119 static void ao_radio_show(void) {
1120 uint8_t status = ao_radio_status();
1124 status = ao_radio_status();
1125 printf ("Status: %02x\n", status);
1126 printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1127 printf ("STATE: %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1128 printf ("MARC: %02x\n", ao_radio_marc_status());
1130 for (i = 0; i < AO_NUM_CC1120_REG; i++)
1131 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1135 static void ao_radio_beep(void) {
1136 ao_radio_rdf(RDF_PACKET_LEN);
1139 static void ao_radio_packet(void) {
1140 static const uint8_t packet[] = {
1142 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1143 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1144 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1145 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1151 ao_radio_send(packet, sizeof (packet));
1155 ao_radio_test_recv()
1160 if (ao_radio_recv(bytes, 34)) {
1161 if (bytes[33] & 0x80)
1165 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1166 for (b = 0; b < 32; b++)
1167 printf (" %02x", bytes[b]);
1172 #include <ao_aprs.h>
1177 ao_packet_slave_stop();
1183 static const struct ao_cmds ao_radio_cmds[] = {
1184 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
1186 { ao_radio_aprs, "G\0Send APRS packet" },
1187 { ao_radio_show, "R\0Show CC1120 status" },
1188 { ao_radio_beep, "b\0Emit an RDF beacon" },
1189 { ao_radio_packet, "p\0Send a test packet" },
1190 { ao_radio_test_recv, "q\0Recv a test packet" },
1200 ao_radio_configured = 0;
1201 ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1204 AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1205 for (i = 0; i < 10000; i++) {
1206 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1209 AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1211 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1214 /* Enable the EXTI interrupt for the appropriate pin */
1215 ao_enable_port(AO_CC1120_INT_PORT);
1216 ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1217 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1220 ao_cmd_register(&ao_radio_cmds[0]);