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),
285 CC115L_MDMCFG2, (0x00 |
286 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
287 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
288 (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),
293 * RDF deviation is 5kHz
295 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
297 * 26e6 / (2 ** 17) * (8 + 4) * (2 ** 1) = 4761Hz
304 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
306 * (256 + DATARATE_M) * 2 ** DATARATE_E
307 * Rdata = -------------------------------------- * fosc
310 * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
315 #define RDF_DRATE_E 6
316 #define RDF_DRATE_M 67
318 static const uint16_t rdf_setup[] = {
319 CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
320 (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
321 CC115L_MDMCFG4, ((0xf << 4) |
322 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
323 CC115L_MDMCFG3, (RDF_DRATE_M),
324 CC115L_MDMCFG2, (0x00 |
325 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
326 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
327 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
331 * APRS deviation is the same as RDF
334 #define APRS_DEV_E RDF_DEV_E
335 #define APRS_DEV_M RDF_DEV_M
338 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
340 * (256 + DATARATE_M) * 2 ** DATARATE_E
341 * Rdata = -------------------------------------- * fosc
344 * (256 + 131) * (2 ** 8) / (2**28) * 26e6 = 9596
350 #define APRS_DRATE_E 8
351 #define APRS_DRATE_M 131
353 static const uint16_t aprs_setup[] = {
354 CC115L_DEVIATN, ((APRS_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
355 (APRS_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
356 CC115L_MDMCFG4, ((0xf << 4) |
357 (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
358 CC115L_MDMCFG3, (APRS_DRATE_M),
359 CC115L_MDMCFG2, (0x00 |
360 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
361 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
362 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
365 #define AO_PKTCTRL0_INFINITE ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
366 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
367 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
368 #define AO_PKTCTRL0_FIXED ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
369 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
370 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
372 static uint16_t ao_radio_mode;
376 * These set the data rate and modulation parameters
378 #define AO_RADIO_MODE_BITS_PACKET_TX 1
379 #define AO_RADIO_MODE_BITS_RDF 2
380 #define AO_RADIO_MODE_BITS_APRS 4
383 * Flips between infinite packet mode and fixed packet mode;
384 * we use infinite mode until the sender gives us the
387 #define AO_RADIO_MODE_BITS_INFINITE 40
388 #define AO_RADIO_MODE_BITS_FIXED 80
390 #define AO_RADIO_MODE_NONE 0
392 #define AO_RADIO_MODE_RDF AO_RADIO_MODE_BITS_RDF
393 #define AO_RADIO_MODE_PACKET_TX AO_RADIO_MODE_BITS_PACKET_TX
394 #define AO_RADIO_MODE_APRS AO_RADIO_MODE_BITS_APRS
397 ao_radio_set_mode(uint16_t new_mode)
402 if (new_mode == ao_radio_mode)
405 changes = new_mode & (~ao_radio_mode);
406 if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
407 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
408 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
410 if (changes & AO_RADIO_MODE_BITS_RDF)
411 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
412 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
414 if (changes & AO_RADIO_MODE_BITS_APRS)
415 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
416 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
418 if (changes & AO_RADIO_MODE_BITS_INFINITE)
419 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_INFINITE);
421 if (changes & AO_RADIO_MODE_BITS_FIXED)
422 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_FIXED);
424 ao_radio_mode = new_mode;
427 /***************************************************************
428 * SmartRF Studio(tm) Export
430 * Radio register settings specifed with address, value
434 ***************************************************************/
436 static const uint16_t radio_setup[] = {
438 /* High when FIFO is above threshold, low when fifo is below threshold */
439 AO_CC115L_FIFO_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR,
441 /* High when transmitter is running, low when off */
442 AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV),
444 CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */
445 CC115L_FREQ2, 0x10, /* Frequency Control Word, High Byte */
446 CC115L_FREQ1, 0xb6, /* Frequency Control Word, Middle Byte */
447 CC115L_FREQ0, 0xa5, /* Frequency Control Word, Low Byte */
448 CC115L_MDMCFG2, 0x13, /* Modem Configuration */
449 CC115L_MDMCFG1, (0x00 |
450 (CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) |
451 (1 << CC115L_MDMCFG1_CHANSPC_E)),
452 CC115L_MDMCFG0, 248, /* Channel spacing M value (100kHz channels) */
453 CC115L_DEVIATN, 0x35, /* Modem Deviation Setting */
454 CC115L_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */
455 CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */
456 CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */
457 CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */
458 CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */
459 CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */
460 CC115L_TEST2, 0x81, /* Various Test Settings */
461 CC115L_TEST1, 0x35, /* Various Test Settings */
462 CC115L_TEST0, 0x09, /* Various Test Settings */
463 CC115L_PA, 0x00, /* Power setting (as low as possible) */
466 static uint8_t ao_radio_configured = 0;
473 ao_radio_strobe(CC115L_SRES);
474 ao_delay(AO_MS_TO_TICKS(10));
476 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
477 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
483 ao_radio_configured = 1;
487 ao_radio_set_len(uint8_t len)
489 static uint8_t last_len;
491 if (len != last_len) {
492 ao_radio_reg_write(CC115L_PKTLEN, len);
500 static uint32_t last_radio_setting;
501 static uint8_t last_power_setting;
503 ao_mutex_get(&ao_radio_mutex);
504 if (!ao_radio_configured)
506 if (ao_config.radio_setting != last_radio_setting) {
507 ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16);
508 ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);
509 ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
510 last_radio_setting = ao_config.radio_setting;
512 if (ao_config.radio_power != last_power_setting) {
513 ao_radio_reg_write(CC115L_PA, ao_config.radio_power);
514 last_power_setting = ao_config.radio_power;
519 ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
521 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
523 struct ao_radio_tone {
528 struct ao_radio_tone *ao_radio_tone;
529 uint8_t ao_radio_tone_count;
530 uint8_t ao_radio_tone_current;
531 uint8_t ao_radio_tone_offset;
534 ao_radio_tone_fill(uint8_t *buf, int16_t len)
540 struct ao_radio_tone *t;
542 /* Figure out how many to send of the current value */
543 t = &ao_radio_tone[ao_radio_tone_current];
544 this_time = t->len - ao_radio_tone_offset;
549 memset(buf, t->value, this_time);
553 ao_radio_tone_offset += this_time;
556 if (ao_radio_tone_offset >= t->len) {
557 ao_radio_tone_offset = 0;
558 ao_radio_tone_current++;
559 if (ao_radio_tone_current >= ao_radio_tone_count) {
560 trace_add(trace_line, __LINE__, ret, "done with tone");
565 trace_add(trace_line, __LINE__, ret, "got some tone");
570 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
572 ao_radio_tone = tones;
573 ao_radio_tone_current = 0;
574 ao_radio_tone_offset = 0;
575 ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
581 struct ao_radio_tone tone;
583 tone.value = ao_radio_rdf_value;
584 tone.len = AO_RADIO_RDF_LEN;
585 ao_radio_tone_run(&tone, 1);
589 ao_radio_continuity(uint8_t c)
591 struct ao_radio_tone tones[7];
595 for (i = 0; i < 3; i++) {
596 tones[count].value = 0x00;
597 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
600 tones[count].value = ao_radio_rdf_value;
602 tones[count].value = 0x00;
603 tones[count].len = AO_RADIO_CONT_TONE_LEN;
606 tones[count].value = 0x00;
607 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
609 ao_radio_tone_run(tones, count);
613 ao_radio_rdf_abort(void)
616 ao_wakeup(&ao_radio_wake);
620 ao_radio_test_cmd(void)
623 static uint8_t radio_on;
625 if (ao_cmd_lex_c != '\n') {
627 mode = (uint8_t) ao_cmd_lex_u32;
630 if ((mode & 2) && !radio_on) {
632 ao_monitor_disable();
635 ao_packet_slave_stop();
638 ao_radio_set_len(0xff);
639 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX | AO_RADIO_MODE_BITS_FIXED);
640 ao_radio_strobe(CC115L_SFTX);
642 ao_radio_strobe(CC115L_STX);
646 printf ("Hit a character to stop..."); flush();
650 if ((mode & 1) && radio_on) {
660 static inline int16_t
661 ao_radio_gpio_bits(void)
663 return AO_CC115L_DONE_INT_PORT->idr & ((1 << AO_CC115L_FIFO_INT_PIN) |
664 (1 << AO_CC115L_DONE_INT_PIN));
668 ao_radio_wait_fifo(void)
670 ao_arch_block_interrupts();
671 while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) {
672 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo");
673 ao_sleep(&ao_radio_wake);
675 ao_arch_release_interrupts();
676 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
677 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
678 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
679 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
683 ao_radio_wait_done(void)
685 ao_arch_block_interrupts();
686 while (!ao_radio_done && !ao_radio_abort) {
687 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done");
688 ao_sleep(&ao_radio_wake);
690 ao_arch_release_interrupts();
691 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
692 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
693 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
694 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
697 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
699 static uint8_t *ao_radio_send_buf;
700 static int16_t ao_radio_send_len;
703 ao_radio_send_fill(uint8_t *buf, int16_t len)
707 this_time = ao_radio_send_len;
710 memcpy(buf, ao_radio_send_buf, this_time);
711 ao_radio_send_buf += this_time;
712 ao_radio_send_len -= this_time;
713 if (ao_radio_send_len == 0)
719 ao_radio_send(const void *d, uint8_t size)
721 ao_radio_send_len = ao_fec_encode(d, size, tx_data);
722 ao_radio_send_buf = tx_data;
723 ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX);
726 #define AO_RADIO_LOTS 64
729 ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
731 uint8_t buf[AO_RADIO_LOTS], *b;
739 fifo_space = CC115L_FIFO_SIZE;
743 cnt = (*fill)(buf, sizeof(buf));
744 trace_add(trace_line, __LINE__, cnt, "send data count");
751 /* At the last buffer, set the total length */
753 ao_radio_set_len(total & 0xff);
754 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED);
756 ao_radio_set_len(0xff);
757 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE);
762 uint8_t this_len = cnt;
764 /* Wait for some space in the fifo */
765 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
766 trace_add(trace_line, __LINE__, this_len, "wait for space");
767 ao_radio_wait_fifo();
769 if (ao_radio_abort || ao_radio_done)
771 trace_add(trace_line, __LINE__, fifo_space, "got space");
772 if (this_len > fifo_space)
773 this_len = fifo_space;
779 ao_radio_fifo_write(b, this_len);
782 ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
783 ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
787 ao_radio_strobe(CC115L_STX);
791 if (ao_radio_abort || ao_radio_done)
796 ao_radio_wait_done();
802 ao_radio_send_aprs(ao_radio_fill_func fill)
804 ao_radio_send_lots(fill, AO_RADIO_MODE_APRS);
808 const static char *cc115l_state_name[] = {
809 [CC115L_STATUS_STATE_IDLE] = "IDLE",
810 [CC115L_STATUS_STATE_TX] = "TX",
811 [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
812 [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE",
813 [CC115L_STATUS_STATE_SETTLING] = "SETTLING",
814 [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
817 const static struct ao_cc115l_reg ao_cc115l_reg[] = {
818 { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
819 { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
820 { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
821 { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" },
822 { .addr = CC115L_SYNC1, .name = "SYNC1" },
823 { .addr = CC115L_SYNC0, .name = "SYNC0" },
824 { .addr = CC115L_PKTLEN, .name = "PKTLEN" },
825 { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" },
826 { .addr = CC115L_CHANNR, .name = "CHANNR" },
827 { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" },
828 { .addr = CC115L_FREQ2, .name = "FREQ2" },
829 { .addr = CC115L_FREQ1, .name = "FREQ1" },
830 { .addr = CC115L_FREQ0, .name = "FREQ0" },
831 { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" },
832 { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" },
833 { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" },
834 { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" },
835 { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" },
836 { .addr = CC115L_DEVIATN, .name = "DEVIATN" },
837 { .addr = CC115L_MCSM1, .name = "MCSM1" },
838 { .addr = CC115L_MCSM0, .name = "MCSM0" },
839 { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" },
840 { .addr = CC115L_FREND0, .name = "FREND0" },
841 { .addr = CC115L_FSCAL3, .name = "FSCAL3" },
842 { .addr = CC115L_FSCAL2, .name = "FSCAL2" },
843 { .addr = CC115L_FSCAL1, .name = "FSCAL1" },
844 { .addr = CC115L_FSCAL0, .name = "FSCAL0" },
845 { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" },
846 { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" },
847 { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" },
848 { .addr = CC115L_TEST2, .name = "TEST2" },
849 { .addr = CC115L_TEST1, .name = "TEST1" },
850 { .addr = CC115L_TEST0, .name = "TEST0" },
851 { .addr = CC115L_PARTNUM, .name = "PARTNUM" },
852 { .addr = CC115L_VERSION, .name = "VERSION" },
853 { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" },
854 { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" },
855 { .addr = CC115L_TXBYTES, .name = "TXBYTES" },
856 { .addr = CC115L_PA, .name = "PA" },
859 #define AO_NUM_CC115L_REG (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0])
861 static void ao_radio_show(void) {
862 uint8_t status = ao_radio_status();
866 status = ao_radio_status();
867 printf ("Status: %02x\n", status);
868 printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1);
869 printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]);
870 printf ("MARC: %02x\n", ao_radio_get_marcstate());
872 for (i = 0; i < AO_NUM_CC115L_REG; i++)
873 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name);
877 static void ao_radio_beep(void) {
881 static void ao_radio_packet(void) {
882 static const uint8_t packet[] = {
884 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
885 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
886 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
887 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
893 ao_radio_send(packet, sizeof (packet));
896 #endif /* CC115L_DEBUG */
905 ao_packet_slave_stop();
911 static const struct ao_cmds ao_radio_cmds[] = {
912 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
915 { ao_radio_aprs, "G\0Send APRS packet" },
917 { ao_radio_show, "R\0Show CC115L status" },
918 { ao_radio_beep, "b\0Emit an RDF beacon" },
919 { ao_radio_packet, "p\0Send a test packet" },
929 ao_radio_configured = 0;
930 ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN));
933 AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN));
934 for (i = 0; i < 10000; i++) {
935 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
938 AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN);
940 ao_panic(AO_PANIC_SELF_TEST_CC115L);
943 /* Enable the fifo threhold interrupt pin */
944 ao_enable_port(AO_CC115L_FIFO_INT_PORT);
945 ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN,
946 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
949 /* Enable the tx done interrupt pin */
950 ao_enable_port(AO_CC115L_DONE_INT_PORT);
951 ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN,
952 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
957 ao_cmd_register(&ao_radio_cmds[0]);