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_1MHz)
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);
254 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
256 * For 38400 baud, use 20.5kHz:
258 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz
260 * For 9600 baud, use 5.125kHz:
262 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 1) = 5157Hz
264 * For 2400 baud, use 1.5kHz:
266 * 26e6 / (2 ** 17) * (8 + 0) * (2 ** 0) = 1587Hz
269 #define PACKET_DEV_E_384 3
270 #define PACKET_DEV_M_384 5
272 #define PACKET_DEV_E_96 1
273 #define PACKET_DEV_M_96 5
275 #define PACKET_DEV_E_24 0
276 #define PACKET_DEV_M_24 0
279 * For our packet data:
281 * (256 + DATARATE_M) * 2 ** DATARATE_E
282 * Rdata = -------------------------------------- * fosc
287 * (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383
290 * DATARATE_E_384 = 10
294 #define PACKET_DRATE_M 131
296 #define PACKET_DRATE_E_384 10
297 #define PACKET_DRATE_E_96 8
298 #define PACKET_DRATE_E_24 6
300 static const struct {
303 } packet_rate_setup[] = {
304 [AO_RADIO_RATE_38400] = {
305 .mdmcfg4 = ((0xf << 4) |
306 (PACKET_DRATE_E_384 << CC115L_MDMCFG4_DRATE_E)),
307 .deviatn = ((PACKET_DEV_E_384 << CC115L_DEVIATN_DEVIATION_E) |
308 (PACKET_DEV_M_384 << CC115L_DEVIATN_DEVIATION_M)),
311 [AO_RADIO_RATE_9600] = {
312 .mdmcfg4 = ((0xf << 4) |
313 (PACKET_DRATE_E_96 << CC115L_MDMCFG4_DRATE_E)),
314 .deviatn = ((PACKET_DEV_E_96 << CC115L_DEVIATN_DEVIATION_E) |
315 (PACKET_DEV_M_96 << CC115L_DEVIATN_DEVIATION_M)),
318 [AO_RADIO_RATE_2400] = {
319 .mdmcfg4 = ((0xf << 4) |
320 (PACKET_DRATE_E_24 << CC115L_MDMCFG4_DRATE_E)),
321 .deviatn = ((PACKET_DEV_E_24 << CC115L_DEVIATN_DEVIATION_E) |
322 (PACKET_DEV_M_24 << CC115L_DEVIATN_DEVIATION_M)),
326 static const uint16_t packet_setup[] = {
327 CC115L_MDMCFG3, (PACKET_DRATE_M),
328 CC115L_MDMCFG2, (0x00 |
329 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
330 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
331 (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),
336 * RDF deviation is 5kHz
338 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
340 * 26e6 / (2 ** 17) * (8 + 4) * (2 ** 1) = 4761Hz
347 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
349 * (256 + DATARATE_M) * 2 ** DATARATE_E
350 * Rdata = -------------------------------------- * fosc
353 * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
358 #define RDF_DRATE_E 6
359 #define RDF_DRATE_M 67
361 static const uint16_t rdf_setup[] = {
362 CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
363 (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
364 CC115L_MDMCFG4, ((0xf << 4) |
365 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
366 CC115L_MDMCFG3, (RDF_DRATE_M),
367 CC115L_MDMCFG2, (0x00 |
368 (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, (0x00 |
405 (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, (0x00 |
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_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */
499 CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */
500 CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */
501 CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */
502 CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */
503 CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */
504 CC115L_TEST2, 0x81, /* Various Test Settings */
505 CC115L_TEST1, 0x35, /* Various Test Settings */
506 CC115L_TEST0, 0x09, /* Various Test Settings */
509 static uint8_t ao_radio_configured = 0;
516 ao_radio_strobe(CC115L_SRES);
517 ao_delay(AO_MS_TO_TICKS(10));
519 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
520 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
526 ao_radio_strobe(CC115L_SCAL);
528 ao_radio_configured = 1;
532 ao_radio_set_len(uint8_t len)
534 static uint8_t last_len;
536 if (len != last_len) {
537 ao_radio_reg_write(CC115L_PKTLEN, len);
545 static uint32_t last_radio_setting;
546 static uint8_t last_radio_rate;
548 ao_mutex_get(&ao_radio_mutex);
549 if (!ao_radio_configured)
551 if (ao_config.radio_setting != last_radio_setting) {
552 ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16);
553 ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);
554 ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
555 last_radio_setting = ao_config.radio_setting;
557 if (ao_config.radio_rate != last_radio_rate) {
558 ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET_TX;
559 last_radio_rate = ao_config.radio_rate;
564 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
566 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
568 struct ao_radio_tone {
573 struct ao_radio_tone *ao_radio_tone;
574 uint8_t ao_radio_tone_count;
575 uint8_t ao_radio_tone_current;
576 uint8_t ao_radio_tone_offset;
579 ao_radio_tone_fill(uint8_t *buf, int16_t len)
585 struct ao_radio_tone *t;
587 /* Figure out how many to send of the current value */
588 t = &ao_radio_tone[ao_radio_tone_current];
589 this_time = t->len - ao_radio_tone_offset;
594 memset(buf, t->value, this_time);
598 ao_radio_tone_offset += this_time;
601 if (ao_radio_tone_offset >= t->len) {
602 ao_radio_tone_offset = 0;
603 ao_radio_tone_current++;
604 if (ao_radio_tone_current >= ao_radio_tone_count) {
605 trace_add(trace_line, __LINE__, ret, "done with tone");
610 trace_add(trace_line, __LINE__, ret, "got some tone");
615 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
618 ao_radio_tone = tones;
619 ao_radio_tone_current = 0;
620 ao_radio_tone_offset = 0;
621 ao_radio_tone_count = ntones;
622 _ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
629 struct ao_radio_tone tone;
631 tone.value = ao_radio_rdf_value;
632 tone.len = AO_RADIO_RDF_LEN;
633 ao_radio_tone_run(&tone, 1);
637 ao_radio_continuity(uint8_t c)
639 struct ao_radio_tone tones[7];
643 for (i = 0; i < 3; i++) {
644 tones[count].value = 0x00;
645 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
648 tones[count].value = ao_radio_rdf_value;
650 tones[count].value = 0x00;
651 tones[count].len = AO_RADIO_CONT_TONE_LEN;
654 tones[count].value = 0x00;
655 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
657 ao_radio_tone_run(tones, count);
661 ao_radio_rdf_abort(void)
664 ao_wakeup(&ao_radio_wake);
667 #define POWER_STEP 0x08
670 #define RADIO_POWER ao_config.radio_power
672 #define RADIO_POWER 0xc0
680 ao_radio_reg_write(CC115L_PA, 0);
681 ao_radio_strobe(CC115L_STX);
682 for (power = POWER_STEP; power < RADIO_POWER; power += POWER_STEP)
683 ao_radio_reg_write(CC115L_PA, power);
684 if (power != RADIO_POWER)
685 ao_radio_reg_write(CC115L_PA, RADIO_POWER);
689 ao_radio_test_cmd(void)
692 static uint8_t radio_on;
694 if (ao_cmd_lex_c != '\n') {
696 mode = (uint8_t) ao_cmd_lex_u32;
699 if ((mode & 2) && !radio_on) {
701 ao_monitor_disable();
704 ao_packet_slave_stop();
707 ao_radio_strobe(CC115L_SFTX);
708 ao_radio_set_len(0xff);
709 ao_radio_set_mode(AO_RADIO_MODE_RDF);
714 printf ("Hit a character to stop..."); flush();
718 if ((mode & 1) && radio_on) {
729 static inline int16_t
730 ao_radio_gpio_bits(void)
732 return ((ao_gpio_get(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN, AO_CC115L_DONE_INT) << 1) |
733 ao_gpio_get(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN, AO_CC115L_FIFO_INT));
738 ao_radio_wait_fifo(void)
740 ao_arch_block_interrupts();
741 while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) {
742 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo");
743 ao_sleep(&ao_radio_wake);
745 ao_arch_release_interrupts();
746 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
747 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
748 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
749 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
753 ao_radio_wait_done(void)
755 ao_arch_block_interrupts();
756 while (!ao_radio_done && !ao_radio_abort) {
757 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done");
758 ao_sleep(&ao_radio_wake);
760 ao_arch_release_interrupts();
761 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
762 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
763 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
764 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
767 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
769 static uint8_t *ao_radio_send_buf;
770 static int16_t ao_radio_send_len;
773 ao_radio_send_fill(uint8_t *buf, int16_t len)
777 this_time = ao_radio_send_len;
780 memcpy(buf, ao_radio_send_buf, this_time);
781 ao_radio_send_buf += this_time;
782 ao_radio_send_len -= this_time;
783 if (ao_radio_send_len == 0)
789 ao_radio_send(const void *d, uint8_t size)
792 ao_radio_send_len = ao_fec_encode(d, size, tx_data);
793 ao_radio_send_buf = tx_data;
794 _ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX);
798 #define AO_RADIO_LOTS 64
801 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
803 uint8_t buf[AO_RADIO_LOTS], *b;
810 fifo_space = CC115L_FIFO_SIZE;
813 ao_radio_strobe(CC115L_SFTX);
818 cnt = (*fill)(buf, sizeof(buf));
819 trace_add(trace_line, __LINE__, cnt, "send data count");
826 /* At the last buffer, set the total length */
828 ao_radio_set_len(total & 0xff);
829 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED);
831 ao_radio_set_len(0xff);
832 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE);
837 uint8_t this_len = cnt;
839 /* Wait for some space in the fifo */
840 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
841 trace_add(trace_line, __LINE__, this_len, "wait for space");
842 ao_radio_wait_fifo();
844 if (ao_radio_abort || ao_radio_done)
846 trace_add(trace_line, __LINE__, fifo_space, "got space");
847 if (this_len > fifo_space)
848 this_len = fifo_space;
854 ao_radio_fifo_write(b, this_len);
857 ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
858 ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
865 if (ao_radio_abort || ao_radio_done)
870 ao_radio_wait_done();
875 ao_radio_send_aprs(ao_radio_fill_func fill)
878 _ao_radio_send_lots(fill, AO_RADIO_MODE_APRS);
883 static const char *cc115l_state_name[] = {
884 [CC115L_STATUS_STATE_IDLE] = "IDLE",
885 [CC115L_STATUS_STATE_TX] = "TX",
886 [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
887 [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE",
888 [CC115L_STATUS_STATE_SETTLING] = "SETTLING",
889 [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
892 static const struct ao_cc115l_reg ao_cc115l_reg[] = {
893 { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
894 { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
895 { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
896 { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" },
897 { .addr = CC115L_SYNC1, .name = "SYNC1" },
898 { .addr = CC115L_SYNC0, .name = "SYNC0" },
899 { .addr = CC115L_PKTLEN, .name = "PKTLEN" },
900 { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" },
901 { .addr = CC115L_CHANNR, .name = "CHANNR" },
902 { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" },
903 { .addr = CC115L_FREQ2, .name = "FREQ2" },
904 { .addr = CC115L_FREQ1, .name = "FREQ1" },
905 { .addr = CC115L_FREQ0, .name = "FREQ0" },
906 { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" },
907 { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" },
908 { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" },
909 { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" },
910 { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" },
911 { .addr = CC115L_DEVIATN, .name = "DEVIATN" },
912 { .addr = CC115L_MCSM1, .name = "MCSM1" },
913 { .addr = CC115L_MCSM0, .name = "MCSM0" },
914 { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" },
915 { .addr = CC115L_FREND0, .name = "FREND0" },
916 { .addr = CC115L_FSCAL3, .name = "FSCAL3" },
917 { .addr = CC115L_FSCAL2, .name = "FSCAL2" },
918 { .addr = CC115L_FSCAL1, .name = "FSCAL1" },
919 { .addr = CC115L_FSCAL0, .name = "FSCAL0" },
920 { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" },
921 { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" },
922 { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" },
923 { .addr = CC115L_TEST2, .name = "TEST2" },
924 { .addr = CC115L_TEST1, .name = "TEST1" },
925 { .addr = CC115L_TEST0, .name = "TEST0" },
926 { .addr = CC115L_PARTNUM, .name = "PARTNUM" },
927 { .addr = CC115L_VERSION, .name = "VERSION" },
928 { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" },
929 { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" },
930 { .addr = CC115L_TXBYTES, .name = "TXBYTES" },
931 { .addr = CC115L_PA, .name = "PA" },
934 #define AO_NUM_CC115L_REG (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0])
936 static void ao_radio_show(void) {
937 uint8_t status = ao_radio_status();
941 status = ao_radio_status();
942 printf ("Status: %02x\n", status);
943 printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1);
944 printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]);
945 printf ("MARC: %02x\n", ao_radio_get_marcstate());
947 for (i = 0; i < AO_NUM_CC115L_REG; i++)
948 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name);
952 static void ao_radio_beep(void) {
956 static void ao_radio_packet(void) {
957 static const uint8_t packet[] = {
959 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
960 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
961 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
962 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
968 ao_radio_send(packet, sizeof (packet));
979 ao_packet_slave_stop();
984 #endif /* CC115L_DEBUG */
986 static const struct ao_cmds ao_radio_cmds[] = {
987 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
990 { ao_radio_aprs, "G\0Send APRS packet" },
992 { ao_radio_show, "R\0Show CC115L status" },
993 { ao_radio_beep, "b\0Emit an RDF beacon" },
994 { ao_radio_packet, "p\0Send a test packet" },
1006 ao_radio_configured = 0;
1007 ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN));
1010 AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN));
1011 for (i = 0; i < 10000; i++) {
1012 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1015 AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN);
1017 ao_panic(AO_PANIC_SELF_TEST_CC115L);
1020 /* Enable the fifo threhold interrupt pin */
1021 ao_enable_port(AO_CC115L_FIFO_INT_PORT);
1022 ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN,
1023 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1026 /* Enable the tx done interrupt pin */
1027 ao_enable_port(AO_CC115L_DONE_INT_PORT);
1028 ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN,
1029 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1034 ao_cmd_register(&ao_radio_cmds[0]);