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);
252 * Packet deviation is 20.5kHz
254 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
256 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz
259 #define PACKET_DEV_E 3
260 #define PACKET_DEV_M 5
263 * For our packet data, set the symbol rate to 38400 Baud
265 * (256 + DATARATE_M) * 2 ** DATARATE_E
266 * Rdata = -------------------------------------- * fosc
269 * (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383
274 #define PACKET_DRATE_E 10
275 #define PACKET_DRATE_M 131
277 static const uint16_t packet_setup[] = {
278 CC115L_DEVIATN, ((PACKET_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
279 (PACKET_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
280 CC115L_MDMCFG4, ((0xf << 4) |
281 (PACKET_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
282 CC115L_MDMCFG3, (PACKET_DRATE_M),
283 CC115L_MDMCFG2, (0x00 |
284 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
285 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
286 (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),
291 * RDF deviation is 5kHz
293 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
295 * 26e6 / (2 ** 17) * (8 + 4) * (2 ** 1) = 4761Hz
302 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
304 * (256 + DATARATE_M) * 2 ** DATARATE_E
305 * Rdata = -------------------------------------- * fosc
308 * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
313 #define RDF_DRATE_E 6
314 #define RDF_DRATE_M 67
316 static const uint16_t rdf_setup[] = {
317 CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
318 (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
319 CC115L_MDMCFG4, ((0xf << 4) |
320 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
321 CC115L_MDMCFG3, (RDF_DRATE_M),
322 CC115L_MDMCFG2, (0x00 |
323 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
324 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
325 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
329 * APRS deviation is 3kHz
331 * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
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_MDMCFG1, (0x00 |
446 (CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) |
447 (1 << CC115L_MDMCFG1_CHANSPC_E)),
448 CC115L_MDMCFG0, 248, /* Channel spacing M value (100kHz channels) */
449 CC115L_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */
450 CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */
451 CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */
452 CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */
453 CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */
454 CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */
455 CC115L_TEST2, 0x81, /* Various Test Settings */
456 CC115L_TEST1, 0x35, /* Various Test Settings */
457 CC115L_TEST0, 0x09, /* Various Test Settings */
460 static uint8_t ao_radio_configured = 0;
467 ao_radio_strobe(CC115L_SRES);
468 ao_delay(AO_MS_TO_TICKS(10));
470 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
471 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
477 ao_radio_strobe(CC115L_SCAL);
479 ao_radio_configured = 1;
483 ao_radio_set_len(uint8_t len)
485 static uint8_t last_len;
487 if (len != last_len) {
488 ao_radio_reg_write(CC115L_PKTLEN, len);
496 static uint32_t last_radio_setting;
498 ao_mutex_get(&ao_radio_mutex);
499 if (!ao_radio_configured)
501 if (ao_config.radio_setting != last_radio_setting) {
502 ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16);
503 ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);
504 ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
505 last_radio_setting = ao_config.radio_setting;
510 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
512 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
514 struct ao_radio_tone {
519 struct ao_radio_tone *ao_radio_tone;
520 uint8_t ao_radio_tone_count;
521 uint8_t ao_radio_tone_current;
522 uint8_t ao_radio_tone_offset;
525 ao_radio_tone_fill(uint8_t *buf, int16_t len)
531 struct ao_radio_tone *t;
533 /* Figure out how many to send of the current value */
534 t = &ao_radio_tone[ao_radio_tone_current];
535 this_time = t->len - ao_radio_tone_offset;
540 memset(buf, t->value, this_time);
544 ao_radio_tone_offset += this_time;
547 if (ao_radio_tone_offset >= t->len) {
548 ao_radio_tone_offset = 0;
549 ao_radio_tone_current++;
550 if (ao_radio_tone_current >= ao_radio_tone_count) {
551 trace_add(trace_line, __LINE__, ret, "done with tone");
556 trace_add(trace_line, __LINE__, ret, "got some tone");
561 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
564 ao_radio_tone = tones;
565 ao_radio_tone_current = 0;
566 ao_radio_tone_offset = 0;
567 ao_radio_tone_count = ntones;
568 _ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
575 struct ao_radio_tone tone;
577 tone.value = ao_radio_rdf_value;
578 tone.len = AO_RADIO_RDF_LEN;
579 ao_radio_tone_run(&tone, 1);
583 ao_radio_continuity(uint8_t c)
585 struct ao_radio_tone tones[7];
589 for (i = 0; i < 3; i++) {
590 tones[count].value = 0x00;
591 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
594 tones[count].value = ao_radio_rdf_value;
596 tones[count].value = 0x00;
597 tones[count].len = AO_RADIO_CONT_TONE_LEN;
600 tones[count].value = 0x00;
601 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
603 ao_radio_tone_run(tones, count);
607 ao_radio_rdf_abort(void)
610 ao_wakeup(&ao_radio_wake);
613 #define POWER_STEP 0x08
616 #define RADIO_POWER ao_config.radio_power
618 #define RADIO_POWER 0xc0
626 ao_radio_reg_write(CC115L_PA, 0);
627 ao_radio_strobe(CC115L_STX);
628 for (power = POWER_STEP; power < RADIO_POWER; power += POWER_STEP)
629 ao_radio_reg_write(CC115L_PA, power);
630 if (power != RADIO_POWER)
631 ao_radio_reg_write(CC115L_PA, RADIO_POWER);
635 ao_radio_test_cmd(void)
638 static uint8_t radio_on;
640 if (ao_cmd_lex_c != '\n') {
642 mode = (uint8_t) ao_cmd_lex_u32;
645 if ((mode & 2) && !radio_on) {
647 ao_monitor_disable();
650 ao_packet_slave_stop();
653 ao_radio_strobe(CC115L_SFTX);
654 ao_radio_set_len(0xff);
655 ao_radio_set_mode(AO_RADIO_MODE_RDF);
660 printf ("Hit a character to stop..."); flush();
664 if ((mode & 1) && radio_on) {
675 static inline int16_t
676 ao_radio_gpio_bits(void)
678 return ((ao_gpio_get(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN, AO_CC115L_DONE_INT) << 1) |
679 ao_gpio_get(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN, AO_CC115L_FIFO_INT));
684 ao_radio_wait_fifo(void)
686 ao_arch_block_interrupts();
687 while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) {
688 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo");
689 ao_sleep(&ao_radio_wake);
691 ao_arch_release_interrupts();
692 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
693 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
694 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
695 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
699 ao_radio_wait_done(void)
701 ao_arch_block_interrupts();
702 while (!ao_radio_done && !ao_radio_abort) {
703 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done");
704 ao_sleep(&ao_radio_wake);
706 ao_arch_release_interrupts();
707 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
708 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
709 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
710 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
713 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
715 static uint8_t *ao_radio_send_buf;
716 static int16_t ao_radio_send_len;
719 ao_radio_send_fill(uint8_t *buf, int16_t len)
723 this_time = ao_radio_send_len;
726 memcpy(buf, ao_radio_send_buf, this_time);
727 ao_radio_send_buf += this_time;
728 ao_radio_send_len -= this_time;
729 if (ao_radio_send_len == 0)
735 ao_radio_send(const void *d, uint8_t size)
738 ao_radio_send_len = ao_fec_encode(d, size, tx_data);
739 ao_radio_send_buf = tx_data;
740 _ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX);
744 #define AO_RADIO_LOTS 64
747 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
749 uint8_t buf[AO_RADIO_LOTS], *b;
756 fifo_space = CC115L_FIFO_SIZE;
759 ao_radio_strobe(CC115L_SFTX);
764 cnt = (*fill)(buf, sizeof(buf));
765 trace_add(trace_line, __LINE__, cnt, "send data count");
772 /* At the last buffer, set the total length */
774 ao_radio_set_len(total & 0xff);
775 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED);
777 ao_radio_set_len(0xff);
778 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE);
783 uint8_t this_len = cnt;
785 /* Wait for some space in the fifo */
786 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
787 trace_add(trace_line, __LINE__, this_len, "wait for space");
788 ao_radio_wait_fifo();
790 if (ao_radio_abort || ao_radio_done)
792 trace_add(trace_line, __LINE__, fifo_space, "got space");
793 if (this_len > fifo_space)
794 this_len = fifo_space;
800 ao_radio_fifo_write(b, this_len);
803 ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
804 ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
811 if (ao_radio_abort || ao_radio_done)
816 ao_radio_wait_done();
821 ao_radio_send_aprs(ao_radio_fill_func fill)
824 _ao_radio_send_lots(fill, AO_RADIO_MODE_APRS);
829 static const char *cc115l_state_name[] = {
830 [CC115L_STATUS_STATE_IDLE] = "IDLE",
831 [CC115L_STATUS_STATE_TX] = "TX",
832 [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
833 [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE",
834 [CC115L_STATUS_STATE_SETTLING] = "SETTLING",
835 [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
838 static const struct ao_cc115l_reg ao_cc115l_reg[] = {
839 { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
840 { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
841 { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
842 { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" },
843 { .addr = CC115L_SYNC1, .name = "SYNC1" },
844 { .addr = CC115L_SYNC0, .name = "SYNC0" },
845 { .addr = CC115L_PKTLEN, .name = "PKTLEN" },
846 { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" },
847 { .addr = CC115L_CHANNR, .name = "CHANNR" },
848 { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" },
849 { .addr = CC115L_FREQ2, .name = "FREQ2" },
850 { .addr = CC115L_FREQ1, .name = "FREQ1" },
851 { .addr = CC115L_FREQ0, .name = "FREQ0" },
852 { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" },
853 { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" },
854 { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" },
855 { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" },
856 { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" },
857 { .addr = CC115L_DEVIATN, .name = "DEVIATN" },
858 { .addr = CC115L_MCSM1, .name = "MCSM1" },
859 { .addr = CC115L_MCSM0, .name = "MCSM0" },
860 { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" },
861 { .addr = CC115L_FREND0, .name = "FREND0" },
862 { .addr = CC115L_FSCAL3, .name = "FSCAL3" },
863 { .addr = CC115L_FSCAL2, .name = "FSCAL2" },
864 { .addr = CC115L_FSCAL1, .name = "FSCAL1" },
865 { .addr = CC115L_FSCAL0, .name = "FSCAL0" },
866 { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" },
867 { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" },
868 { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" },
869 { .addr = CC115L_TEST2, .name = "TEST2" },
870 { .addr = CC115L_TEST1, .name = "TEST1" },
871 { .addr = CC115L_TEST0, .name = "TEST0" },
872 { .addr = CC115L_PARTNUM, .name = "PARTNUM" },
873 { .addr = CC115L_VERSION, .name = "VERSION" },
874 { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" },
875 { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" },
876 { .addr = CC115L_TXBYTES, .name = "TXBYTES" },
877 { .addr = CC115L_PA, .name = "PA" },
880 #define AO_NUM_CC115L_REG (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0])
882 static void ao_radio_show(void) {
883 uint8_t status = ao_radio_status();
887 status = ao_radio_status();
888 printf ("Status: %02x\n", status);
889 printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1);
890 printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]);
891 printf ("MARC: %02x\n", ao_radio_get_marcstate());
893 for (i = 0; i < AO_NUM_CC115L_REG; i++)
894 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name);
898 static void ao_radio_beep(void) {
902 static void ao_radio_packet(void) {
903 static const uint8_t packet[] = {
905 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
906 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
907 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
908 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
914 ao_radio_send(packet, sizeof (packet));
925 ao_packet_slave_stop();
930 #endif /* CC115L_DEBUG */
932 static const struct ao_cmds ao_radio_cmds[] = {
933 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
936 { ao_radio_aprs, "G\0Send APRS packet" },
938 { ao_radio_show, "R\0Show CC115L status" },
939 { ao_radio_beep, "b\0Emit an RDF beacon" },
940 { ao_radio_packet, "p\0Send a test packet" },
952 ao_radio_configured = 0;
953 ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN));
956 AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN));
957 for (i = 0; i < 10000; i++) {
958 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
961 AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN);
963 ao_panic(AO_PANIC_SELF_TEST_CC115L);
966 /* Enable the fifo threhold interrupt pin */
967 ao_enable_port(AO_CC115L_FIFO_INT_PORT);
968 ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN,
969 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
972 /* Enable the tx done interrupt pin */
973 ao_enable_port(AO_CC115L_DONE_INT_PORT);
974 ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN,
975 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
980 ao_cmd_register(&ao_radio_cmds[0]);