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 static uint8_t ao_radio_mutex;
29 static uint8_t ao_radio_wake; /* radio ready. Also used as sleep address */
30 static uint8_t ao_radio_abort; /* radio operation should abort */
31 static uint8_t ao_radio_mcu_wake; /* MARC status change */
32 static uint8_t ao_radio_marc_status; /* Last read MARC status value */
33 static uint8_t ao_radio_tx_finished; /* MARC status indicates TX finished */
35 #define CC1120_DEBUG AO_FEC_DEBUG
36 #define CC1120_TRACE 0
38 extern const uint32_t ao_radio_cal;
42 #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_4MHz)
43 #define ao_radio_deselect() ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
44 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
45 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
46 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
47 #define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS)
50 ao_radio_reg_read(uint16_t addr)
56 printf("\t\tao_radio_reg_read (%04x): ", addr); flush();
58 if (CC1120_IS_EXTENDED(addr)) {
59 data[0] = ((1 << CC1120_READ) |
65 data[0] = ((1 << CC1120_READ) |
71 ao_radio_spi_send(data, d);
72 ao_radio_spi_recv(data, 1);
75 printf (" %02x\n", data[0]);
81 ao_radio_reg_write(uint16_t addr, uint8_t value)
87 printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value);
89 if (CC1120_IS_EXTENDED(addr)) {
90 data[0] = ((0 << CC1120_READ) |
96 data[0] = ((0 << CC1120_READ) |
103 ao_radio_spi_send(data, d+1);
108 ao_radio_burst_read_start (uint16_t addr)
113 if (CC1120_IS_EXTENDED(addr)) {
114 data[0] = ((1 << CC1120_READ) |
115 (1 << CC1120_BURST) |
120 data[0] = ((1 << CC1120_READ) |
121 (1 << CC1120_BURST) |
126 ao_radio_spi_send(data, d);
130 ao_radio_burst_read_stop (void)
137 ao_radio_strobe(uint8_t addr)
142 printf("\t\tao_radio_strobe (%02x): ", addr); flush();
145 ao_radio_duplex(&addr, &in, 1);
148 printf("%02x\n", in); flush();
154 ao_radio_fifo_read(uint8_t *data, uint8_t len)
156 uint8_t addr = ((1 << CC1120_READ) |
157 (1 << CC1120_BURST) |
162 ao_radio_duplex(&addr, &status, 1);
163 ao_radio_spi_recv(data, len);
169 ao_radio_fifo_write_start(void)
171 uint8_t addr = ((0 << CC1120_READ) |
172 (1 << CC1120_BURST) |
177 ao_radio_duplex(&addr, &status, 1);
181 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
187 ao_radio_fifo_write(uint8_t *data, uint8_t len)
189 uint8_t status = ao_radio_fifo_write_start();
190 ao_radio_spi_send(data, len);
191 return ao_radio_fifo_write_stop(status);
195 ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)
197 uint8_t status = ao_radio_fifo_write_start();
198 ao_radio_spi_send_fixed(data, len);
199 return ao_radio_fifo_write_stop(status);
203 ao_radio_tx_fifo_space(void)
205 return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
209 ao_radio_status(void)
211 return ao_radio_strobe (CC1120_SNOP);
215 ao_radio_recv_abort(void)
218 ao_wakeup(&ao_radio_wake);
221 #define ao_radio_rdf_value 0x55
224 ao_radio_get_marc_status(void)
226 return ao_radio_reg_read(CC1120_MARC_STATUS1);
230 ao_radio_mcu_wakeup_isr(void)
232 ao_radio_mcu_wake = 1;
233 ao_wakeup(&ao_radio_wake);
238 ao_radio_check_marc_status(void)
240 ao_radio_mcu_wake = 0;
241 ao_radio_marc_status = ao_radio_get_marc_status();
243 /* Anyt other than 'tx/rx finished' means an error occurred */
244 if (ao_radio_marc_status & ~(CC1120_MARC_STATUS1_TX_FINISHED|CC1120_MARC_STATUS1_RX_FINISHED))
246 if (ao_radio_marc_status & (CC1120_MARC_STATUS1_TX_FINISHED))
247 ao_radio_tx_finished = 1;
253 ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
255 ao_wakeup(&ao_radio_wake);
259 ao_radio_start_tx(void)
261 ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
262 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
263 ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
264 ao_radio_tx_finished = 0;
265 ao_radio_strobe(CC1120_STX);
272 uint8_t state = ao_radio_strobe(CC1120_SIDLE);
273 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
275 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_TX_FIFO_ERROR)
276 ao_radio_strobe(CC1120_SFTX);
278 /* Flush any pending TX bytes */
279 ao_radio_strobe(CC1120_SFTX);
283 * Packet deviation is 20.5kHz
285 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
287 * 32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
290 #define PACKET_DEV_E 5
291 #define PACKET_DEV_M 80
294 * For our packet data, set the symbol rate to 38400 Baud
296 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
297 * Rdata = -------------------------------------- * fosc
301 * DATARATE_M = 239914
304 #define PACKET_DRATE_E 9
305 #define PACKET_DRATE_M 239914
307 static const uint16_t packet_setup[] = {
308 CC1120_DEVIATION_M, PACKET_DEV_M,
309 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
310 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
311 (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
312 CC1120_DRATE2, ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
313 (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
314 CC1120_DRATE1, ((PACKET_DRATE_M >> 8) & 0xff),
315 CC1120_DRATE0, ((PACKET_DRATE_M >> 0) & 0xff),
316 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
317 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
318 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
319 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
320 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
321 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
322 CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) |
323 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
324 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
325 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
326 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
327 AO_CC1120_MARC_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,
330 static const uint16_t packet_tx_setup[] = {
331 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
332 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
333 AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
336 static const uint16_t packet_rx_setup[] = {
337 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
338 (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
339 AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
343 * RDF deviation is 5kHz
345 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
347 * 32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
352 #define RDF_PACKET_LEN 50
355 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
357 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
358 * Rdata = -------------------------------------- * fosc
364 * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
366 #define RDF_DRATE_E 5
367 #define RDF_DRATE_M 25166
368 #define RDF_PACKET_LEN 50
370 static const uint16_t rdf_setup[] = {
371 CC1120_DEVIATION_M, RDF_DEV_M,
372 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
373 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
374 (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
375 CC1120_DRATE2, ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
376 (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
377 CC1120_DRATE1, ((RDF_DRATE_M >> 8) & 0xff),
378 CC1120_DRATE0, ((RDF_DRATE_M >> 0) & 0xff),
379 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
380 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
381 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
382 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
383 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
384 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
385 CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) |
386 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
387 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
388 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
389 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
393 * APRS deviation is 5kHz
395 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
397 * 32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
401 #define APRS_DEV_M 71
402 #define APRS_PACKET_LEN 50
405 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
407 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
408 * Rdata = -------------------------------------- * fosc
411 * DATARATE_M = 239914
414 * Rdata = 9599.998593330383301
417 #define APRS_DRATE_E 7
418 #define APRS_DRATE_M 239914
420 static const uint16_t aprs_setup[] = {
421 CC1120_DEVIATION_M, APRS_DEV_M,
422 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
423 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
424 (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
425 CC1120_DRATE2, ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
426 (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
427 CC1120_DRATE1, ((APRS_DRATE_M >> 8) & 0xff),
428 CC1120_DRATE0, ((APRS_DRATE_M >> 0) & 0xff),
429 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
430 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
431 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
432 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
433 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
434 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
437 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) | \
438 (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
439 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) | \
440 (0 << CC1120_PKT_CFG0_UART_MODE_EN) | \
441 (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
443 #define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) | \
444 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
445 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) | \
446 (0 << CC1120_PKT_CFG0_UART_MODE_EN) | \
447 (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
449 static uint16_t ao_radio_mode;
451 #define AO_RADIO_MODE_BITS_PACKET 1
452 #define AO_RADIO_MODE_BITS_PACKET_TX 2
453 #define AO_RADIO_MODE_BITS_TX_BUF 4
454 #define AO_RADIO_MODE_BITS_TX_FINISH 8
455 #define AO_RADIO_MODE_BITS_PACKET_RX 16
456 #define AO_RADIO_MODE_BITS_RDF 32
457 #define AO_RADIO_MODE_BITS_APRS 64
458 #define AO_RADIO_MODE_BITS_INFINITE 128
459 #define AO_RADIO_MODE_BITS_FIXED 256
461 #define AO_RADIO_MODE_NONE 0
462 #define AO_RADIO_MODE_PACKET_TX_BUF (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
463 #define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
464 #define AO_RADIO_MODE_PACKET_RX (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
465 #define AO_RADIO_MODE_RDF (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
466 #define AO_RADIO_MODE_APRS_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
467 #define AO_RADIO_MODE_APRS_LAST_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
468 #define AO_RADIO_MODE_APRS_FINISH (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
471 ao_radio_set_mode(uint16_t new_mode)
476 if (new_mode == ao_radio_mode)
479 changes = new_mode & (~ao_radio_mode);
480 if (changes & AO_RADIO_MODE_BITS_PACKET)
481 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
482 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
484 if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
485 for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2)
486 ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
488 if (changes & AO_RADIO_MODE_BITS_TX_BUF)
489 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
491 if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
492 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
494 if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
495 for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
496 ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]);
498 if (changes & AO_RADIO_MODE_BITS_RDF)
499 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
500 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
502 if (changes & AO_RADIO_MODE_BITS_APRS)
503 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
504 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
506 if (changes & AO_RADIO_MODE_BITS_INFINITE)
507 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
509 if (changes & AO_RADIO_MODE_BITS_FIXED)
510 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
512 ao_radio_mode = new_mode;
515 static const uint16_t radio_setup[] = {
516 #include "ao_cc1120_CC1120.h"
519 static uint8_t ao_radio_configured = 0;
526 ao_radio_strobe(CC1120_SRES);
528 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
529 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
535 ao_radio_configured = 1;
539 ao_radio_set_len(uint8_t len)
541 static uint8_t last_len;
543 if (len != last_len) {
544 ao_radio_reg_write(CC1120_PKT_LEN, len);
550 ao_radio_get(uint8_t len)
552 static uint32_t last_radio_setting;
554 ao_mutex_get(&ao_radio_mutex);
555 if (!ao_radio_configured)
557 if (ao_config.radio_setting != last_radio_setting) {
558 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
559 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
560 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
561 last_radio_setting = ao_config.radio_setting;
563 ao_radio_set_len(len);
566 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
569 ao_rdf_start(uint8_t len)
574 ao_radio_set_mode(AO_RADIO_MODE_RDF);
584 ao_arch_block_interrupts();
585 while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake)
586 ao_sleep(&ao_radio_wake);
587 ao_arch_release_interrupts();
588 if (ao_radio_mcu_wake)
589 ao_radio_check_marc_status();
598 ao_rdf_start(AO_RADIO_RDF_LEN);
600 ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
606 ao_radio_continuity(uint8_t c)
611 ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
613 status = ao_radio_fifo_write_start();
614 for (i = 0; i < 3; i++) {
615 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
617 ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN);
619 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN);
621 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
622 status = ao_radio_fifo_write_stop(status);
628 ao_radio_rdf_abort(void)
631 ao_wakeup(&ao_radio_wake);
635 ao_radio_test_cmd(void)
638 static uint8_t radio_on;
640 if (ao_cmd_lex_c != '\n') {
642 mode = (uint8_t) ao_cmd_lex_u32;
645 if ((mode & 2) && !radio_on) {
647 ao_monitor_disable();
650 ao_packet_slave_stop();
653 ao_radio_strobe(CC1120_STX);
656 for (t = 0; t < 10; t++) {
657 printf ("status: %02x\n", ao_radio_status());
658 ao_delay(AO_MS_TO_TICKS(100));
665 printf ("Hit a character to stop..."); flush();
669 if ((mode & 1) && radio_on) {
680 ao_radio_wait_isr(uint16_t timeout)
684 ao_arch_block_interrupts();
685 while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
686 if (ao_sleep(&ao_radio_wake))
688 ao_arch_release_interrupts();
691 if (ao_radio_mcu_wake)
692 ao_radio_check_marc_status();
696 ao_radio_wait_tx(uint8_t wait_fifo)
698 uint8_t fifo_space = 0;
701 ao_radio_wait_isr(0);
704 fifo_space = ao_radio_tx_fifo_space();
705 } while (!fifo_space && !ao_radio_abort);
709 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
712 ao_radio_send(const void *d, uint8_t size)
715 uint8_t *e = tx_data;
722 encode_len = ao_fec_encode(d, size, tx_data);
724 ao_radio_get(encode_len);
728 /* Flush any pending TX bytes */
729 ao_radio_strobe(CC1120_SFTX);
732 fifo_space = CC1120_FIFO_SIZE;
734 this_len = encode_len;
737 if (this_len > fifo_space) {
738 this_len = fifo_space;
739 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
741 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
744 ao_radio_fifo_write(e, this_len);
746 encode_len -= this_len;
752 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
755 fifo_space = ao_radio_wait_tx(encode_len != 0);
756 if (ao_radio_abort) {
761 while (started && !ao_radio_abort && !ao_radio_tx_finished)
762 ao_radio_wait_isr(0);
766 #define AO_RADIO_LOTS 64
769 ao_radio_send_aprs(ao_radio_fill_func fill)
771 uint8_t buf[AO_RADIO_LOTS], *b;
779 fifo_space = CC1120_FIFO_SIZE;
781 cnt = (*fill)(buf, sizeof(buf));
788 /* At the last buffer, set the total length */
790 ao_radio_set_len(total & 0xff);
794 uint8_t this_len = cnt;
796 /* Wait for some space in the fifo */
797 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
799 ao_radio_wait_isr(0);
803 if (this_len > fifo_space)
804 this_len = fifo_space;
810 ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
812 ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
814 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
816 ao_radio_fifo_write(b, this_len);
823 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
825 if (ao_radio_abort) {
829 /* Wait for the transmitter to go idle */
831 ao_radio_wait_isr(0);
836 static uint8_t rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
837 static uint16_t rx_data_count;
838 static uint16_t rx_data_consumed;
839 static uint16_t rx_data_cur;
840 static uint8_t rx_ignore;
841 static uint8_t rx_waiting;
844 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
846 uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
848 #include <ao_profile.h>
852 ao_radio_rx_isr(void)
856 d = AO_CC1120_SPI.dr;
857 AO_CC1120_SPI.dr = 0;
858 if (rx_ignore == 0) {
859 if (rx_data_cur >= rx_data_count)
860 ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
862 rx_data[rx_data_cur++] = d;
863 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
866 rx_packet_tick = ao_profile_tick();
867 if (rx_data_cur < rx_data_count)
871 ao_wakeup(&ao_radio_wake);
879 ao_radio_rx_wait(void)
882 if (ao_radio_mcu_wake)
883 ao_radio_check_marc_status();
884 ao_alarm(AO_MS_TO_TICKS(100));
885 ao_arch_block_interrupts();
887 while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
891 if (ao_sleep(&ao_radio_wake))
895 ao_arch_release_interrupts();
897 } while (ao_radio_mcu_wake);
900 rx_data_consumed += AO_FEC_DECODE_BLOCK;
902 return rx_data_cur - rx_data_consumed;
904 return AO_FEC_DECODE_BLOCK;
908 ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
914 static int been_here = 0;
916 size -= 2; /* status bytes */
917 if (size > AO_RADIO_MAX_RECV) {
918 ao_delay(AO_SEC_TO_TICKS(1));
922 rx_start_tick = ao_profile_tick();
925 len = size + 2; /* CRC bytes */
926 len += 1 + ~(len & 1); /* 1 or two pad bytes */
927 len *= 2; /* 1/2 rate convolution */
928 rx_data_count = len * 8; /* bytes to bits */
930 rx_data_consumed = 0;
933 /* Must be set before changing the frequency; any abort
934 * after the frequency is set needs to terminate the read
935 * so that the registers can be reprogrammed
939 /* configure interrupt pin */
941 ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
944 ao_radio_mcu_wake = 0;
946 AO_CC1120_SPI.cr2 = 0;
949 (void) AO_CC1120_SPI.dr;
951 /* Have the radio signal when the preamble quality goes high */
952 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_PQT_REACHED);
953 ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
954 AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH);
955 ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
956 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
957 ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
959 ao_radio_strobe(CC1120_SRX);
961 /* Wait for the preamble to appear */
962 ao_radio_wait_isr(timeout);
966 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
967 ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
968 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
970 ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
971 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
973 ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
975 ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
977 ao_radio_burst_read_stop();
980 ao_radio_strobe(CC1120_SIDLE);
982 /* Convert from 'real' rssi to cc1111-style values */
984 rssi = AO_RADIO_FROM_RSSI(ao_radio_reg_read(CC1120_RSSI1));
988 /* Store the received RSSI value; the crc-OK byte is already done */
990 ((uint8_t *) d)[size] = (uint8_t) rssi;
993 rx_last_done_tick = rx_done_tick;
994 rx_done_tick = ao_profile_tick();
996 ao_rx_start_tick = rx_start_tick;
997 ao_rx_packet_tick = rx_packet_tick;
998 ao_rx_done_tick = rx_done_tick;
999 ao_rx_last_done_tick = rx_last_done_tick;
1007 static char *cc1120_state_name[] = {
1008 [CC1120_STATUS_STATE_IDLE] = "IDLE",
1009 [CC1120_STATUS_STATE_RX] = "RX",
1010 [CC1120_STATUS_STATE_TX] = "TX",
1011 [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
1012 [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
1013 [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
1014 [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
1015 [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
1018 struct ao_cc1120_reg {
1023 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
1024 { .addr = CC1120_IOCFG3, .name = "IOCFG3" },
1025 { .addr = CC1120_IOCFG2, .name = "IOCFG2" },
1026 { .addr = CC1120_IOCFG1, .name = "IOCFG1" },
1027 { .addr = CC1120_IOCFG0, .name = "IOCFG0" },
1028 { .addr = CC1120_SYNC3, .name = "SYNC3" },
1029 { .addr = CC1120_SYNC2, .name = "SYNC2" },
1030 { .addr = CC1120_SYNC1, .name = "SYNC1" },
1031 { .addr = CC1120_SYNC0, .name = "SYNC0" },
1032 { .addr = CC1120_SYNC_CFG1, .name = "SYNC_CFG1" },
1033 { .addr = CC1120_SYNC_CFG0, .name = "SYNC_CFG0" },
1034 { .addr = CC1120_DEVIATION_M, .name = "DEVIATION_M" },
1035 { .addr = CC1120_MODCFG_DEV_E, .name = "MODCFG_DEV_E" },
1036 { .addr = CC1120_DCFILT_CFG, .name = "DCFILT_CFG" },
1037 { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
1038 { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
1039 { .addr = CC1120_FREQ_IF_CFG, .name = "FREQ_IF_CFG" },
1040 { .addr = CC1120_IQIC, .name = "IQIC" },
1041 { .addr = CC1120_CHAN_BW, .name = "CHAN_BW" },
1042 { .addr = CC1120_MDMCFG1, .name = "MDMCFG1" },
1043 { .addr = CC1120_MDMCFG0, .name = "MDMCFG0" },
1044 { .addr = CC1120_DRATE2, .name = "DRATE2" },
1045 { .addr = CC1120_DRATE1, .name = "DRATE1" },
1046 { .addr = CC1120_DRATE0, .name = "DRATE0" },
1047 { .addr = CC1120_AGC_REF, .name = "AGC_REF" },
1048 { .addr = CC1120_AGC_CS_THR, .name = "AGC_CS_THR" },
1049 { .addr = CC1120_AGC_GAIN_ADJUST, .name = "AGC_GAIN_ADJUST" },
1050 { .addr = CC1120_AGC_CFG3, .name = "AGC_CFG3" },
1051 { .addr = CC1120_AGC_CFG2, .name = "AGC_CFG2" },
1052 { .addr = CC1120_AGC_CFG1, .name = "AGC_CFG1" },
1053 { .addr = CC1120_AGC_CFG0, .name = "AGC_CFG0" },
1054 { .addr = CC1120_FIFO_CFG, .name = "FIFO_CFG" },
1055 { .addr = CC1120_DEV_ADDR, .name = "DEV_ADDR" },
1056 { .addr = CC1120_SETTLING_CFG, .name = "SETTLING_CFG" },
1057 { .addr = CC1120_FS_CFG, .name = "FS_CFG" },
1058 { .addr = CC1120_WOR_CFG1, .name = "WOR_CFG1" },
1059 { .addr = CC1120_WOR_CFG0, .name = "WOR_CFG0" },
1060 { .addr = CC1120_WOR_EVENT0_MSB, .name = "WOR_EVENT0_MSB" },
1061 { .addr = CC1120_WOR_EVENT0_LSB, .name = "WOR_EVENT0_LSB" },
1062 { .addr = CC1120_PKT_CFG2, .name = "PKT_CFG2" },
1063 { .addr = CC1120_PKT_CFG1, .name = "PKT_CFG1" },
1064 { .addr = CC1120_PKT_CFG0, .name = "PKT_CFG0" },
1065 { .addr = CC1120_RFEND_CFG1, .name = "RFEND_CFG1" },
1066 { .addr = CC1120_RFEND_CFG0, .name = "RFEND_CFG0" },
1067 { .addr = CC1120_PA_CFG2, .name = "PA_CFG2" },
1068 { .addr = CC1120_PA_CFG1, .name = "PA_CFG1" },
1069 { .addr = CC1120_PA_CFG0, .name = "PA_CFG0" },
1070 { .addr = CC1120_PKT_LEN, .name = "PKT_LEN" },
1071 { .addr = CC1120_IF_MIX_CFG, .name = "IF_MIX_CFG" },
1072 { .addr = CC1120_FREQOFF_CFG, .name = "FREQOFF_CFG" },
1073 { .addr = CC1120_TOC_CFG, .name = "TOC_CFG" },
1074 { .addr = CC1120_MARC_SPARE, .name = "MARC_SPARE" },
1075 { .addr = CC1120_ECG_CFG, .name = "ECG_CFG" },
1076 { .addr = CC1120_SOFT_TX_DATA_CFG, .name = "SOFT_TX_DATA_CFG" },
1077 { .addr = CC1120_EXT_CTRL, .name = "EXT_CTRL" },
1078 { .addr = CC1120_RCCAL_FINE, .name = "RCCAL_FINE" },
1079 { .addr = CC1120_RCCAL_COARSE, .name = "RCCAL_COARSE" },
1080 { .addr = CC1120_RCCAL_OFFSET, .name = "RCCAL_OFFSET" },
1081 { .addr = CC1120_FREQOFF1, .name = "FREQOFF1" },
1082 { .addr = CC1120_FREQOFF0, .name = "FREQOFF0" },
1083 { .addr = CC1120_FREQ2, .name = "FREQ2" },
1084 { .addr = CC1120_FREQ1, .name = "FREQ1" },
1085 { .addr = CC1120_FREQ0, .name = "FREQ0" },
1086 { .addr = CC1120_IF_ADC2, .name = "IF_ADC2" },
1087 { .addr = CC1120_IF_ADC1, .name = "IF_ADC1" },
1088 { .addr = CC1120_IF_ADC0, .name = "IF_ADC0" },
1089 { .addr = CC1120_FS_DIG1, .name = "FS_DIG1" },
1090 { .addr = CC1120_FS_DIG0, .name = "FS_DIG0" },
1091 { .addr = CC1120_FS_CAL3, .name = "FS_CAL3" },
1092 { .addr = CC1120_FS_CAL2, .name = "FS_CAL2" },
1093 { .addr = CC1120_FS_CAL1, .name = "FS_CAL1" },
1094 { .addr = CC1120_FS_CAL0, .name = "FS_CAL0" },
1095 { .addr = CC1120_FS_CHP, .name = "FS_CHP" },
1096 { .addr = CC1120_FS_DIVTWO, .name = "FS_DIVTWO" },
1097 { .addr = CC1120_FS_DSM1, .name = "FS_DSM1" },
1098 { .addr = CC1120_FS_DSM0, .name = "FS_DSM0" },
1099 { .addr = CC1120_FS_DVC1, .name = "FS_DVC1" },
1100 { .addr = CC1120_FS_DVC0, .name = "FS_DVC0" },
1101 { .addr = CC1120_FS_LBI, .name = "FS_LBI" },
1102 { .addr = CC1120_FS_PFD, .name = "FS_PFD" },
1103 { .addr = CC1120_FS_PRE, .name = "FS_PRE" },
1104 { .addr = CC1120_FS_REG_DIV_CML, .name = "FS_REG_DIV_CML" },
1105 { .addr = CC1120_FS_SPARE, .name = "FS_SPARE" },
1106 { .addr = CC1120_FS_VCO4, .name = "FS_VCO4" },
1107 { .addr = CC1120_FS_VCO3, .name = "FS_VCO3" },
1108 { .addr = CC1120_FS_VCO2, .name = "FS_VCO2" },
1109 { .addr = CC1120_FS_VCO1, .name = "FS_VCO1" },
1110 { .addr = CC1120_FS_VCO0, .name = "FS_VCO0" },
1111 { .addr = CC1120_GBIAS6, .name = "GBIAS6" },
1112 { .addr = CC1120_GBIAS5, .name = "GBIAS5" },
1113 { .addr = CC1120_GBIAS4, .name = "GBIAS4" },
1114 { .addr = CC1120_GBIAS3, .name = "GBIAS3" },
1115 { .addr = CC1120_GBIAS2, .name = "GBIAS2" },
1116 { .addr = CC1120_GBIAS1, .name = "GBIAS1" },
1117 { .addr = CC1120_GBIAS0, .name = "GBIAS0" },
1118 { .addr = CC1120_IFAMP, .name = "IFAMP" },
1119 { .addr = CC1120_LNA, .name = "LNA" },
1120 { .addr = CC1120_RXMIX, .name = "RXMIX" },
1121 { .addr = CC1120_XOSC5, .name = "XOSC5" },
1122 { .addr = CC1120_XOSC4, .name = "XOSC4" },
1123 { .addr = CC1120_XOSC3, .name = "XOSC3" },
1124 { .addr = CC1120_XOSC2, .name = "XOSC2" },
1125 { .addr = CC1120_XOSC1, .name = "XOSC1" },
1126 { .addr = CC1120_XOSC0, .name = "XOSC0" },
1127 { .addr = CC1120_ANALOG_SPARE, .name = "ANALOG_SPARE" },
1128 { .addr = CC1120_PA_CFG3, .name = "PA_CFG3" },
1129 { .addr = CC1120_WOR_TIME1, .name = "WOR_TIME1" },
1130 { .addr = CC1120_WOR_TIME0, .name = "WOR_TIME0" },
1131 { .addr = CC1120_WOR_CAPTURE1, .name = "WOR_CAPTURE1" },
1132 { .addr = CC1120_WOR_CAPTURE0, .name = "WOR_CAPTURE0" },
1133 { .addr = CC1120_BIST, .name = "BIST" },
1134 { .addr = CC1120_DCFILTOFFSET_I1, .name = "DCFILTOFFSET_I1" },
1135 { .addr = CC1120_DCFILTOFFSET_I0, .name = "DCFILTOFFSET_I0" },
1136 { .addr = CC1120_DCFILTOFFSET_Q1, .name = "DCFILTOFFSET_Q1" },
1137 { .addr = CC1120_DCFILTOFFSET_Q0, .name = "DCFILTOFFSET_Q0" },
1138 { .addr = CC1120_IQIE_I1, .name = "IQIE_I1" },
1139 { .addr = CC1120_IQIE_I0, .name = "IQIE_I0" },
1140 { .addr = CC1120_IQIE_Q1, .name = "IQIE_Q1" },
1141 { .addr = CC1120_IQIE_Q0, .name = "IQIE_Q0" },
1142 { .addr = CC1120_RSSI1, .name = "RSSI1" },
1143 { .addr = CC1120_RSSI0, .name = "RSSI0" },
1144 { .addr = CC1120_MARCSTATE, .name = "MARCSTATE" },
1145 { .addr = CC1120_LQI_VAL, .name = "LQI_VAL" },
1146 { .addr = CC1120_PQT_SYNC_ERR, .name = "PQT_SYNC_ERR" },
1147 { .addr = CC1120_DEM_STATUS, .name = "DEM_STATUS" },
1148 { .addr = CC1120_FREQOFF_EST1, .name = "FREQOFF_EST1" },
1149 { .addr = CC1120_FREQOFF_EST0, .name = "FREQOFF_EST0" },
1150 { .addr = CC1120_AGC_GAIN3, .name = "AGC_GAIN3" },
1151 { .addr = CC1120_AGC_GAIN2, .name = "AGC_GAIN2" },
1152 { .addr = CC1120_AGC_GAIN1, .name = "AGC_GAIN1" },
1153 { .addr = CC1120_AGC_GAIN0, .name = "AGC_GAIN0" },
1154 { .addr = CC1120_SOFT_RX_DATA_OUT, .name = "SOFT_RX_DATA_OUT" },
1155 { .addr = CC1120_SOFT_TX_DATA_IN, .name = "SOFT_TX_DATA_IN" },
1156 { .addr = CC1120_ASK_SOFT_RX_DATA, .name = "ASK_SOFT_RX_DATA" },
1157 { .addr = CC1120_RNDGEN, .name = "RNDGEN" },
1158 { .addr = CC1120_MAGN2, .name = "MAGN2" },
1159 { .addr = CC1120_MAGN1, .name = "MAGN1" },
1160 { .addr = CC1120_MAGN0, .name = "MAGN0" },
1161 { .addr = CC1120_ANG1, .name = "ANG1" },
1162 { .addr = CC1120_ANG0, .name = "ANG0" },
1163 { .addr = CC1120_CHFILT_I2, .name = "CHFILT_I2" },
1164 { .addr = CC1120_CHFILT_I1, .name = "CHFILT_I1" },
1165 { .addr = CC1120_CHFILT_I0, .name = "CHFILT_I0" },
1166 { .addr = CC1120_CHFILT_Q2, .name = "CHFILT_Q2" },
1167 { .addr = CC1120_CHFILT_Q1, .name = "CHFILT_Q1" },
1168 { .addr = CC1120_CHFILT_Q0, .name = "CHFILT_Q0" },
1169 { .addr = CC1120_GPIO_STATUS, .name = "GPIO_STATUS" },
1170 { .addr = CC1120_FSCAL_CTRL, .name = "FSCAL_CTRL" },
1171 { .addr = CC1120_PHASE_ADJUST, .name = "PHASE_ADJUST" },
1172 { .addr = CC1120_PARTNUMBER, .name = "PARTNUMBER" },
1173 { .addr = CC1120_PARTVERSION, .name = "PARTVERSION" },
1174 { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1175 { .addr = CC1120_RX_STATUS, .name = "RX_STATUS" },
1176 { .addr = CC1120_TX_STATUS, .name = "TX_STATUS" },
1177 { .addr = CC1120_MARC_STATUS1, .name = "MARC_STATUS1" },
1178 { .addr = CC1120_MARC_STATUS0, .name = "MARC_STATUS0" },
1179 { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1180 { .addr = CC1120_FSRF_TEST, .name = "FSRF_TEST" },
1181 { .addr = CC1120_PRE_TEST, .name = "PRE_TEST" },
1182 { .addr = CC1120_PRE_OVR, .name = "PRE_OVR" },
1183 { .addr = CC1120_ADC_TEST, .name = "ADC_TEST" },
1184 { .addr = CC1120_DVC_TEST, .name = "DVC_TEST" },
1185 { .addr = CC1120_ATEST, .name = "ATEST" },
1186 { .addr = CC1120_ATEST_LVDS, .name = "ATEST_LVDS" },
1187 { .addr = CC1120_ATEST_MODE, .name = "ATEST_MODE" },
1188 { .addr = CC1120_XOSC_TEST1, .name = "XOSC_TEST1" },
1189 { .addr = CC1120_XOSC_TEST0, .name = "XOSC_TEST0" },
1190 { .addr = CC1120_RXFIRST, .name = "RXFIRST" },
1191 { .addr = CC1120_TXFIRST, .name = "TXFIRST" },
1192 { .addr = CC1120_RXLAST, .name = "RXLAST" },
1193 { .addr = CC1120_TXLAST, .name = "TXLAST" },
1194 { .addr = CC1120_NUM_TXBYTES, .name = "NUM_TXBYTES" },
1195 { .addr = CC1120_NUM_RXBYTES, .name = "NUM_RXBYTES" },
1196 { .addr = CC1120_FIFO_NUM_TXBYTES, .name = "FIFO_NUM_TXBYTES" },
1197 { .addr = CC1120_FIFO_NUM_RXBYTES, .name = "FIFO_NUM_RXBYTES" },
1200 #define AO_NUM_CC1120_REG (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1202 static void ao_radio_show(void) {
1203 uint8_t status = ao_radio_status();
1207 status = ao_radio_status();
1208 printf ("Status: %02x\n", status);
1209 printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1210 printf ("STATE: %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1211 printf ("MARC: %02x\n", ao_radio_get_marc_status());
1213 for (i = 0; i < AO_NUM_CC1120_REG; i++)
1214 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1218 static void ao_radio_beep(void) {
1222 static void ao_radio_packet(void) {
1223 static const uint8_t packet[] = {
1225 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1226 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1227 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1228 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1234 ao_radio_send(packet, sizeof (packet));
1238 ao_radio_test_recv()
1243 if (ao_radio_recv(bytes, 34)) {
1244 if (bytes[33] & 0x80)
1248 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1249 for (b = 0; b < 32; b++)
1250 printf (" %02x", bytes[b]);
1256 #include <ao_aprs.h>
1261 ao_packet_slave_stop();
1268 static const struct ao_cmds ao_radio_cmds[] = {
1269 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
1272 { ao_radio_aprs, "G\0Send APRS packet" },
1274 { ao_radio_show, "R\0Show CC1120 status" },
1275 { ao_radio_beep, "b\0Emit an RDF beacon" },
1276 { ao_radio_packet, "p\0Send a test packet" },
1277 { ao_radio_test_recv, "q\0Recv a test packet" },
1287 ao_radio_configured = 0;
1288 ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1291 AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1292 for (i = 0; i < 10000; i++) {
1293 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1296 AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1298 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1301 /* Enable the EXTI interrupt for the appropriate pin */
1302 ao_enable_port(AO_CC1120_INT_PORT);
1303 ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1304 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1307 /* Enable the hacked up GPIO3 pin */
1308 ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
1309 ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
1310 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1311 ao_radio_mcu_wakeup_isr);
1313 ao_cmd_register(&ao_radio_cmds[0]);