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_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)
43 #define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)
44 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS)
45 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS)
46 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC115L_SPI_BUS)
47 #define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC115L_SPI_BUS)
49 struct ao_cc115l_reg {
56 static const struct ao_cc115l_reg ao_cc115l_reg[];
57 static const char *cc115l_state_name[];
59 enum ao_cc115l_trace_type {
67 struct ao_cc115l_trace {
68 enum ao_cc115l_trace_type type;
76 static struct ao_cc115l_trace trace[NUM_TRACE];
78 static int trace_disable;
80 static void trace_add(enum ao_cc115l_trace_type type, int16_t addr, int16_t value, const char *comment)
87 comment = ao_cc115l_reg[addr].name;
90 comment = cc115l_state_name[(value >> 4) & 0x7];
95 trace[trace_i].type = type;
96 trace[trace_i].addr = addr;
97 trace[trace_i].value = value;
98 trace[trace_i].comment = comment;
99 if (++trace_i == NUM_TRACE)
103 #define trace_add(t,a,v,c)
107 ao_radio_reg_read(uint8_t addr)
111 data[0] = ((1 << CC115L_READ) |
112 (0 << CC115L_BURST) |
115 ao_radio_spi_send(data, 1);
116 ao_radio_spi_recv(data, 1);
118 trace_add(trace_read, addr, data[0], NULL);
123 ao_radio_reg_write(uint8_t addr, uint8_t value)
127 trace_add(trace_write, addr, value, NULL);
128 data[0] = ((0 << CC115L_READ) |
129 (0 << CC115L_BURST) |
133 ao_radio_spi_send(data, 2);
139 ao_radio_burst_read_start (uint16_t addr)
143 data[0] = ((1 << CC115L_READ) |
144 (1 << CC115L_BURST) |
147 ao_radio_spi_send(data, 1);
151 ao_radio_burst_read_stop (void)
159 ao_radio_strobe(uint8_t addr)
164 ao_radio_duplex(&addr, &in, 1);
166 trace_add(trace_strobe, addr, in, NULL);
171 ao_radio_fifo_write_start(void)
173 uint8_t addr = ((0 << CC115L_READ) |
174 (1 << CC115L_BURST) |
179 ao_radio_duplex(&addr, &status, 1);
183 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
189 ao_radio_fifo_write(uint8_t *data, uint8_t len)
191 uint8_t status = ao_radio_fifo_write_start();
192 trace_add(trace_dma, CC115L_FIFO, len, NULL);
193 ao_radio_spi_send(data, len);
194 return ao_radio_fifo_write_stop(status);
198 ao_radio_tx_fifo_space(void)
200 return CC115L_FIFO_SIZE - (ao_radio_reg_read(CC115L_TXBYTES) & CC115L_TXBYTES_NUM_TX_BYTES_MASK);
205 ao_radio_status(void)
207 return ao_radio_strobe (CC115L_SNOP);
211 ao_radio_get_marcstate(void)
213 return ao_radio_reg_read(CC115L_MARCSTATE) & CC115L_MARCSTATE_MASK;
217 #define ao_radio_rdf_value 0x55
220 ao_radio_done_isr(void)
222 ao_exti_disable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
223 trace_add(trace_line, __LINE__, 0, "done_isr");
225 ao_wakeup(&ao_radio_wake);
229 ao_radio_fifo_isr(void)
231 ao_exti_disable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
232 trace_add(trace_line, __LINE__, 0, "fifo_isr");
234 ao_wakeup(&ao_radio_wake);
242 uint8_t state = ao_radio_strobe(CC115L_SIDLE);
243 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE)
245 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW)
246 ao_radio_strobe(CC115L_SFTX);
248 /* Flush any pending TX bytes */
249 ao_radio_strobe(CC115L_SFTX);
250 /* Make sure the RF calibration is current */
251 ao_radio_strobe(CC115L_SCAL);
257 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
259 * For 38400 baud, use 20.5kHz:
261 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz
263 * For 9600 baud, use 5.125kHz:
265 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 1) = 5157Hz
267 * For 2400 baud, use 1.5kHz:
269 * 26e6 / (2 ** 17) * (8 + 0) * (2 ** 0) = 1587Hz
272 #define PACKET_DEV_E_384 3
273 #define PACKET_DEV_M_384 5
275 #define PACKET_DEV_E_96 1
276 #define PACKET_DEV_M_96 5
278 #define PACKET_DEV_E_24 0
279 #define PACKET_DEV_M_24 0
282 * For our packet data:
284 * (256 + DATARATE_M) * 2 ** DATARATE_E
285 * Rdata = -------------------------------------- * fosc
290 * (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383
293 * DATARATE_E_384 = 10
297 #define PACKET_DRATE_M 131
299 #define PACKET_DRATE_E_384 10
300 #define PACKET_DRATE_E_96 8
301 #define PACKET_DRATE_E_24 6
303 static const struct {
306 } packet_rate_setup[] = {
307 [AO_RADIO_RATE_38400] = {
308 .mdmcfg4 = ((0xf << 4) |
309 (PACKET_DRATE_E_384 << CC115L_MDMCFG4_DRATE_E)),
310 .deviatn = ((PACKET_DEV_E_384 << CC115L_DEVIATN_DEVIATION_E) |
311 (PACKET_DEV_M_384 << CC115L_DEVIATN_DEVIATION_M)),
314 [AO_RADIO_RATE_9600] = {
315 .mdmcfg4 = ((0xf << 4) |
316 (PACKET_DRATE_E_96 << CC115L_MDMCFG4_DRATE_E)),
317 .deviatn = ((PACKET_DEV_E_96 << CC115L_DEVIATN_DEVIATION_E) |
318 (PACKET_DEV_M_96 << CC115L_DEVIATN_DEVIATION_M)),
321 [AO_RADIO_RATE_2400] = {
322 .mdmcfg4 = ((0xf << 4) |
323 (PACKET_DRATE_E_24 << CC115L_MDMCFG4_DRATE_E)),
324 .deviatn = ((PACKET_DEV_E_24 << CC115L_DEVIATN_DEVIATION_E) |
325 (PACKET_DEV_M_24 << CC115L_DEVIATN_DEVIATION_M)),
329 static const uint16_t packet_setup[] = {
330 CC115L_MDMCFG3, (PACKET_DRATE_M),
331 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
332 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
333 (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),
338 * RDF deviation is 3kHz
340 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
342 * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
349 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
351 * (256 + DATARATE_M) * 2 ** DATARATE_E
352 * Rdata = -------------------------------------- * fosc
355 * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
360 #define RDF_DRATE_E 6
361 #define RDF_DRATE_M 67
363 static const uint16_t rdf_setup[] = {
364 CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
365 (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
366 CC115L_MDMCFG4, ((0xf << 4) |
367 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
368 CC115L_MDMCFG3, (RDF_DRATE_M),
369 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
370 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
371 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
375 * APRS deviation is 3kHz
377 * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
384 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
386 * (256 + DATARATE_M) * 2 ** DATARATE_E
387 * Rdata = -------------------------------------- * fosc
390 * (256 + 131) * (2 ** 8) / (2**28) * 26e6 = 9596
396 #define APRS_DRATE_E 8
397 #define APRS_DRATE_M 131
399 static const uint16_t aprs_setup[] = {
400 CC115L_DEVIATN, ((APRS_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
401 (APRS_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
402 CC115L_MDMCFG4, ((0xf << 4) |
403 (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
404 CC115L_MDMCFG3, (APRS_DRATE_M),
405 CC115L_MDMCFG2, ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
406 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
407 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
410 #define AO_PKTCTRL0_INFINITE ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
411 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
412 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
413 #define AO_PKTCTRL0_FIXED ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
414 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
415 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
417 static uint16_t ao_radio_mode;
421 * These set the data rate and modulation parameters
423 #define AO_RADIO_MODE_BITS_PACKET_TX 1
424 #define AO_RADIO_MODE_BITS_RDF 2
425 #define AO_RADIO_MODE_BITS_APRS 4
428 * Flips between infinite packet mode and fixed packet mode;
429 * we use infinite mode until the sender gives us the
432 #define AO_RADIO_MODE_BITS_INFINITE 40
433 #define AO_RADIO_MODE_BITS_FIXED 80
435 #define AO_RADIO_MODE_NONE 0
437 #define AO_RADIO_MODE_RDF AO_RADIO_MODE_BITS_RDF
438 #define AO_RADIO_MODE_PACKET_TX AO_RADIO_MODE_BITS_PACKET_TX
439 #define AO_RADIO_MODE_APRS AO_RADIO_MODE_BITS_APRS
442 ao_radio_set_mode(uint16_t new_mode)
447 if (new_mode == ao_radio_mode)
450 changes = new_mode & (~ao_radio_mode);
451 if (changes & AO_RADIO_MODE_BITS_PACKET_TX) {
452 ao_radio_reg_write(CC115L_MDMCFG4, packet_rate_setup[ao_config.radio_rate].mdmcfg4);
453 ao_radio_reg_write(CC115L_DEVIATN, packet_rate_setup[ao_config.radio_rate].deviatn);
455 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
456 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
459 if (changes & AO_RADIO_MODE_BITS_RDF)
460 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
461 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
463 if (changes & AO_RADIO_MODE_BITS_APRS)
464 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
465 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
467 if (changes & AO_RADIO_MODE_BITS_INFINITE)
468 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_INFINITE);
470 if (changes & AO_RADIO_MODE_BITS_FIXED)
471 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_FIXED);
473 ao_radio_mode = new_mode;
476 /***************************************************************
477 * SmartRF Studio(tm) Export
479 * Radio register settings specifed with address, value
483 ***************************************************************/
485 static const uint16_t radio_setup[] = {
487 /* High when FIFO is above threshold, low when fifo is below threshold */
488 AO_CC115L_FIFO_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR,
490 /* High when transmitter is running, low when off */
491 AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV),
493 CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */
494 CC115L_MDMCFG1, /* Modem Configuration */
495 ((CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) |
496 (1 << CC115L_MDMCFG1_CHANSPC_E)),
497 CC115L_MDMCFG0, 248, /* Channel spacing M value (100kHz channels) */
498 CC115L_MCSM1, 0x30, /* Main Radio Control State Machine Configuration */
499 CC115L_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */
500 CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */
501 CC115L_FREND0, 0x10, /* Front End TX Configuration */
502 CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */
503 CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */
504 CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */
505 CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */
506 CC115L_RESERVED_0X29, 0x59, /* RESERVED */
507 CC115L_RESERVED_0X2A, 0x7f, /* RESERVED */
508 CC115L_RESERVED_0X2B, 0x3f, /* RESERVED */
509 CC115L_TEST2, 0x81, /* Various Test Settings */
510 CC115L_TEST1, 0x35, /* Various Test Settings */
511 CC115L_TEST0, 0x09, /* Various Test Settings */
514 static uint8_t ao_radio_configured = 0;
517 #define RADIO_POWER ao_config.radio_power
521 #define RADIO_POWER 0x03 /* -31.75dBm on the test board */
524 #define RADIO_POWER 0xc0 /* full power */
533 ao_radio_strobe(CC115L_SRES);
534 ao_delay(AO_MS_TO_TICKS(10));
536 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
537 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
543 ao_radio_reg_write(CC115L_PA, RADIO_POWER);
545 ao_radio_strobe(CC115L_SCAL);
547 ao_radio_configured = 1;
551 ao_radio_set_len(uint8_t len)
553 static uint8_t last_len;
555 if (len != last_len) {
556 ao_radio_reg_write(CC115L_PKTLEN, len);
564 static uint32_t last_radio_setting;
565 static uint8_t last_radio_rate;
567 ao_mutex_get(&ao_radio_mutex);
568 if (!ao_radio_configured)
570 if (ao_config.radio_setting != last_radio_setting) {
571 ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16);
572 ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);
573 ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
574 last_radio_setting = ao_config.radio_setting;
575 /* Make sure the RF calibration is current */
576 ao_radio_strobe(CC115L_SCAL);
578 if (ao_config.radio_rate != last_radio_rate) {
579 ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET_TX;
580 last_radio_rate = ao_config.radio_rate;
585 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
587 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
589 struct ao_radio_tone {
594 struct ao_radio_tone *ao_radio_tone;
595 uint8_t ao_radio_tone_count;
596 uint8_t ao_radio_tone_current;
597 uint8_t ao_radio_tone_offset;
600 ao_radio_tone_fill(uint8_t *buf, int16_t len)
606 struct ao_radio_tone *t;
608 /* Figure out how many to send of the current value */
609 t = &ao_radio_tone[ao_radio_tone_current];
610 this_time = t->len - ao_radio_tone_offset;
615 memset(buf, t->value, this_time);
619 ao_radio_tone_offset += this_time;
622 if (ao_radio_tone_offset >= t->len) {
623 ao_radio_tone_offset = 0;
624 ao_radio_tone_current++;
625 if (ao_radio_tone_current >= ao_radio_tone_count) {
626 trace_add(trace_line, __LINE__, ret, "done with tone");
631 trace_add(trace_line, __LINE__, ret, "got some tone");
636 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
639 ao_radio_tone = tones;
640 ao_radio_tone_current = 0;
641 ao_radio_tone_offset = 0;
642 ao_radio_tone_count = ntones;
643 _ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
650 struct ao_radio_tone tone;
652 tone.value = ao_radio_rdf_value;
653 tone.len = AO_RADIO_RDF_LEN;
654 ao_radio_tone_run(&tone, 1);
658 ao_radio_continuity(uint8_t c)
660 struct ao_radio_tone tones[7];
664 for (i = 0; i < 3; i++) {
665 tones[count].value = 0x00;
666 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
669 tones[count].value = ao_radio_rdf_value;
671 tones[count].value = 0x00;
672 tones[count].len = AO_RADIO_CONT_TONE_LEN;
675 tones[count].value = 0x00;
676 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
678 ao_radio_tone_run(tones, count);
682 ao_radio_rdf_abort(void)
685 ao_wakeup(&ao_radio_wake);
688 #define POWER_STEP 0x08
694 ao_radio_strobe(CC115L_STX);
698 ao_radio_test_cmd(void)
701 static uint8_t radio_on;
703 if (ao_cmd_lex_c != '\n') {
705 mode = (uint8_t) ao_cmd_lex_u32;
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]);