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 38360 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 5
387 #define APRS_DRATE_M 25166
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)
436 #define AO_RADIO_MODE_APRS_FINISH (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED)
439 ao_radio_set_mode(uint16_t new_mode)
444 if (new_mode == ao_radio_mode)
447 changes = new_mode & (~ao_radio_mode);
448 if (changes & AO_RADIO_MODE_BITS_PACKET)
449 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
450 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
452 if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
453 for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2)
454 ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
456 if (changes & AO_RADIO_MODE_BITS_TX_BUF)
457 ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
459 if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
460 ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
462 if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
463 for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
464 ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]);
466 if (changes & AO_RADIO_MODE_BITS_RDF)
467 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
468 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
470 if (changes & AO_RADIO_MODE_BITS_APRS)
471 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
472 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
474 if (changes & AO_RADIO_MODE_BITS_INFINITE)
475 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
477 if (changes & AO_RADIO_MODE_BITS_FIXED)
478 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
480 ao_radio_mode = new_mode;
483 static const uint16_t radio_setup[] = {
484 #include "ao_cc1120_CC1120.h"
487 static uint8_t ao_radio_configured = 0;
494 ao_radio_strobe(CC1120_SRES);
496 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
497 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
503 ao_radio_configured = 1;
507 ao_radio_set_len(uint8_t len)
509 static uint8_t last_len;
511 if (len != last_len) {
512 ao_radio_reg_write(CC1120_PKT_LEN, len);
518 ao_radio_get(uint8_t len)
520 static uint32_t last_radio_setting;
522 ao_mutex_get(&ao_radio_mutex);
523 if (!ao_radio_configured)
525 if (ao_config.radio_setting != last_radio_setting) {
526 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
527 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
528 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
529 last_radio_setting = ao_config.radio_setting;
531 ao_radio_set_len(len);
534 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
537 ao_rdf_start(uint8_t len)
542 ao_radio_set_mode(AO_RADIO_MODE_RDF);
552 ao_arch_block_interrupts();
553 while (!ao_radio_wake && !ao_radio_abort)
554 ao_sleep(&ao_radio_wake);
555 ao_arch_release_interrupts();
564 ao_rdf_start(AO_RADIO_RDF_LEN);
566 ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
572 ao_radio_continuity(uint8_t c)
577 ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
579 status = ao_radio_fifo_write_start();
580 for (i = 0; i < 3; i++) {
581 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
583 ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN);
585 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN);
587 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
588 status = ao_radio_fifo_write_stop(status);
594 ao_radio_rdf_abort(void)
597 ao_wakeup(&ao_radio_wake);
601 ao_radio_test_cmd(void)
604 static uint8_t radio_on;
606 if (ao_cmd_lex_c != '\n') {
608 mode = (uint8_t) ao_cmd_lex_u32;
611 if ((mode & 2) && !radio_on) {
613 ao_monitor_disable();
616 ao_packet_slave_stop();
619 ao_radio_strobe(CC1120_STX);
622 for (t = 0; t < 10; t++) {
623 printf ("status: %02x\n", ao_radio_status());
624 ao_delay(AO_MS_TO_TICKS(100));
631 printf ("Hit a character to stop..."); flush();
635 if ((mode & 1) && radio_on) {
646 ao_radio_wait_tx(uint8_t wait_fifo)
648 uint8_t fifo_space = 0;
652 ao_arch_block_interrupts();
653 while (!ao_radio_wake)
654 ao_sleep(&ao_radio_wake);
655 ao_arch_release_interrupts();
658 fifo_space = ao_radio_tx_fifo_space();
659 } while (!fifo_space);
663 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
666 ao_radio_send(const void *d, uint8_t size)
669 uint8_t *e = tx_data;
675 encode_len = ao_fec_encode(d, size, tx_data);
677 ao_radio_get(encode_len);
680 fifo_space = CC1120_FIFO_SIZE;
682 this_len = encode_len;
684 if (this_len > fifo_space) {
685 this_len = fifo_space;
686 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
688 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
691 ao_radio_fifo_write(e, this_len);
693 encode_len -= this_len;
699 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
702 fifo_space = ao_radio_wait_tx(encode_len != 0);
707 #define AO_RADIO_LOTS 64
710 ao_radio_send_lots(ao_radio_fill_func fill)
712 uint8_t buf[AO_RADIO_LOTS], *b;
720 fifo_space = CC1120_FIFO_SIZE;
722 cnt = (*fill)(buf, sizeof(buf));
729 ao_radio_set_len(total & 0xff);
730 ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
732 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
735 uint8_t this_len = cnt;
736 if (this_len > fifo_space)
737 this_len = fifo_space;
738 ao_radio_fifo_write(b, this_len);
745 fifo_space = ao_radio_wait_tx(!done || cnt);
751 static uint8_t rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
752 static uint16_t rx_data_count;
753 static uint16_t rx_data_consumed;
754 static uint16_t rx_data_cur;
755 static uint8_t rx_ignore;
756 static uint8_t rx_waiting;
759 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
761 uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
763 #include <ao_profile.h>
767 ao_radio_rx_isr(void)
773 if (rx_ignore == 0) {
774 if (rx_data_cur >= rx_data_count)
775 ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
777 rx_data[rx_data_cur++] = d;
778 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
781 rx_packet_tick = ao_profile_tick();
782 if (rx_data_cur < rx_data_count)
786 ao_wakeup(&ao_radio_wake);
794 ao_radio_rx_wait(void)
796 ao_arch_block_interrupts();
798 while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
800 ao_sleep(&ao_radio_wake);
803 ao_arch_release_interrupts();
806 rx_data_consumed += AO_FEC_DECODE_BLOCK;
808 return rx_data_cur - rx_data_consumed;
810 return AO_FEC_DECODE_BLOCK;
814 ao_radio_recv(__xdata void *d, uint8_t size)
820 static int been_here = 0;
822 size -= 2; /* status bytes */
823 if (size > AO_RADIO_MAX_RECV) {
824 ao_delay(AO_SEC_TO_TICKS(1));
828 rx_start_tick = ao_profile_tick();
831 len = size + 2; /* CRC bytes */
832 len += 1 + ~(len & 1); /* 1 or two pad bytes */
833 len *= 2; /* 1/2 rate convolution */
834 rx_data_count = len * 8; /* bytes to bits */
836 rx_data_consumed = 0;
840 ao_radio_in_recv = 1;
841 /* configure interrupt pin */
843 ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
852 ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
853 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
855 ao_radio_strobe(CC1120_SRX);
857 ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
859 ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
861 ao_radio_burst_read_stop();
863 ao_radio_strobe(CC1120_SIDLE);
865 /* Convert from 'real' rssi to cc1111-style values */
867 rssi = AO_RADIO_FROM_RSSI(ao_radio_reg_read(CC1120_RSSI1));
871 /* Store the received RSSI value; the crc-OK byte is already done */
873 ((uint8_t *) d)[size] = (uint8_t) rssi;
875 ao_radio_in_recv = 0;
881 rx_last_done_tick = rx_done_tick;
882 rx_done_tick = ao_profile_tick();
884 ao_rx_start_tick = rx_start_tick;
885 ao_rx_packet_tick = rx_packet_tick;
886 ao_rx_done_tick = rx_done_tick;
887 ao_rx_last_done_tick = rx_last_done_tick;
895 static char *cc1120_state_name[] = {
896 [CC1120_STATUS_STATE_IDLE] = "IDLE",
897 [CC1120_STATUS_STATE_RX] = "RX",
898 [CC1120_STATUS_STATE_TX] = "TX",
899 [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
900 [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
901 [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
902 [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
903 [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
906 struct ao_cc1120_reg {
911 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
912 { .addr = CC1120_IOCFG3, .name = "IOCFG3" },
913 { .addr = CC1120_IOCFG2, .name = "IOCFG2" },
914 { .addr = CC1120_IOCFG1, .name = "IOCFG1" },
915 { .addr = CC1120_IOCFG0, .name = "IOCFG0" },
916 { .addr = CC1120_SYNC3, .name = "SYNC3" },
917 { .addr = CC1120_SYNC2, .name = "SYNC2" },
918 { .addr = CC1120_SYNC1, .name = "SYNC1" },
919 { .addr = CC1120_SYNC0, .name = "SYNC0" },
920 { .addr = CC1120_SYNC_CFG1, .name = "SYNC_CFG1" },
921 { .addr = CC1120_SYNC_CFG0, .name = "SYNC_CFG0" },
922 { .addr = CC1120_DEVIATION_M, .name = "DEVIATION_M" },
923 { .addr = CC1120_MODCFG_DEV_E, .name = "MODCFG_DEV_E" },
924 { .addr = CC1120_DCFILT_CFG, .name = "DCFILT_CFG" },
925 { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
926 { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
927 { .addr = CC1120_FREQ_IF_CFG, .name = "FREQ_IF_CFG" },
928 { .addr = CC1120_IQIC, .name = "IQIC" },
929 { .addr = CC1120_CHAN_BW, .name = "CHAN_BW" },
930 { .addr = CC1120_MDMCFG1, .name = "MDMCFG1" },
931 { .addr = CC1120_MDMCFG0, .name = "MDMCFG0" },
932 { .addr = CC1120_DRATE2, .name = "DRATE2" },
933 { .addr = CC1120_DRATE1, .name = "DRATE1" },
934 { .addr = CC1120_DRATE0, .name = "DRATE0" },
935 { .addr = CC1120_AGC_REF, .name = "AGC_REF" },
936 { .addr = CC1120_AGC_CS_THR, .name = "AGC_CS_THR" },
937 { .addr = CC1120_AGC_GAIN_ADJUST, .name = "AGC_GAIN_ADJUST" },
938 { .addr = CC1120_AGC_CFG3, .name = "AGC_CFG3" },
939 { .addr = CC1120_AGC_CFG2, .name = "AGC_CFG2" },
940 { .addr = CC1120_AGC_CFG1, .name = "AGC_CFG1" },
941 { .addr = CC1120_AGC_CFG0, .name = "AGC_CFG0" },
942 { .addr = CC1120_FIFO_CFG, .name = "FIFO_CFG" },
943 { .addr = CC1120_DEV_ADDR, .name = "DEV_ADDR" },
944 { .addr = CC1120_SETTLING_CFG, .name = "SETTLING_CFG" },
945 { .addr = CC1120_FS_CFG, .name = "FS_CFG" },
946 { .addr = CC1120_WOR_CFG1, .name = "WOR_CFG1" },
947 { .addr = CC1120_WOR_CFG0, .name = "WOR_CFG0" },
948 { .addr = CC1120_WOR_EVENT0_MSB, .name = "WOR_EVENT0_MSB" },
949 { .addr = CC1120_WOR_EVENT0_LSB, .name = "WOR_EVENT0_LSB" },
950 { .addr = CC1120_PKT_CFG2, .name = "PKT_CFG2" },
951 { .addr = CC1120_PKT_CFG1, .name = "PKT_CFG1" },
952 { .addr = CC1120_PKT_CFG0, .name = "PKT_CFG0" },
953 { .addr = CC1120_RFEND_CFG1, .name = "RFEND_CFG1" },
954 { .addr = CC1120_RFEND_CFG0, .name = "RFEND_CFG0" },
955 { .addr = CC1120_PA_CFG2, .name = "PA_CFG2" },
956 { .addr = CC1120_PA_CFG1, .name = "PA_CFG1" },
957 { .addr = CC1120_PA_CFG0, .name = "PA_CFG0" },
958 { .addr = CC1120_PKT_LEN, .name = "PKT_LEN" },
959 { .addr = CC1120_IF_MIX_CFG, .name = "IF_MIX_CFG" },
960 { .addr = CC1120_FREQOFF_CFG, .name = "FREQOFF_CFG" },
961 { .addr = CC1120_TOC_CFG, .name = "TOC_CFG" },
962 { .addr = CC1120_MARC_SPARE, .name = "MARC_SPARE" },
963 { .addr = CC1120_ECG_CFG, .name = "ECG_CFG" },
964 { .addr = CC1120_SOFT_TX_DATA_CFG, .name = "SOFT_TX_DATA_CFG" },
965 { .addr = CC1120_EXT_CTRL, .name = "EXT_CTRL" },
966 { .addr = CC1120_RCCAL_FINE, .name = "RCCAL_FINE" },
967 { .addr = CC1120_RCCAL_COARSE, .name = "RCCAL_COARSE" },
968 { .addr = CC1120_RCCAL_OFFSET, .name = "RCCAL_OFFSET" },
969 { .addr = CC1120_FREQOFF1, .name = "FREQOFF1" },
970 { .addr = CC1120_FREQOFF0, .name = "FREQOFF0" },
971 { .addr = CC1120_FREQ2, .name = "FREQ2" },
972 { .addr = CC1120_FREQ1, .name = "FREQ1" },
973 { .addr = CC1120_FREQ0, .name = "FREQ0" },
974 { .addr = CC1120_IF_ADC2, .name = "IF_ADC2" },
975 { .addr = CC1120_IF_ADC1, .name = "IF_ADC1" },
976 { .addr = CC1120_IF_ADC0, .name = "IF_ADC0" },
977 { .addr = CC1120_FS_DIG1, .name = "FS_DIG1" },
978 { .addr = CC1120_FS_DIG0, .name = "FS_DIG0" },
979 { .addr = CC1120_FS_CAL3, .name = "FS_CAL3" },
980 { .addr = CC1120_FS_CAL2, .name = "FS_CAL2" },
981 { .addr = CC1120_FS_CAL1, .name = "FS_CAL1" },
982 { .addr = CC1120_FS_CAL0, .name = "FS_CAL0" },
983 { .addr = CC1120_FS_CHP, .name = "FS_CHP" },
984 { .addr = CC1120_FS_DIVTWO, .name = "FS_DIVTWO" },
985 { .addr = CC1120_FS_DSM1, .name = "FS_DSM1" },
986 { .addr = CC1120_FS_DSM0, .name = "FS_DSM0" },
987 { .addr = CC1120_FS_DVC1, .name = "FS_DVC1" },
988 { .addr = CC1120_FS_DVC0, .name = "FS_DVC0" },
989 { .addr = CC1120_FS_LBI, .name = "FS_LBI" },
990 { .addr = CC1120_FS_PFD, .name = "FS_PFD" },
991 { .addr = CC1120_FS_PRE, .name = "FS_PRE" },
992 { .addr = CC1120_FS_REG_DIV_CML, .name = "FS_REG_DIV_CML" },
993 { .addr = CC1120_FS_SPARE, .name = "FS_SPARE" },
994 { .addr = CC1120_FS_VCO4, .name = "FS_VCO4" },
995 { .addr = CC1120_FS_VCO3, .name = "FS_VCO3" },
996 { .addr = CC1120_FS_VCO2, .name = "FS_VCO2" },
997 { .addr = CC1120_FS_VCO1, .name = "FS_VCO1" },
998 { .addr = CC1120_FS_VCO0, .name = "FS_VCO0" },
999 { .addr = CC1120_GBIAS6, .name = "GBIAS6" },
1000 { .addr = CC1120_GBIAS5, .name = "GBIAS5" },
1001 { .addr = CC1120_GBIAS4, .name = "GBIAS4" },
1002 { .addr = CC1120_GBIAS3, .name = "GBIAS3" },
1003 { .addr = CC1120_GBIAS2, .name = "GBIAS2" },
1004 { .addr = CC1120_GBIAS1, .name = "GBIAS1" },
1005 { .addr = CC1120_GBIAS0, .name = "GBIAS0" },
1006 { .addr = CC1120_IFAMP, .name = "IFAMP" },
1007 { .addr = CC1120_LNA, .name = "LNA" },
1008 { .addr = CC1120_RXMIX, .name = "RXMIX" },
1009 { .addr = CC1120_XOSC5, .name = "XOSC5" },
1010 { .addr = CC1120_XOSC4, .name = "XOSC4" },
1011 { .addr = CC1120_XOSC3, .name = "XOSC3" },
1012 { .addr = CC1120_XOSC2, .name = "XOSC2" },
1013 { .addr = CC1120_XOSC1, .name = "XOSC1" },
1014 { .addr = CC1120_XOSC0, .name = "XOSC0" },
1015 { .addr = CC1120_ANALOG_SPARE, .name = "ANALOG_SPARE" },
1016 { .addr = CC1120_PA_CFG3, .name = "PA_CFG3" },
1017 { .addr = CC1120_WOR_TIME1, .name = "WOR_TIME1" },
1018 { .addr = CC1120_WOR_TIME0, .name = "WOR_TIME0" },
1019 { .addr = CC1120_WOR_CAPTURE1, .name = "WOR_CAPTURE1" },
1020 { .addr = CC1120_WOR_CAPTURE0, .name = "WOR_CAPTURE0" },
1021 { .addr = CC1120_BIST, .name = "BIST" },
1022 { .addr = CC1120_DCFILTOFFSET_I1, .name = "DCFILTOFFSET_I1" },
1023 { .addr = CC1120_DCFILTOFFSET_I0, .name = "DCFILTOFFSET_I0" },
1024 { .addr = CC1120_DCFILTOFFSET_Q1, .name = "DCFILTOFFSET_Q1" },
1025 { .addr = CC1120_DCFILTOFFSET_Q0, .name = "DCFILTOFFSET_Q0" },
1026 { .addr = CC1120_IQIE_I1, .name = "IQIE_I1" },
1027 { .addr = CC1120_IQIE_I0, .name = "IQIE_I0" },
1028 { .addr = CC1120_IQIE_Q1, .name = "IQIE_Q1" },
1029 { .addr = CC1120_IQIE_Q0, .name = "IQIE_Q0" },
1030 { .addr = CC1120_RSSI1, .name = "RSSI1" },
1031 { .addr = CC1120_RSSI0, .name = "RSSI0" },
1032 { .addr = CC1120_MARCSTATE, .name = "MARCSTATE" },
1033 { .addr = CC1120_LQI_VAL, .name = "LQI_VAL" },
1034 { .addr = CC1120_PQT_SYNC_ERR, .name = "PQT_SYNC_ERR" },
1035 { .addr = CC1120_DEM_STATUS, .name = "DEM_STATUS" },
1036 { .addr = CC1120_FREQOFF_EST1, .name = "FREQOFF_EST1" },
1037 { .addr = CC1120_FREQOFF_EST0, .name = "FREQOFF_EST0" },
1038 { .addr = CC1120_AGC_GAIN3, .name = "AGC_GAIN3" },
1039 { .addr = CC1120_AGC_GAIN2, .name = "AGC_GAIN2" },
1040 { .addr = CC1120_AGC_GAIN1, .name = "AGC_GAIN1" },
1041 { .addr = CC1120_AGC_GAIN0, .name = "AGC_GAIN0" },
1042 { .addr = CC1120_SOFT_RX_DATA_OUT, .name = "SOFT_RX_DATA_OUT" },
1043 { .addr = CC1120_SOFT_TX_DATA_IN, .name = "SOFT_TX_DATA_IN" },
1044 { .addr = CC1120_ASK_SOFT_RX_DATA, .name = "ASK_SOFT_RX_DATA" },
1045 { .addr = CC1120_RNDGEN, .name = "RNDGEN" },
1046 { .addr = CC1120_MAGN2, .name = "MAGN2" },
1047 { .addr = CC1120_MAGN1, .name = "MAGN1" },
1048 { .addr = CC1120_MAGN0, .name = "MAGN0" },
1049 { .addr = CC1120_ANG1, .name = "ANG1" },
1050 { .addr = CC1120_ANG0, .name = "ANG0" },
1051 { .addr = CC1120_CHFILT_I2, .name = "CHFILT_I2" },
1052 { .addr = CC1120_CHFILT_I1, .name = "CHFILT_I1" },
1053 { .addr = CC1120_CHFILT_I0, .name = "CHFILT_I0" },
1054 { .addr = CC1120_CHFILT_Q2, .name = "CHFILT_Q2" },
1055 { .addr = CC1120_CHFILT_Q1, .name = "CHFILT_Q1" },
1056 { .addr = CC1120_CHFILT_Q0, .name = "CHFILT_Q0" },
1057 { .addr = CC1120_GPIO_STATUS, .name = "GPIO_STATUS" },
1058 { .addr = CC1120_FSCAL_CTRL, .name = "FSCAL_CTRL" },
1059 { .addr = CC1120_PHASE_ADJUST, .name = "PHASE_ADJUST" },
1060 { .addr = CC1120_PARTNUMBER, .name = "PARTNUMBER" },
1061 { .addr = CC1120_PARTVERSION, .name = "PARTVERSION" },
1062 { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1063 { .addr = CC1120_RX_STATUS, .name = "RX_STATUS" },
1064 { .addr = CC1120_TX_STATUS, .name = "TX_STATUS" },
1065 { .addr = CC1120_MARC_STATUS1, .name = "MARC_STATUS1" },
1066 { .addr = CC1120_MARC_STATUS0, .name = "MARC_STATUS0" },
1067 { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1068 { .addr = CC1120_FSRF_TEST, .name = "FSRF_TEST" },
1069 { .addr = CC1120_PRE_TEST, .name = "PRE_TEST" },
1070 { .addr = CC1120_PRE_OVR, .name = "PRE_OVR" },
1071 { .addr = CC1120_ADC_TEST, .name = "ADC_TEST" },
1072 { .addr = CC1120_DVC_TEST, .name = "DVC_TEST" },
1073 { .addr = CC1120_ATEST, .name = "ATEST" },
1074 { .addr = CC1120_ATEST_LVDS, .name = "ATEST_LVDS" },
1075 { .addr = CC1120_ATEST_MODE, .name = "ATEST_MODE" },
1076 { .addr = CC1120_XOSC_TEST1, .name = "XOSC_TEST1" },
1077 { .addr = CC1120_XOSC_TEST0, .name = "XOSC_TEST0" },
1078 { .addr = CC1120_RXFIRST, .name = "RXFIRST" },
1079 { .addr = CC1120_TXFIRST, .name = "TXFIRST" },
1080 { .addr = CC1120_RXLAST, .name = "RXLAST" },
1081 { .addr = CC1120_TXLAST, .name = "TXLAST" },
1082 { .addr = CC1120_NUM_TXBYTES, .name = "NUM_TXBYTES" },
1083 { .addr = CC1120_NUM_RXBYTES, .name = "NUM_RXBYTES" },
1084 { .addr = CC1120_FIFO_NUM_TXBYTES, .name = "FIFO_NUM_TXBYTES" },
1085 { .addr = CC1120_FIFO_NUM_RXBYTES, .name = "FIFO_NUM_RXBYTES" },
1088 #define AO_NUM_CC1120_REG (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1090 static void ao_radio_show(void) {
1091 uint8_t status = ao_radio_status();
1095 status = ao_radio_status();
1096 printf ("Status: %02x\n", status);
1097 printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1098 printf ("STATE: %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1099 printf ("MARC: %02x\n", ao_radio_marc_status());
1101 for (i = 0; i < AO_NUM_CC1120_REG; i++)
1102 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1106 static void ao_radio_beep(void) {
1107 ao_radio_rdf(RDF_PACKET_LEN);
1110 static void ao_radio_packet(void) {
1111 static const uint8_t packet[] = {
1113 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1114 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1115 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1116 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1122 ao_radio_send(packet, sizeof (packet));
1126 ao_radio_test_recv()
1131 if (ao_radio_recv(bytes, 34)) {
1132 if (bytes[33] & 0x80)
1136 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1137 for (b = 0; b < 32; b++)
1138 printf (" %02x", bytes[b]);
1145 static const struct ao_cmds ao_radio_cmds[] = {
1146 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
1148 { ao_radio_show, "R\0Show CC1120 status" },
1149 { ao_radio_beep, "b\0Emit an RDF beacon" },
1150 { ao_radio_packet, "p\0Send a test packet" },
1151 { ao_radio_test_recv, "q\0Recv a test packet" },
1161 ao_radio_configured = 0;
1162 ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1165 AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1166 for (i = 0; i < 10000; i++) {
1167 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1170 AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1172 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1175 /* Enable the EXTI interrupt for the appropriate pin */
1176 ao_enable_port(AO_CC1120_INT_PORT);
1177 ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1178 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1181 ao_cmd_register(&ao_radio_cmds[0]);