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 static 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 */
32 static uint8_t ao_radio_mcu_wake; /* MARC status change */
33 static uint8_t ao_radio_marcstate; /* Last read MARC state value */
35 /* Debugging commands */
36 #define CC115L_DEBUG 1
39 #define CC115L_TRACE 0
43 #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)
44 #define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)
45 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS)
46 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS)
47 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC115L_SPI_BUS)
48 #define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC115L_SPI_BUS)
50 struct ao_cc115l_reg {
57 const static struct ao_cc115l_reg ao_cc115l_reg[];
58 const static char *cc115l_state_name[];
60 enum ao_cc115l_trace_type {
68 struct ao_cc115l_trace {
69 enum ao_cc115l_trace_type type;
77 static struct ao_cc115l_trace trace[NUM_TRACE];
79 static int trace_disable;
81 static void trace_add(enum ao_cc115l_trace_type type, int16_t addr, int16_t value, const char *comment)
88 comment = ao_cc115l_reg[addr].name;
91 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)
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)
128 trace_add(trace_write, addr, value, NULL);
129 data[0] = ((0 << CC115L_READ) |
130 (0 << CC115L_BURST) |
134 ao_radio_spi_send(data, 2);
139 ao_radio_burst_read_start (uint16_t addr)
144 data[0] = ((1 << CC115L_READ) |
145 (1 << CC115L_BURST) |
148 ao_radio_spi_send(data, 1);
152 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);
204 ao_radio_status(void)
206 return ao_radio_strobe (CC115L_SNOP);
209 #define ao_radio_rdf_value 0x55
212 ao_radio_get_marcstate(void)
214 return ao_radio_reg_read(CC115L_MARCSTATE) & CC115L_MARCSTATE_MASK;
218 ao_radio_done_isr(void)
220 ao_exti_disable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
221 trace_add(trace_line, __LINE__, 0, "done_isr");
223 ao_wakeup(&ao_radio_wake);
227 ao_radio_fifo_isr(void)
229 ao_exti_disable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
230 trace_add(trace_line, __LINE__, 0, "fifo_isr");
232 ao_wakeup(&ao_radio_wake);
236 ao_radio_start_tx(void)
245 uint8_t state = ao_radio_strobe(CC115L_SIDLE);
246 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE)
249 /* Flush any pending TX bytes */
250 ao_radio_strobe(CC115L_SFTX);
254 * Packet deviation is 20.5kHz
256 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
258 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz
261 #define PACKET_DEV_E 3
262 #define PACKET_DEV_M 5
265 * For our packet data, set the symbol rate to 38400 Baud
267 * (256 + DATARATE_M) * 2 ** DATARATE_E
268 * Rdata = -------------------------------------- * fosc
271 * (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383
276 #define PACKET_DRATE_E 10
277 #define PACKET_DRATE_M 131
279 static const uint16_t packet_setup[] = {
280 CC115L_DEVIATN, ((PACKET_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
281 (PACKET_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
282 CC115L_MDMCFG4, ((0xf << 4) |
283 (PACKET_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
284 CC115L_MDMCFG3, (PACKET_DRATE_M),
289 * RDF deviation is 5kHz
291 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
293 * 26e6 / (2 ** 17) * (8 + 4) * (2 ** 1) = 4761Hz
300 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
302 * (256 + DATARATE_M) * 2 ** DATARATE_E
303 * Rdata = -------------------------------------- * fosc
306 * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
311 #define RDF_DRATE_E 6
312 #define RDF_DRATE_M 67
314 static const uint16_t rdf_setup[] = {
315 CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
316 (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
317 CC115L_MDMCFG4, ((0xf << 4) |
318 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
319 CC115L_MDMCFG3, (RDF_DRATE_M),
323 * APRS deviation is the same as RDF
326 #define APRS_DEV_E RDF_DEV_E
327 #define APRS_DEV_M RDF_DEV_M
330 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
332 * (256 + DATARATE_M) * 2 ** DATARATE_E
333 * Rdata = -------------------------------------- * fosc
336 * (256 + 131) * (2 ** 8) / (2**28) * 26e6 = 9596
342 #define APRS_DRATE_E 8
343 #define APRS_DRATE_M 131
345 static const uint16_t aprs_setup[] = {
346 CC115L_DEVIATN, ((APRS_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
347 (APRS_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
348 CC115L_MDMCFG4, ((0xf << 4) |
349 (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
350 CC115L_MDMCFG3, (APRS_DRATE_M),
353 #define AO_PKTCTRL0_INFINITE ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
354 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
355 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
356 #define AO_PKTCTRL0_FIXED ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
357 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
358 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
360 static uint16_t ao_radio_mode;
364 * These set the data rate and modulation parameters
366 #define AO_RADIO_MODE_BITS_PACKET_TX 1
367 #define AO_RADIO_MODE_BITS_RDF 2
368 #define AO_RADIO_MODE_BITS_APRS 4
371 * Flips between infinite packet mode and fixed packet mode;
372 * we use infinite mode until the sender gives us the
375 #define AO_RADIO_MODE_BITS_INFINITE 40
376 #define AO_RADIO_MODE_BITS_FIXED 80
378 #define AO_RADIO_MODE_NONE 0
380 #define AO_RADIO_MODE_RDF AO_RADIO_MODE_BITS_RDF
381 #define AO_RADIO_MODE_PACKET_TX AO_RADIO_MODE_BITS_PACKET_TX
382 #define AO_RADIO_MODE_APRS AO_RADIO_MODE_BITS_APRS
385 ao_radio_set_mode(uint16_t new_mode)
390 if (new_mode == ao_radio_mode)
393 changes = new_mode & (~ao_radio_mode);
394 if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
395 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
396 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
398 if (changes & AO_RADIO_MODE_BITS_RDF)
399 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
400 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
402 if (changes & AO_RADIO_MODE_BITS_APRS)
403 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
404 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
406 if (changes & AO_RADIO_MODE_BITS_INFINITE)
407 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_INFINITE);
409 if (changes & AO_RADIO_MODE_BITS_FIXED)
410 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_FIXED);
412 ao_radio_mode = new_mode;
415 /***************************************************************
416 * SmartRF Studio(tm) Export
418 * Radio register settings specifed with address, value
422 ***************************************************************/
424 static const uint16_t radio_setup[] = {
426 /* High when FIFO is above threshold, low when fifo is below threshold */
427 AO_CC115L_FIFO_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR,
429 /* High when transmitter is running, low when off */
430 AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV),
432 CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */
433 CC115L_PKTCTRL0, 0x05, /* Packet Automation Control */
434 CC115L_FREQ2, 0x10, /* Frequency Control Word, High Byte */
435 CC115L_FREQ1, 0xb6, /* Frequency Control Word, Middle Byte */
436 CC115L_FREQ0, 0xa5, /* Frequency Control Word, Low Byte */
437 CC115L_MDMCFG4, 0xfa, /* Modem Configuration */
438 CC115L_MDMCFG3, 0x83, /* Modem Configuration */
439 CC115L_MDMCFG2, 0x13, /* Modem Configuration */
440 CC115L_MDMCFG1, 0x21, /* Modem Configuration */
441 CC115L_DEVIATN, 0x35, /* Modem Deviation Setting */
442 CC115L_MCSM0, 0x18, /* Main Radio Control State Machine Configuration */
443 CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */
444 CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */
445 CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */
446 CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */
447 CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */
448 CC115L_TEST2, 0x81, /* Various Test Settings */
449 CC115L_TEST1, 0x35, /* Various Test Settings */
450 CC115L_TEST0, 0x09, /* Various Test Settings */
452 CC115L_PA, 0x00, /* Power setting (0dBm) */
455 static uint8_t ao_radio_configured = 0;
462 ao_radio_strobe(CC115L_SRES);
463 ao_delay(AO_MS_TO_TICKS(10));
465 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
466 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
472 ao_radio_configured = 1;
476 ao_radio_set_len(uint8_t len)
478 static uint8_t last_len;
480 if (len != last_len) {
481 ao_radio_reg_write(CC115L_PKTLEN, len);
489 static uint32_t last_radio_setting;
490 static uint8_t last_power_setting;
492 ao_mutex_get(&ao_radio_mutex);
493 if (!ao_radio_configured)
495 if (ao_config.radio_setting != last_radio_setting) {
496 ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16);
497 ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);
498 ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
499 last_radio_setting = ao_config.radio_setting;
501 if (ao_config.radio_power != last_power_setting) {
502 ao_radio_reg_write(CC115L_PA, ao_config.radio_power);
503 last_power_setting = ao_config.radio_power;
508 ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
510 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
512 struct ao_radio_tone {
517 struct ao_radio_tone *ao_radio_tone;
518 uint8_t ao_radio_tone_count;
519 uint8_t ao_radio_tone_current;
520 uint8_t ao_radio_tone_offset;
523 ao_radio_tone_fill(uint8_t *buf, int16_t len)
529 struct ao_radio_tone *t;
531 /* Figure out how many to send of the current value */
532 t = &ao_radio_tone[ao_radio_tone_current];
533 this_time = t->len - ao_radio_tone_offset;
538 memset(buf, t->value, this_time);
542 ao_radio_tone_offset += this_time;
545 if (ao_radio_tone_offset >= t->len) {
546 ao_radio_tone_offset = 0;
547 ao_radio_tone_current++;
548 if (ao_radio_tone_current >= ao_radio_tone_count) {
549 trace_add(trace_line, __LINE__, ret, "done with tone");
554 trace_add(trace_line, __LINE__, ret, "got some tone");
559 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
561 ao_radio_tone = tones;
562 ao_radio_tone_current = 0;
563 ao_radio_tone_offset = 0;
564 ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
570 struct ao_radio_tone tone;
572 tone.value = ao_radio_rdf_value;
573 tone.len = AO_RADIO_RDF_LEN;
574 ao_radio_tone_run(&tone, 1);
578 ao_radio_continuity(uint8_t c)
580 struct ao_radio_tone tones[7];
584 for (i = 0; i < 3; i++) {
585 tones[count].value = 0x00;
586 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
589 tones[count].value = ao_radio_rdf_value;
591 tones[count].value = 0x00;
592 tones[count].len = AO_RADIO_CONT_TONE_LEN;
595 tones[count].value = 0x00;
596 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
598 ao_radio_tone_run(tones, count);
602 ao_radio_rdf_abort(void)
605 ao_wakeup(&ao_radio_wake);
609 ao_radio_test_cmd(void)
612 static uint8_t radio_on;
614 if (ao_cmd_lex_c != '\n') {
616 mode = (uint8_t) ao_cmd_lex_u32;
619 if ((mode & 2) && !radio_on) {
621 ao_monitor_disable();
624 ao_packet_slave_stop();
627 ao_radio_set_len(0xff);
628 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX | AO_RADIO_MODE_BITS_FIXED);
629 ao_radio_strobe(CC115L_SFTX);
631 ao_radio_strobe(CC115L_STX);
635 printf ("Hit a character to stop..."); flush();
639 if ((mode & 1) && radio_on) {
649 static inline int16_t
650 ao_radio_gpio_bits(void)
652 return AO_CC115L_DONE_INT_PORT->idr & ((1 << AO_CC115L_FIFO_INT_PIN) |
653 (1 << AO_CC115L_DONE_INT_PIN));
657 ao_radio_wait_fifo(void)
659 ao_arch_block_interrupts();
660 while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) {
661 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo");
662 ao_sleep(&ao_radio_wake);
664 ao_arch_release_interrupts();
665 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
666 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
667 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
668 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
672 ao_radio_wait_done(void)
674 ao_arch_block_interrupts();
675 while (!ao_radio_done && !ao_radio_abort) {
676 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done");
677 ao_sleep(&ao_radio_wake);
679 ao_arch_release_interrupts();
680 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
681 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
682 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
683 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
686 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
688 static uint8_t *ao_radio_send_buf;
689 static int16_t ao_radio_send_len;
692 ao_radio_send_fill(uint8_t *buf, int16_t len)
696 this_time = ao_radio_send_len;
699 memcpy(buf, ao_radio_send_buf, this_time);
700 ao_radio_send_buf += this_time;
701 ao_radio_send_len -= this_time;
702 if (ao_radio_send_len == 0)
708 ao_radio_send(const void *d, uint8_t size)
710 ao_radio_send_len = ao_fec_encode(d, size, tx_data);
711 ao_radio_send_buf = tx_data;
712 ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX);
715 #define AO_RADIO_LOTS 64
718 ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
720 uint8_t buf[AO_RADIO_LOTS], *b;
728 fifo_space = CC115L_FIFO_SIZE;
732 cnt = (*fill)(buf, sizeof(buf));
733 trace_add(trace_line, __LINE__, cnt, "send data count");
740 /* At the last buffer, set the total length */
742 ao_radio_set_len(total & 0xff);
743 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED);
745 ao_radio_set_len(0xff);
746 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE);
751 uint8_t this_len = cnt;
753 /* Wait for some space in the fifo */
754 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
755 trace_add(trace_line, __LINE__, this_len, "wait for space");
756 ao_radio_wait_fifo();
758 if (ao_radio_abort || ao_radio_done)
760 trace_add(trace_line, __LINE__, fifo_space, "got space");
761 if (this_len > fifo_space)
762 this_len = fifo_space;
768 ao_radio_fifo_write(b, this_len);
771 ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
772 ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
776 ao_radio_strobe(CC115L_STX);
780 if (ao_radio_abort || ao_radio_done)
785 ao_radio_wait_done();
791 ao_radio_send_aprs(ao_radio_fill_func fill)
793 ao_radio_send_lots(fill, AO_RADIO_MODE_APRS);
797 const static char *cc115l_state_name[] = {
798 [CC115L_STATUS_STATE_IDLE] = "IDLE",
799 [CC115L_STATUS_STATE_TX] = "TX",
800 [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
801 [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE",
802 [CC115L_STATUS_STATE_SETTLING] = "SETTLING",
803 [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
806 const static struct ao_cc115l_reg ao_cc115l_reg[] = {
807 { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
808 { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
809 { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
810 { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" },
811 { .addr = CC115L_SYNC1, .name = "SYNC1" },
812 { .addr = CC115L_SYNC0, .name = "SYNC0" },
813 { .addr = CC115L_PKTLEN, .name = "PKTLEN" },
814 { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" },
815 { .addr = CC115L_CHANNR, .name = "CHANNR" },
816 { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" },
817 { .addr = CC115L_FREQ2, .name = "FREQ2" },
818 { .addr = CC115L_FREQ1, .name = "FREQ1" },
819 { .addr = CC115L_FREQ0, .name = "FREQ0" },
820 { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" },
821 { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" },
822 { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" },
823 { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" },
824 { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" },
825 { .addr = CC115L_DEVIATN, .name = "DEVIATN" },
826 { .addr = CC115L_MCSM1, .name = "MCSM1" },
827 { .addr = CC115L_MCSM0, .name = "MCSM0" },
828 { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" },
829 { .addr = CC115L_FREND0, .name = "FREND0" },
830 { .addr = CC115L_FSCAL3, .name = "FSCAL3" },
831 { .addr = CC115L_FSCAL2, .name = "FSCAL2" },
832 { .addr = CC115L_FSCAL1, .name = "FSCAL1" },
833 { .addr = CC115L_FSCAL0, .name = "FSCAL0" },
834 { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" },
835 { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" },
836 { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" },
837 { .addr = CC115L_TEST2, .name = "TEST2" },
838 { .addr = CC115L_TEST1, .name = "TEST1" },
839 { .addr = CC115L_TEST0, .name = "TEST0" },
840 { .addr = CC115L_PARTNUM, .name = "PARTNUM" },
841 { .addr = CC115L_VERSION, .name = "VERSION" },
842 { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" },
843 { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" },
844 { .addr = CC115L_TXBYTES, .name = "TXBYTES" },
845 { .addr = CC115L_PA, .name = "PA" },
848 #define AO_NUM_CC115L_REG (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0])
850 static void ao_radio_show(void) {
851 uint8_t status = ao_radio_status();
855 status = ao_radio_status();
856 printf ("Status: %02x\n", status);
857 printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1);
858 printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]);
859 printf ("MARC: %02x\n", ao_radio_get_marcstate());
861 for (i = 0; i < AO_NUM_CC115L_REG; i++)
862 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name);
866 static void ao_radio_beep(void) {
870 static void ao_radio_packet(void) {
871 static const uint8_t packet[] = {
873 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
874 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
875 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
876 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
882 ao_radio_send(packet, sizeof (packet));
885 #endif /* CC115L_DEBUG */
894 ao_packet_slave_stop();
900 static const struct ao_cmds ao_radio_cmds[] = {
901 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
904 { ao_radio_aprs, "G\0Send APRS packet" },
906 { ao_radio_show, "R\0Show CC115L status" },
907 { ao_radio_beep, "b\0Emit an RDF beacon" },
908 { ao_radio_packet, "p\0Send a test packet" },
918 ao_radio_configured = 0;
919 ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN));
922 AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN));
923 for (i = 0; i < 10000; i++) {
924 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
927 AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN);
929 ao_panic(AO_PANIC_SELF_TEST_CC115L);
932 /* Enable the fifo threhold interrupt pin */
933 ao_enable_port(AO_CC115L_FIFO_INT_PORT);
934 ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN,
935 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
938 /* Enable the tx done interrupt pin */
939 ao_enable_port(AO_CC115L_DONE_INT_PORT);
940 ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN,
941 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
946 ao_cmd_register(&ao_radio_cmds[0]);