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; 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_cc115l.h>
21 #include <ao_telemetry.h>
24 #define AO_RADIO_MAX_SEND sizeof (struct ao_telemetry_generic)
26 uint8_t ao_radio_mutex;
28 static uint8_t ao_radio_fifo; /* fifo drained interrupt received */
29 static uint8_t ao_radio_done; /* tx done interrupt received */
30 static uint8_t ao_radio_wake; /* sleep address for radio interrupts */
31 static uint8_t ao_radio_abort; /* radio operation should abort */
33 /* Debugging commands */
34 #define CC115L_DEBUG 0
37 #define CC115L_TRACE 0
41 #define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_6MHz)
42 #define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)
43 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS)
44 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS)
45 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC115L_SPI_BUS)
46 #define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC115L_SPI_BUS)
48 struct ao_cc115l_reg {
55 static const struct ao_cc115l_reg ao_cc115l_reg[];
56 static const char *cc115l_state_name[];
58 enum ao_cc115l_trace_type {
66 struct ao_cc115l_trace {
67 enum ao_cc115l_trace_type type;
75 static struct ao_cc115l_trace trace[NUM_TRACE];
77 static int trace_disable;
79 static void trace_add(enum ao_cc115l_trace_type type, int16_t addr, int16_t value, const char *comment)
86 comment = ao_cc115l_reg[addr].name;
89 comment = cc115l_state_name[(value >> 4) & 0x7];
94 trace[trace_i].type = type;
95 trace[trace_i].addr = addr;
96 trace[trace_i].value = value;
97 trace[trace_i].comment = comment;
98 if (++trace_i == NUM_TRACE)
102 #define trace_add(t,a,v,c)
106 ao_radio_reg_read(uint8_t addr)
110 data[0] = ((1 << CC115L_READ) |
111 (0 << CC115L_BURST) |
114 ao_radio_spi_send(data, 1);
115 ao_radio_spi_recv(data, 1);
117 trace_add(trace_read, addr, data[0], NULL);
122 ao_radio_reg_write(uint8_t addr, uint8_t value)
126 trace_add(trace_write, addr, value, NULL);
127 data[0] = ((0 << CC115L_READ) |
128 (0 << CC115L_BURST) |
132 ao_radio_spi_send(data, 2);
138 ao_radio_burst_read_start (uint16_t addr)
142 data[0] = ((1 << CC115L_READ) |
143 (1 << CC115L_BURST) |
146 ao_radio_spi_send(data, 1);
150 ao_radio_burst_read_stop (void)
158 ao_radio_strobe(uint8_t addr)
163 ao_radio_duplex(&addr, &in, 1);
165 trace_add(trace_strobe, addr, in, NULL);
170 ao_radio_fifo_write_start(void)
172 uint8_t addr = ((0 << CC115L_READ) |
173 (1 << CC115L_BURST) |
178 ao_radio_duplex(&addr, &status, 1);
182 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
188 ao_radio_fifo_write(uint8_t *data, uint8_t len)
190 uint8_t status = ao_radio_fifo_write_start();
191 trace_add(trace_dma, CC115L_FIFO, len, NULL);
192 ao_radio_spi_send(data, len);
193 return ao_radio_fifo_write_stop(status);
197 ao_radio_tx_fifo_space(void)
199 return CC115L_FIFO_SIZE - (ao_radio_reg_read(CC115L_TXBYTES) & CC115L_TXBYTES_NUM_TX_BYTES_MASK);
204 ao_radio_status(void)
206 return ao_radio_strobe (CC115L_SNOP);
210 ao_radio_get_marcstate(void)
212 return ao_radio_reg_read(CC115L_MARCSTATE) & CC115L_MARCSTATE_MASK;
216 #define ao_radio_rdf_value 0x55
219 ao_radio_done_isr(void)
221 ao_exti_disable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
222 trace_add(trace_line, __LINE__, 0, "done_isr");
224 ao_wakeup(&ao_radio_wake);
228 ao_radio_fifo_isr(void)
230 ao_exti_disable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
231 trace_add(trace_line, __LINE__, 0, "fifo_isr");
233 ao_wakeup(&ao_radio_wake);
241 uint8_t state = ao_radio_strobe(CC115L_SIDLE);
242 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE)
244 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW)
245 ao_radio_strobe(CC115L_SFTX);
247 /* Flush any pending TX bytes */
248 ao_radio_strobe(CC115L_SFTX);
249 /* Make sure the RF calibration is current */
250 ao_radio_strobe(CC115L_SCAL);
256 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
258 * For 38400 baud, use 20.5kHz:
260 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz
262 * For 9600 baud, use 5.125kHz:
264 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 1) = 5157Hz
266 * For 2400 baud, use 1.5kHz:
268 * 26e6 / (2 ** 17) * (8 + 0) * (2 ** 0) = 1587Hz
271 #define PACKET_DEV_E_384 3
272 #define PACKET_DEV_M_384 5
274 #define PACKET_DEV_E_96 1
275 #define PACKET_DEV_M_96 5
277 #define PACKET_DEV_E_24 0
278 #define PACKET_DEV_M_24 0
281 * For our packet data:
283 * (256 + DATARATE_M) * 2 ** DATARATE_E
284 * Rdata = -------------------------------------- * fosc
289 * (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383
292 * DATARATE_E_384 = 10
296 #define PACKET_DRATE_M 131
298 #define PACKET_DRATE_E_384 10
299 #define PACKET_DRATE_E_96 8
300 #define PACKET_DRATE_E_24 6
302 static const struct {
305 } packet_rate_setup[] = {
306 [AO_RADIO_RATE_38400] = {
307 .mdmcfg4 = ((0xf << 4) |
308 (PACKET_DRATE_E_384 << CC115L_MDMCFG4_DRATE_E)),
309 .deviatn = ((PACKET_DEV_E_384 << CC115L_DEVIATN_DEVIATION_E) |
310 (PACKET_DEV_M_384 << CC115L_DEVIATN_DEVIATION_M)),
313 [AO_RADIO_RATE_9600] = {
314 .mdmcfg4 = ((0xf << 4) |
315 (PACKET_DRATE_E_96 << CC115L_MDMCFG4_DRATE_E)),
316 .deviatn = ((PACKET_DEV_E_96 << CC115L_DEVIATN_DEVIATION_E) |
317 (PACKET_DEV_M_96 << CC115L_DEVIATN_DEVIATION_M)),
320 [AO_RADIO_RATE_2400] = {
321 .mdmcfg4 = ((0xf << 4) |
322 (PACKET_DRATE_E_24 << CC115L_MDMCFG4_DRATE_E)),
323 .deviatn = ((PACKET_DEV_E_24 << CC115L_DEVIATN_DEVIATION_E) |
324 (PACKET_DEV_M_24 << CC115L_DEVIATN_DEVIATION_M)),
328 static const uint16_t packet_setup[] = {
329 CC115L_MDMCFG3, (PACKET_DRATE_M),
330 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
331 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
332 (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),
337 * RDF deviation is 3kHz
339 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
341 * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
348 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
350 * (256 + DATARATE_M) * 2 ** DATARATE_E
351 * Rdata = -------------------------------------- * fosc
354 * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
359 #define RDF_DRATE_E 6
360 #define RDF_DRATE_M 67
362 static const uint16_t rdf_setup[] = {
363 CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
364 (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
365 CC115L_MDMCFG4, ((0xf << 4) |
366 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
367 CC115L_MDMCFG3, (RDF_DRATE_M),
368 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
369 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
370 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
374 * APRS deviation is 3kHz
376 * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
383 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
385 * (256 + DATARATE_M) * 2 ** DATARATE_E
386 * Rdata = -------------------------------------- * fosc
389 * (256 + 131) * (2 ** 8) / (2**28) * 26e6 = 9596
395 #define APRS_DRATE_E 8
396 #define APRS_DRATE_M 131
398 static const uint16_t aprs_setup[] = {
399 CC115L_DEVIATN, ((APRS_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
400 (APRS_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
401 CC115L_MDMCFG4, ((0xf << 4) |
402 (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
403 CC115L_MDMCFG3, (APRS_DRATE_M),
404 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
405 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
406 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
409 #define AO_PKTCTRL0_INFINITE ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
410 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
411 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
412 #define AO_PKTCTRL0_FIXED ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
413 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
414 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
416 static uint16_t ao_radio_mode;
420 * These set the data rate and modulation parameters
422 #define AO_RADIO_MODE_BITS_PACKET_TX 1
423 #define AO_RADIO_MODE_BITS_RDF 2
424 #define AO_RADIO_MODE_BITS_APRS 4
427 * Flips between infinite packet mode and fixed packet mode;
428 * we use infinite mode until the sender gives us the
431 #define AO_RADIO_MODE_BITS_INFINITE 40
432 #define AO_RADIO_MODE_BITS_FIXED 80
434 #define AO_RADIO_MODE_NONE 0
436 #define AO_RADIO_MODE_RDF AO_RADIO_MODE_BITS_RDF
437 #define AO_RADIO_MODE_PACKET_TX AO_RADIO_MODE_BITS_PACKET_TX
438 #define AO_RADIO_MODE_APRS AO_RADIO_MODE_BITS_APRS
441 ao_radio_set_mode(uint16_t new_mode)
446 if (new_mode == ao_radio_mode)
449 changes = new_mode & (~ao_radio_mode);
450 if (changes & AO_RADIO_MODE_BITS_PACKET_TX) {
451 ao_radio_reg_write(CC115L_MDMCFG4, packet_rate_setup[ao_config.radio_rate].mdmcfg4);
452 ao_radio_reg_write(CC115L_DEVIATN, packet_rate_setup[ao_config.radio_rate].deviatn);
454 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
455 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
458 if (changes & AO_RADIO_MODE_BITS_RDF)
459 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
460 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
462 if (changes & AO_RADIO_MODE_BITS_APRS)
463 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
464 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
466 if (changes & AO_RADIO_MODE_BITS_INFINITE)
467 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_INFINITE);
469 if (changes & AO_RADIO_MODE_BITS_FIXED)
470 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_FIXED);
472 ao_radio_mode = new_mode;
475 /***************************************************************
476 * SmartRF Studio(tm) Export
478 * Radio register settings specifed with address, value
482 ***************************************************************/
484 static const uint16_t radio_setup[] = {
486 /* High when FIFO is above threshold, low when fifo is below threshold */
487 AO_CC115L_FIFO_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR,
489 /* High when transmitter is running, low when off */
490 AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV),
492 CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */
493 CC115L_MDMCFG1, /* Modem Configuration */
494 ((CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) |
495 (1 << CC115L_MDMCFG1_CHANSPC_E)),
496 CC115L_MDMCFG0, 248, /* Channel spacing M value (100kHz channels) */
497 CC115L_MCSM1, 0x30, /* Main Radio Control State Machine Configuration */
498 CC115L_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */
499 CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */
500 CC115L_FREND0, 0x10, /* Front End TX Configuration */
501 CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */
502 CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */
503 CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */
504 CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */
505 CC115L_RESERVED_0X29, 0x59, /* RESERVED */
506 CC115L_RESERVED_0X2A, 0x7f, /* RESERVED */
507 CC115L_RESERVED_0X2B, 0x3f, /* RESERVED */
508 CC115L_TEST2, 0x81, /* Various Test Settings */
509 CC115L_TEST1, 0x35, /* Various Test Settings */
510 CC115L_TEST0, 0x09, /* Various Test Settings */
513 static uint8_t ao_radio_configured = 0;
516 #define RADIO_POWER ao_config.radio_power
520 #define RADIO_POWER 0x03 /* -31.75dBm on the test board */
523 #define RADIO_POWER 0xc0 /* full power */
532 ao_radio_strobe(CC115L_SRES);
533 ao_delay(AO_MS_TO_TICKS(10));
535 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
536 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
542 ao_radio_reg_write(CC115L_PA, RADIO_POWER);
544 ao_radio_strobe(CC115L_SCAL);
546 ao_radio_configured = 1;
550 ao_radio_set_len(uint8_t len)
552 static uint8_t last_len;
554 if (len != last_len) {
555 ao_radio_reg_write(CC115L_PKTLEN, len);
563 static uint32_t last_radio_setting;
564 static uint8_t last_radio_rate;
566 ao_mutex_get(&ao_radio_mutex);
567 if (!ao_radio_configured)
569 if (ao_config.radio_setting != last_radio_setting) {
570 ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16);
571 ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);
572 ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
573 last_radio_setting = ao_config.radio_setting;
574 /* Make sure the RF calibration is current */
575 ao_radio_strobe(CC115L_SCAL);
577 if (ao_config.radio_rate != last_radio_rate) {
578 ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET_TX;
579 last_radio_rate = ao_config.radio_rate;
584 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
586 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
588 struct ao_radio_tone {
593 struct ao_radio_tone *ao_radio_tone;
594 uint8_t ao_radio_tone_count;
595 uint8_t ao_radio_tone_current;
596 uint8_t ao_radio_tone_offset;
599 ao_radio_tone_fill(uint8_t *buf, int16_t len)
605 struct ao_radio_tone *t;
607 /* Figure out how many to send of the current value */
608 t = &ao_radio_tone[ao_radio_tone_current];
609 this_time = t->len - ao_radio_tone_offset;
614 memset(buf, t->value, this_time);
618 ao_radio_tone_offset += this_time;
621 if (ao_radio_tone_offset >= t->len) {
622 ao_radio_tone_offset = 0;
623 ao_radio_tone_current++;
624 if (ao_radio_tone_current >= ao_radio_tone_count) {
625 trace_add(trace_line, __LINE__, ret, "done with tone");
630 trace_add(trace_line, __LINE__, ret, "got some tone");
635 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
638 ao_radio_tone = tones;
639 ao_radio_tone_current = 0;
640 ao_radio_tone_offset = 0;
641 ao_radio_tone_count = ntones;
642 _ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
649 struct ao_radio_tone tone;
651 tone.value = ao_radio_rdf_value;
652 tone.len = AO_RADIO_RDF_LEN;
653 ao_radio_tone_run(&tone, 1);
657 ao_radio_continuity(uint8_t c)
659 struct ao_radio_tone tones[7];
663 for (i = 0; i < 3; i++) {
664 tones[count].value = 0x00;
665 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
668 tones[count].value = ao_radio_rdf_value;
670 tones[count].value = 0x00;
671 tones[count].len = AO_RADIO_CONT_TONE_LEN;
674 tones[count].value = 0x00;
675 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
677 ao_radio_tone_run(tones, count);
681 ao_radio_rdf_abort(void)
684 ao_wakeup(&ao_radio_wake);
687 #define POWER_STEP 0x08
693 ao_radio_strobe(CC115L_STX);
697 ao_radio_test_cmd(void)
700 static uint8_t radio_on;
702 if (ao_cmd_lex_c != '\n') {
704 mode = (uint8_t) ao_cmd_lex_u32;
707 if ((mode & 2) && !radio_on) {
709 ao_monitor_disable();
712 ao_packet_slave_stop();
715 ao_radio_strobe(CC115L_SFTX);
716 ao_radio_set_len(0xff);
717 ao_radio_set_mode(AO_RADIO_MODE_RDF);
722 printf ("Hit a character to stop..."); flush();
726 if ((mode & 1) && radio_on) {
737 static inline int16_t
738 ao_radio_gpio_bits(void)
740 return ((ao_gpio_get(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN, AO_CC115L_DONE_INT) << 1) |
741 ao_gpio_get(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN, AO_CC115L_FIFO_INT));
746 ao_radio_wait_fifo(void)
748 ao_arch_block_interrupts();
749 while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) {
750 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo");
751 ao_sleep(&ao_radio_wake);
753 ao_arch_release_interrupts();
754 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
755 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
756 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
757 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
761 ao_radio_wait_done(void)
763 ao_arch_block_interrupts();
764 while (!ao_radio_done && !ao_radio_abort) {
765 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done");
766 ao_sleep(&ao_radio_wake);
768 ao_arch_release_interrupts();
769 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
770 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
771 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
772 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
775 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
777 static uint8_t *ao_radio_send_buf;
778 static int16_t ao_radio_send_len;
781 ao_radio_send_fill(uint8_t *buf, int16_t len)
785 this_time = ao_radio_send_len;
788 memcpy(buf, ao_radio_send_buf, this_time);
789 ao_radio_send_buf += this_time;
790 ao_radio_send_len -= this_time;
791 if (ao_radio_send_len == 0)
797 ao_radio_send(const void *d, uint8_t size)
800 ao_radio_send_len = ao_fec_encode(d, size, tx_data);
801 ao_radio_send_buf = tx_data;
802 _ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX);
806 #define AO_RADIO_LOTS 64
809 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
811 uint8_t buf[AO_RADIO_LOTS], *b;
818 fifo_space = CC115L_FIFO_SIZE;
821 ao_radio_strobe(CC115L_SFTX);
826 cnt = (*fill)(buf, sizeof(buf));
827 trace_add(trace_line, __LINE__, cnt, "send data count");
834 /* At the last buffer, set the total length */
836 ao_radio_set_len(total & 0xff);
837 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED);
839 ao_radio_set_len(0xff);
840 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE);
845 uint8_t this_len = cnt;
847 /* Wait for some space in the fifo */
848 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
849 trace_add(trace_line, __LINE__, this_len, "wait for space");
850 ao_radio_wait_fifo();
852 if (ao_radio_abort || ao_radio_done)
854 trace_add(trace_line, __LINE__, fifo_space, "got space");
855 if (this_len > fifo_space)
856 this_len = fifo_space;
862 ao_radio_fifo_write(b, this_len);
865 ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
866 ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
873 if (ao_radio_abort || ao_radio_done)
878 ao_radio_wait_done();
883 ao_radio_send_aprs(ao_radio_fill_func fill)
886 _ao_radio_send_lots(fill, AO_RADIO_MODE_APRS);
891 static const char *cc115l_state_name[] = {
892 [CC115L_STATUS_STATE_IDLE] = "IDLE",
893 [CC115L_STATUS_STATE_TX] = "TX",
894 [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
895 [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE",
896 [CC115L_STATUS_STATE_SETTLING] = "SETTLING",
897 [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
900 static const struct ao_cc115l_reg ao_cc115l_reg[] = {
901 { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
902 { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
903 { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
904 { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" },
905 { .addr = CC115L_SYNC1, .name = "SYNC1" },
906 { .addr = CC115L_SYNC0, .name = "SYNC0" },
907 { .addr = CC115L_PKTLEN, .name = "PKTLEN" },
908 { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" },
909 { .addr = CC115L_CHANNR, .name = "CHANNR" },
910 { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" },
911 { .addr = CC115L_FREQ2, .name = "FREQ2" },
912 { .addr = CC115L_FREQ1, .name = "FREQ1" },
913 { .addr = CC115L_FREQ0, .name = "FREQ0" },
914 { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" },
915 { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" },
916 { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" },
917 { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" },
918 { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" },
919 { .addr = CC115L_DEVIATN, .name = "DEVIATN" },
920 { .addr = CC115L_MCSM1, .name = "MCSM1" },
921 { .addr = CC115L_MCSM0, .name = "MCSM0" },
922 { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" },
923 { .addr = CC115L_FREND0, .name = "FREND0" },
924 { .addr = CC115L_FSCAL3, .name = "FSCAL3" },
925 { .addr = CC115L_FSCAL2, .name = "FSCAL2" },
926 { .addr = CC115L_FSCAL1, .name = "FSCAL1" },
927 { .addr = CC115L_FSCAL0, .name = "FSCAL0" },
928 { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" },
929 { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" },
930 { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" },
931 { .addr = CC115L_TEST2, .name = "TEST2" },
932 { .addr = CC115L_TEST1, .name = "TEST1" },
933 { .addr = CC115L_TEST0, .name = "TEST0" },
934 { .addr = CC115L_PARTNUM, .name = "PARTNUM" },
935 { .addr = CC115L_VERSION, .name = "VERSION" },
936 { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" },
937 { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" },
938 { .addr = CC115L_TXBYTES, .name = "TXBYTES" },
939 { .addr = CC115L_PA, .name = "PA" },
942 #define AO_NUM_CC115L_REG (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0])
944 static void ao_radio_show(void) {
945 uint8_t status = ao_radio_status();
949 status = ao_radio_status();
950 printf ("Status: %02x\n", status);
951 printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1);
952 printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]);
953 printf ("MARC: %02x\n", ao_radio_get_marcstate());
955 for (i = 0; i < AO_NUM_CC115L_REG; i++)
956 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name);
960 static void ao_radio_beep(void) {
964 static void ao_radio_packet(void) {
965 static const uint8_t packet[] = {
967 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
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,
976 ao_radio_send(packet, sizeof (packet));
987 ao_packet_slave_stop();
992 #endif /* CC115L_DEBUG */
994 static const struct ao_cmds ao_radio_cmds[] = {
995 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
998 { ao_radio_aprs, "G\0Send APRS packet" },
1000 { ao_radio_show, "R\0Show CC115L status" },
1001 { ao_radio_beep, "b\0Emit an RDF beacon" },
1002 { ao_radio_packet, "p\0Send a test packet" },
1014 ao_radio_configured = 0;
1015 ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN));
1018 AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN));
1019 for (i = 0; i < 10000; i++) {
1020 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1023 AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN);
1025 ao_panic(AO_PANIC_SELF_TEST_CC115L);
1028 /* Enable the fifo threhold interrupt pin */
1029 ao_enable_port(AO_CC115L_FIFO_INT_PORT);
1030 ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN,
1031 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1034 /* Enable the tx done interrupt pin */
1035 ao_enable_port(AO_CC115L_DONE_INT_PORT);
1036 ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN,
1037 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1042 ao_cmd_register(&ao_radio_cmds[0]);