2 * Copyright © 2013 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; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 #include <ao_cc115l.h>
22 #include <ao_telemetry.h>
25 #define AO_RADIO_MAX_SEND sizeof (struct ao_telemetry_generic)
27 uint8_t ao_radio_mutex;
29 static uint8_t ao_radio_fifo; /* fifo drained interrupt received */
30 static uint8_t ao_radio_done; /* tx done interrupt received */
31 static uint8_t ao_radio_wake; /* sleep address for radio interrupts */
32 static uint8_t ao_radio_abort; /* radio operation should abort */
34 /* Debugging commands */
35 #define CC115L_DEBUG 0
38 #define CC115L_TRACE 0
42 #define AO_CC115L_SPI_SPEED ao_spi_speed(6500000) /* for back-to-back access */
44 #define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_CC115L_SPI_SPEED)
45 #define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)
46 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS)
47 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS)
48 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC115L_SPI_BUS)
49 #define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC115L_SPI_BUS)
51 struct ao_cc115l_reg {
58 static const struct ao_cc115l_reg ao_cc115l_reg[];
59 static const char *cc115l_state_name[];
61 enum ao_cc115l_trace_type {
69 struct ao_cc115l_trace {
70 enum ao_cc115l_trace_type type;
78 static struct ao_cc115l_trace trace[NUM_TRACE];
80 static int trace_disable;
82 static void trace_add(enum ao_cc115l_trace_type type, int16_t addr, int16_t value, const char *comment)
89 comment = ao_cc115l_reg[addr].name;
92 comment = cc115l_state_name[(value >> 4) & 0x7];
97 trace[trace_i].type = type;
98 trace[trace_i].addr = addr;
99 trace[trace_i].value = value;
100 trace[trace_i].comment = comment;
101 if (++trace_i == NUM_TRACE)
105 #define trace_add(t,a,v,c)
109 ao_radio_reg_read(uint8_t addr)
113 data[0] = ((1 << CC115L_READ) |
114 (0 << CC115L_BURST) |
117 ao_radio_spi_send(data, 1);
118 ao_radio_spi_recv(data, 1);
120 trace_add(trace_read, addr, data[0], NULL);
125 ao_radio_reg_write(uint8_t addr, uint8_t value)
129 trace_add(trace_write, addr, value, NULL);
130 data[0] = ((0 << CC115L_READ) |
131 (0 << CC115L_BURST) |
135 ao_radio_spi_send(data, 2);
141 ao_radio_burst_read_start (uint16_t addr)
145 data[0] = ((1 << CC115L_READ) |
146 (1 << CC115L_BURST) |
149 ao_radio_spi_send(data, 1);
153 ao_radio_burst_read_stop (void)
161 ao_radio_strobe(uint8_t addr)
166 ao_radio_duplex(&addr, &in, 1);
168 trace_add(trace_strobe, addr, in, NULL);
173 ao_radio_fifo_write_start(void)
175 uint8_t addr = ((0 << CC115L_READ) |
176 (1 << CC115L_BURST) |
181 ao_radio_duplex(&addr, &status, 1);
185 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
191 ao_radio_fifo_write(uint8_t *data, uint8_t len)
193 uint8_t status = ao_radio_fifo_write_start();
194 trace_add(trace_dma, CC115L_FIFO, len, NULL);
195 ao_radio_spi_send(data, len);
196 return ao_radio_fifo_write_stop(status);
200 ao_radio_tx_fifo_space(void)
202 return CC115L_FIFO_SIZE - (ao_radio_reg_read(CC115L_TXBYTES) & CC115L_TXBYTES_NUM_TX_BYTES_MASK);
207 ao_radio_status(void)
209 return ao_radio_strobe (CC115L_SNOP);
213 ao_radio_get_marcstate(void)
215 return ao_radio_reg_read(CC115L_MARCSTATE) & CC115L_MARCSTATE_MASK;
219 #define ao_radio_rdf_value 0x55
222 ao_radio_done_isr(void)
224 ao_exti_disable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
225 trace_add(trace_line, __LINE__, 0, "done_isr");
227 ao_wakeup(&ao_radio_wake);
231 ao_radio_fifo_isr(void)
233 ao_exti_disable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
234 trace_add(trace_line, __LINE__, 0, "fifo_isr");
236 ao_wakeup(&ao_radio_wake);
244 uint8_t state = ao_radio_strobe(CC115L_SIDLE);
245 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE)
247 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW)
248 ao_radio_strobe(CC115L_SFTX);
250 /* Flush any pending TX bytes */
251 ao_radio_strobe(CC115L_SFTX);
252 /* Make sure the RF calibration is current */
253 ao_radio_strobe(CC115L_SCAL);
259 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
261 * For 38400 baud, use 20.5kHz:
263 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz
265 * For 9600 baud, use 5.125kHz:
267 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 1) = 5157Hz
269 * For 2400 baud, use 1.5kHz:
271 * 26e6 / (2 ** 17) * (8 + 0) * (2 ** 0) = 1587Hz
274 #define PACKET_DEV_E_384 3
275 #define PACKET_DEV_M_384 5
277 #define PACKET_DEV_E_96 1
278 #define PACKET_DEV_M_96 5
280 #define PACKET_DEV_E_24 0
281 #define PACKET_DEV_M_24 0
284 * For our packet data:
286 * (256 + DATARATE_M) * 2 ** DATARATE_E
287 * Rdata = -------------------------------------- * fosc
292 * (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383
295 * DATARATE_E_384 = 10
299 #define PACKET_DRATE_M 131
301 #define PACKET_DRATE_E_384 10
302 #define PACKET_DRATE_E_96 8
303 #define PACKET_DRATE_E_24 6
305 static const struct {
308 } packet_rate_setup[] = {
309 [AO_RADIO_RATE_38400] = {
310 .mdmcfg4 = ((0xf << 4) |
311 (PACKET_DRATE_E_384 << CC115L_MDMCFG4_DRATE_E)),
312 .deviatn = ((PACKET_DEV_E_384 << CC115L_DEVIATN_DEVIATION_E) |
313 (PACKET_DEV_M_384 << CC115L_DEVIATN_DEVIATION_M)),
316 [AO_RADIO_RATE_9600] = {
317 .mdmcfg4 = ((0xf << 4) |
318 (PACKET_DRATE_E_96 << CC115L_MDMCFG4_DRATE_E)),
319 .deviatn = ((PACKET_DEV_E_96 << CC115L_DEVIATN_DEVIATION_E) |
320 (PACKET_DEV_M_96 << CC115L_DEVIATN_DEVIATION_M)),
323 [AO_RADIO_RATE_2400] = {
324 .mdmcfg4 = ((0xf << 4) |
325 (PACKET_DRATE_E_24 << CC115L_MDMCFG4_DRATE_E)),
326 .deviatn = ((PACKET_DEV_E_24 << CC115L_DEVIATN_DEVIATION_E) |
327 (PACKET_DEV_M_24 << CC115L_DEVIATN_DEVIATION_M)),
331 static const uint16_t packet_setup[] = {
332 CC115L_MDMCFG3, (PACKET_DRATE_M),
333 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
334 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
335 (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),
340 * RDF deviation is 3kHz
342 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
344 * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
351 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
353 * (256 + DATARATE_M) * 2 ** DATARATE_E
354 * Rdata = -------------------------------------- * fosc
357 * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
362 #define RDF_DRATE_E 6
363 #define RDF_DRATE_M 67
365 static const uint16_t rdf_setup[] = {
366 CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
367 (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
368 CC115L_MDMCFG4, ((0xf << 4) |
369 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
370 CC115L_MDMCFG3, (RDF_DRATE_M),
371 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
372 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
373 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
377 * APRS deviation is 3kHz
379 * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
386 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
388 * (256 + DATARATE_M) * 2 ** DATARATE_E
389 * Rdata = -------------------------------------- * fosc
392 * (256 + 131) * (2 ** 8) / (2**28) * 26e6 = 9596
398 #define APRS_DRATE_E 8
399 #define APRS_DRATE_M 131
401 static const uint16_t aprs_setup[] = {
402 CC115L_DEVIATN, ((APRS_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
403 (APRS_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
404 CC115L_MDMCFG4, ((0xf << 4) |
405 (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
406 CC115L_MDMCFG3, (APRS_DRATE_M),
407 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
408 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
409 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
412 #define AO_PKTCTRL0_INFINITE ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
413 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
414 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
415 #define AO_PKTCTRL0_FIXED ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
416 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
417 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
419 static uint16_t ao_radio_mode;
423 * These set the data rate and modulation parameters
425 #define AO_RADIO_MODE_BITS_PACKET_TX 1
426 #define AO_RADIO_MODE_BITS_RDF 2
427 #define AO_RADIO_MODE_BITS_APRS 4
430 * Flips between infinite packet mode and fixed packet mode;
431 * we use infinite mode until the sender gives us the
434 #define AO_RADIO_MODE_BITS_INFINITE 40
435 #define AO_RADIO_MODE_BITS_FIXED 80
437 #define AO_RADIO_MODE_NONE 0
439 #define AO_RADIO_MODE_RDF AO_RADIO_MODE_BITS_RDF
440 #define AO_RADIO_MODE_PACKET_TX AO_RADIO_MODE_BITS_PACKET_TX
441 #define AO_RADIO_MODE_APRS AO_RADIO_MODE_BITS_APRS
444 ao_radio_set_mode(uint16_t new_mode)
449 if (new_mode == ao_radio_mode)
452 changes = new_mode & (~ao_radio_mode);
453 if (changes & AO_RADIO_MODE_BITS_PACKET_TX) {
454 ao_radio_reg_write(CC115L_MDMCFG4, packet_rate_setup[ao_config.radio_rate].mdmcfg4);
455 ao_radio_reg_write(CC115L_DEVIATN, packet_rate_setup[ao_config.radio_rate].deviatn);
457 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
458 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
461 if (changes & AO_RADIO_MODE_BITS_RDF)
462 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
463 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
465 if (changes & AO_RADIO_MODE_BITS_APRS)
466 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
467 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
469 if (changes & AO_RADIO_MODE_BITS_INFINITE)
470 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_INFINITE);
472 if (changes & AO_RADIO_MODE_BITS_FIXED)
473 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_FIXED);
475 ao_radio_mode = new_mode;
478 /***************************************************************
479 * SmartRF Studio(tm) Export
481 * Radio register settings specifed with address, value
485 ***************************************************************/
487 static const uint16_t radio_setup[] = {
489 /* High when FIFO is above threshold, low when fifo is below threshold */
490 AO_CC115L_FIFO_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR,
492 /* High when transmitter is running, low when off */
493 AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV),
495 CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */
496 CC115L_MDMCFG1, /* Modem Configuration */
497 ((CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) |
498 (1 << CC115L_MDMCFG1_CHANSPC_E)),
499 CC115L_MDMCFG0, 248, /* Channel spacing M value (100kHz channels) */
500 CC115L_MCSM1, 0x30, /* Main Radio Control State Machine Configuration */
501 CC115L_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */
502 CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */
503 CC115L_FREND0, 0x10, /* Front End TX Configuration */
504 CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */
505 CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */
506 CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */
507 CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */
508 CC115L_RESERVED_0X29, 0x59, /* RESERVED */
509 CC115L_RESERVED_0X2A, 0x7f, /* RESERVED */
510 CC115L_RESERVED_0X2B, 0x3f, /* RESERVED */
511 CC115L_TEST2, 0x81, /* Various Test Settings */
512 CC115L_TEST1, 0x35, /* Various Test Settings */
513 CC115L_TEST0, 0x09, /* Various Test Settings */
516 static uint8_t ao_radio_configured = 0;
519 #define RADIO_POWER ao_config.radio_power
523 #define RADIO_POWER 0x03 /* -31.75dBm on the test board */
526 #define RADIO_POWER 0xc0 /* full power */
535 ao_radio_strobe(CC115L_SRES);
536 ao_delay(AO_MS_TO_TICKS(10));
538 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
539 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
545 ao_radio_reg_write(CC115L_PA, RADIO_POWER);
547 ao_radio_strobe(CC115L_SCAL);
549 ao_radio_configured = 1;
553 ao_radio_set_len(uint8_t len)
555 static uint8_t last_len;
557 if (len != last_len) {
558 ao_radio_reg_write(CC115L_PKTLEN, len);
566 static uint32_t last_radio_setting;
567 static uint8_t last_radio_rate;
569 ao_mutex_get(&ao_radio_mutex);
570 if (!ao_radio_configured)
572 if (ao_config.radio_setting != last_radio_setting) {
573 ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16);
574 ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);
575 ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
576 last_radio_setting = ao_config.radio_setting;
577 /* Make sure the RF calibration is current */
578 ao_radio_strobe(CC115L_SCAL);
580 if (ao_config.radio_rate != last_radio_rate) {
581 ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET_TX;
582 last_radio_rate = ao_config.radio_rate;
587 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
589 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
591 struct ao_radio_tone {
596 struct ao_radio_tone *ao_radio_tone;
597 uint8_t ao_radio_tone_count;
598 uint8_t ao_radio_tone_current;
599 uint8_t ao_radio_tone_offset;
602 ao_radio_tone_fill(uint8_t *buf, int16_t len)
608 struct ao_radio_tone *t;
610 /* Figure out how many to send of the current value */
611 t = &ao_radio_tone[ao_radio_tone_current];
612 this_time = t->len - ao_radio_tone_offset;
617 memset(buf, t->value, this_time);
621 ao_radio_tone_offset += this_time;
624 if (ao_radio_tone_offset >= t->len) {
625 ao_radio_tone_offset = 0;
626 ao_radio_tone_current++;
627 if (ao_radio_tone_current >= ao_radio_tone_count) {
628 trace_add(trace_line, __LINE__, ret, "done with tone");
633 trace_add(trace_line, __LINE__, ret, "got some tone");
638 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
641 ao_radio_tone = tones;
642 ao_radio_tone_current = 0;
643 ao_radio_tone_offset = 0;
644 ao_radio_tone_count = ntones;
645 _ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
652 struct ao_radio_tone tone;
654 tone.value = ao_radio_rdf_value;
655 tone.len = AO_RADIO_RDF_LEN;
656 ao_radio_tone_run(&tone, 1);
660 ao_radio_continuity(uint8_t c)
662 struct ao_radio_tone tones[7];
666 for (i = 0; i < 3; i++) {
667 tones[count].value = 0x00;
668 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
671 tones[count].value = ao_radio_rdf_value;
673 tones[count].value = 0x00;
674 tones[count].len = AO_RADIO_CONT_TONE_LEN;
677 tones[count].value = 0x00;
678 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
680 ao_radio_tone_run(tones, count);
684 ao_radio_rdf_abort(void)
687 ao_wakeup(&ao_radio_wake);
690 #define POWER_STEP 0x08
696 ao_radio_strobe(CC115L_STX);
700 ao_radio_test_cmd(void)
703 static uint8_t radio_on;
705 if (ao_cmd_lex_c != '\n')
706 mode = ao_cmd_decimal();
708 if ((mode & 2) && !radio_on) {
710 ao_monitor_disable();
713 ao_packet_slave_stop();
716 ao_radio_strobe(CC115L_SFTX);
717 ao_radio_set_len(0xff);
718 ao_radio_set_mode(AO_RADIO_MODE_RDF);
723 printf ("Hit a character to stop..."); flush();
727 if ((mode & 1) && radio_on) {
738 static inline int16_t
739 ao_radio_gpio_bits(void)
741 return ((ao_gpio_get(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN, AO_CC115L_DONE_INT) << 1) |
742 ao_gpio_get(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN, AO_CC115L_FIFO_INT));
747 ao_radio_wait_fifo(void)
749 ao_arch_block_interrupts();
750 while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) {
751 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo");
752 ao_sleep(&ao_radio_wake);
754 ao_arch_release_interrupts();
755 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
756 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
757 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
758 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
762 ao_radio_wait_done(void)
764 ao_arch_block_interrupts();
765 while (!ao_radio_done && !ao_radio_abort) {
766 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done");
767 ao_sleep(&ao_radio_wake);
769 ao_arch_release_interrupts();
770 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
771 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
772 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
773 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
776 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
778 static uint8_t *ao_radio_send_buf;
779 static int16_t ao_radio_send_len;
782 ao_radio_send_fill(uint8_t *buf, int16_t len)
786 this_time = ao_radio_send_len;
789 memcpy(buf, ao_radio_send_buf, this_time);
790 ao_radio_send_buf += this_time;
791 ao_radio_send_len -= this_time;
792 if (ao_radio_send_len == 0)
798 ao_radio_send(const void *d, uint8_t size)
801 ao_radio_send_len = ao_fec_encode(d, size, tx_data);
802 ao_radio_send_buf = tx_data;
803 _ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX);
807 #define AO_RADIO_LOTS 64
810 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
812 uint8_t buf[AO_RADIO_LOTS], *b;
819 fifo_space = CC115L_FIFO_SIZE;
822 ao_radio_strobe(CC115L_SFTX);
827 cnt = (*fill)(buf, sizeof(buf));
828 trace_add(trace_line, __LINE__, cnt, "send data count");
835 /* At the last buffer, set the total length */
837 ao_radio_set_len(total & 0xff);
838 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED);
840 ao_radio_set_len(0xff);
841 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE);
846 uint8_t this_len = cnt;
848 /* Wait for some space in the fifo */
849 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
850 trace_add(trace_line, __LINE__, this_len, "wait for space");
851 ao_radio_wait_fifo();
853 if (ao_radio_abort || ao_radio_done)
855 trace_add(trace_line, __LINE__, fifo_space, "got space");
856 if (this_len > fifo_space)
857 this_len = fifo_space;
863 ao_radio_fifo_write(b, this_len);
866 ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
867 ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
874 if (ao_radio_abort || ao_radio_done)
879 ao_radio_wait_done();
884 ao_radio_send_aprs(ao_radio_fill_func fill)
887 _ao_radio_send_lots(fill, AO_RADIO_MODE_APRS);
892 static const char *cc115l_state_name[] = {
893 [CC115L_STATUS_STATE_IDLE] = "IDLE",
894 [CC115L_STATUS_STATE_TX] = "TX",
895 [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
896 [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE",
897 [CC115L_STATUS_STATE_SETTLING] = "SETTLING",
898 [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
901 static const struct ao_cc115l_reg ao_cc115l_reg[] = {
902 { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
903 { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
904 { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
905 { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" },
906 { .addr = CC115L_SYNC1, .name = "SYNC1" },
907 { .addr = CC115L_SYNC0, .name = "SYNC0" },
908 { .addr = CC115L_PKTLEN, .name = "PKTLEN" },
909 { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" },
910 { .addr = CC115L_CHANNR, .name = "CHANNR" },
911 { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" },
912 { .addr = CC115L_FREQ2, .name = "FREQ2" },
913 { .addr = CC115L_FREQ1, .name = "FREQ1" },
914 { .addr = CC115L_FREQ0, .name = "FREQ0" },
915 { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" },
916 { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" },
917 { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" },
918 { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" },
919 { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" },
920 { .addr = CC115L_DEVIATN, .name = "DEVIATN" },
921 { .addr = CC115L_MCSM1, .name = "MCSM1" },
922 { .addr = CC115L_MCSM0, .name = "MCSM0" },
923 { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" },
924 { .addr = CC115L_FREND0, .name = "FREND0" },
925 { .addr = CC115L_FSCAL3, .name = "FSCAL3" },
926 { .addr = CC115L_FSCAL2, .name = "FSCAL2" },
927 { .addr = CC115L_FSCAL1, .name = "FSCAL1" },
928 { .addr = CC115L_FSCAL0, .name = "FSCAL0" },
929 { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" },
930 { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" },
931 { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" },
932 { .addr = CC115L_TEST2, .name = "TEST2" },
933 { .addr = CC115L_TEST1, .name = "TEST1" },
934 { .addr = CC115L_TEST0, .name = "TEST0" },
935 { .addr = CC115L_PARTNUM, .name = "PARTNUM" },
936 { .addr = CC115L_VERSION, .name = "VERSION" },
937 { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" },
938 { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" },
939 { .addr = CC115L_TXBYTES, .name = "TXBYTES" },
940 { .addr = CC115L_PA, .name = "PA" },
943 #define AO_NUM_CC115L_REG (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0])
945 static void ao_radio_show(void) {
946 uint8_t status = ao_radio_status();
950 status = ao_radio_status();
951 printf ("Status: %02x\n", status);
952 printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1);
953 printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]);
954 printf ("MARC: %02x\n", ao_radio_get_marcstate());
956 for (i = 0; i < AO_NUM_CC115L_REG; i++)
957 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name);
961 static void ao_radio_beep(void) {
965 static void ao_radio_packet(void) {
966 static const uint8_t packet[] = {
968 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
969 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
970 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
971 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
977 ao_radio_send(packet, sizeof (packet));
988 ao_packet_slave_stop();
993 #endif /* CC115L_DEBUG */
995 static const struct ao_cmds ao_radio_cmds[] = {
996 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
999 { ao_radio_aprs, "G\0Send APRS packet" },
1001 { ao_radio_show, "R\0Show CC115L status" },
1002 { ao_radio_beep, "b\0Emit an RDF beacon" },
1003 { ao_radio_packet, "p\0Send a test packet" },
1015 ao_radio_configured = 0;
1016 ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN));
1019 AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN));
1020 for (i = 0; i < 10000; i++) {
1021 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1024 AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN);
1026 ao_panic(AO_PANIC_SELF_TEST_CC115L);
1029 /* Enable the fifo threhold interrupt pin */
1030 ao_enable_port(AO_CC115L_FIFO_INT_PORT);
1031 ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN,
1032 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1035 /* Enable the tx done interrupt pin */
1036 ao_enable_port(AO_CC115L_DONE_INT_PORT);
1037 ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN,
1038 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1043 ao_cmd_register(&ao_radio_cmds[0]);