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 */
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 0
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)
248 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW)
249 ao_radio_strobe(CC115L_SFTX);
251 /* Flush any pending TX bytes */
252 ao_radio_strobe(CC115L_SFTX);
256 * Packet deviation is 20.5kHz
258 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
260 * 26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz
263 #define PACKET_DEV_E 3
264 #define PACKET_DEV_M 5
267 * For our packet data, set the symbol rate to 38400 Baud
269 * (256 + DATARATE_M) * 2 ** DATARATE_E
270 * Rdata = -------------------------------------- * fosc
273 * (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383
278 #define PACKET_DRATE_E 10
279 #define PACKET_DRATE_M 131
281 static const uint16_t packet_setup[] = {
282 CC115L_DEVIATN, ((PACKET_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
283 (PACKET_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
284 CC115L_MDMCFG4, ((0xf << 4) |
285 (PACKET_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
286 CC115L_MDMCFG3, (PACKET_DRATE_M),
287 CC115L_MDMCFG2, (0x00 |
288 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
289 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
290 (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),
295 * RDF deviation is 5kHz
297 * fdev = fosc >> 17 * (8 + dev_m) << dev_e
299 * 26e6 / (2 ** 17) * (8 + 4) * (2 ** 1) = 4761Hz
306 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
308 * (256 + DATARATE_M) * 2 ** DATARATE_E
309 * Rdata = -------------------------------------- * fosc
312 * (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
317 #define RDF_DRATE_E 6
318 #define RDF_DRATE_M 67
320 static const uint16_t rdf_setup[] = {
321 CC115L_DEVIATN, ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
322 (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
323 CC115L_MDMCFG4, ((0xf << 4) |
324 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
325 CC115L_MDMCFG3, (RDF_DRATE_M),
326 CC115L_MDMCFG2, (0x00 |
327 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
328 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
329 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
333 * APRS deviation is 3kHz
335 * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
342 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
344 * (256 + DATARATE_M) * 2 ** DATARATE_E
345 * Rdata = -------------------------------------- * fosc
348 * (256 + 131) * (2 ** 8) / (2**28) * 26e6 = 9596
354 #define APRS_DRATE_E 8
355 #define APRS_DRATE_M 131
357 static const uint16_t aprs_setup[] = {
358 CC115L_DEVIATN, ((APRS_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
359 (APRS_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
360 CC115L_MDMCFG4, ((0xf << 4) |
361 (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
362 CC115L_MDMCFG3, (APRS_DRATE_M),
363 CC115L_MDMCFG2, (0x00 |
364 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
365 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
366 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
369 #define AO_PKTCTRL0_INFINITE ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
370 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
371 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
372 #define AO_PKTCTRL0_FIXED ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
373 (0 << CC115L_PKTCTRL0_PKT_CRC_EN) | \
374 (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
376 static uint16_t ao_radio_mode;
380 * These set the data rate and modulation parameters
382 #define AO_RADIO_MODE_BITS_PACKET_TX 1
383 #define AO_RADIO_MODE_BITS_RDF 2
384 #define AO_RADIO_MODE_BITS_APRS 4
387 * Flips between infinite packet mode and fixed packet mode;
388 * we use infinite mode until the sender gives us the
391 #define AO_RADIO_MODE_BITS_INFINITE 40
392 #define AO_RADIO_MODE_BITS_FIXED 80
394 #define AO_RADIO_MODE_NONE 0
396 #define AO_RADIO_MODE_RDF AO_RADIO_MODE_BITS_RDF
397 #define AO_RADIO_MODE_PACKET_TX AO_RADIO_MODE_BITS_PACKET_TX
398 #define AO_RADIO_MODE_APRS AO_RADIO_MODE_BITS_APRS
401 ao_radio_set_mode(uint16_t new_mode)
406 if (new_mode == ao_radio_mode)
409 changes = new_mode & (~ao_radio_mode);
410 if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
411 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
412 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
414 if (changes & AO_RADIO_MODE_BITS_RDF)
415 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
416 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
418 if (changes & AO_RADIO_MODE_BITS_APRS)
419 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
420 ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
422 if (changes & AO_RADIO_MODE_BITS_INFINITE)
423 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_INFINITE);
425 if (changes & AO_RADIO_MODE_BITS_FIXED)
426 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_FIXED);
428 ao_radio_mode = new_mode;
431 /***************************************************************
432 * SmartRF Studio(tm) Export
434 * Radio register settings specifed with address, value
438 ***************************************************************/
440 static const uint16_t radio_setup[] = {
442 /* High when FIFO is above threshold, low when fifo is below threshold */
443 AO_CC115L_FIFO_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_TXFIFO_THR,
445 /* High when transmitter is running, low when off */
446 AO_CC115L_DONE_INT_GPIO_IOCFG, CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV),
448 CC115L_FIFOTHR, 0x47, /* TX FIFO Thresholds */
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_MCSM0, 0x38, /* Main Radio Control State Machine Configuration */
454 CC115L_RESERVED_0X20, 0xfb, /* Use setting from SmartRF Studio */
455 CC115L_FSCAL3, 0xe9, /* Frequency Synthesizer Calibration */
456 CC115L_FSCAL2, 0x2a, /* Frequency Synthesizer Calibration */
457 CC115L_FSCAL1, 0x00, /* Frequency Synthesizer Calibration */
458 CC115L_FSCAL0, 0x1f, /* Frequency Synthesizer Calibration */
459 CC115L_TEST2, 0x81, /* Various Test Settings */
460 CC115L_TEST1, 0x35, /* Various Test Settings */
461 CC115L_TEST0, 0x09, /* Various Test Settings */
464 static uint8_t ao_radio_configured = 0;
471 ao_radio_strobe(CC115L_SRES);
472 ao_delay(AO_MS_TO_TICKS(10));
474 for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
475 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
481 ao_radio_strobe(CC115L_SCAL);
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;
502 ao_mutex_get(&ao_radio_mutex);
503 if (!ao_radio_configured)
505 if (ao_config.radio_setting != last_radio_setting) {
506 ao_radio_reg_write(CC115L_FREQ2, ao_config.radio_setting >> 16);
507 ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);
508 ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
509 last_radio_setting = ao_config.radio_setting;
514 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
516 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
518 struct ao_radio_tone {
523 struct ao_radio_tone *ao_radio_tone;
524 uint8_t ao_radio_tone_count;
525 uint8_t ao_radio_tone_current;
526 uint8_t ao_radio_tone_offset;
529 ao_radio_tone_fill(uint8_t *buf, int16_t len)
535 struct ao_radio_tone *t;
537 /* Figure out how many to send of the current value */
538 t = &ao_radio_tone[ao_radio_tone_current];
539 this_time = t->len - ao_radio_tone_offset;
544 memset(buf, t->value, this_time);
548 ao_radio_tone_offset += this_time;
551 if (ao_radio_tone_offset >= t->len) {
552 ao_radio_tone_offset = 0;
553 ao_radio_tone_current++;
554 if (ao_radio_tone_current >= ao_radio_tone_count) {
555 trace_add(trace_line, __LINE__, ret, "done with tone");
560 trace_add(trace_line, __LINE__, ret, "got some tone");
565 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
568 ao_radio_tone = tones;
569 ao_radio_tone_current = 0;
570 ao_radio_tone_offset = 0;
571 _ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
578 struct ao_radio_tone tone;
580 tone.value = ao_radio_rdf_value;
581 tone.len = AO_RADIO_RDF_LEN;
582 ao_radio_tone_run(&tone, 1);
586 ao_radio_continuity(uint8_t c)
588 struct ao_radio_tone tones[7];
592 for (i = 0; i < 3; i++) {
593 tones[count].value = 0x00;
594 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
597 tones[count].value = ao_radio_rdf_value;
599 tones[count].value = 0x00;
600 tones[count].len = AO_RADIO_CONT_TONE_LEN;
603 tones[count].value = 0x00;
604 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
606 ao_radio_tone_run(tones, count);
610 ao_radio_rdf_abort(void)
613 ao_wakeup(&ao_radio_wake);
616 #define POWER_STEP 0x08
623 ao_radio_reg_write(CC115L_PA, 0);
624 ao_radio_strobe(CC115L_STX);
625 for (power = POWER_STEP; power < ao_config.radio_power; power += POWER_STEP)
626 ao_radio_reg_write(CC115L_PA, power);
627 ao_radio_reg_write(CC115L_PA, ao_config.radio_power);
631 ao_radio_test_cmd(void)
634 static uint8_t radio_on;
636 if (ao_cmd_lex_c != '\n') {
638 mode = (uint8_t) ao_cmd_lex_u32;
641 if ((mode & 2) && !radio_on) {
643 ao_monitor_disable();
646 ao_packet_slave_stop();
649 ao_radio_strobe(CC115L_SFTX);
650 ao_radio_set_len(0xff);
651 ao_radio_set_mode(AO_RADIO_MODE_RDF);
656 printf ("Hit a character to stop..."); flush();
660 if ((mode & 1) && radio_on) {
671 static inline int16_t
672 ao_radio_gpio_bits(void)
674 return AO_CC115L_DONE_INT_PORT->idr & ((1 << AO_CC115L_FIFO_INT_PIN) |
675 (1 << AO_CC115L_DONE_INT_PIN));
680 ao_radio_wait_fifo(void)
682 ao_arch_block_interrupts();
683 while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) {
684 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo");
685 ao_sleep(&ao_radio_wake);
687 ao_arch_release_interrupts();
688 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
689 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
690 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
691 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
695 ao_radio_wait_done(void)
697 ao_arch_block_interrupts();
698 while (!ao_radio_done && !ao_radio_abort) {
699 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done");
700 ao_sleep(&ao_radio_wake);
702 ao_arch_release_interrupts();
703 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
704 trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
705 trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
706 trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
709 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
711 static uint8_t *ao_radio_send_buf;
712 static int16_t ao_radio_send_len;
715 ao_radio_send_fill(uint8_t *buf, int16_t len)
719 this_time = ao_radio_send_len;
722 memcpy(buf, ao_radio_send_buf, this_time);
723 ao_radio_send_buf += this_time;
724 ao_radio_send_len -= this_time;
725 if (ao_radio_send_len == 0)
731 ao_radio_send(const void *d, uint8_t size)
736 ao_radio_send_len = ao_fec_encode(d, size, tx_data);
737 ao_radio_send_buf = tx_data;
738 _ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX);
742 #define AO_RADIO_LOTS 64
745 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
747 uint8_t buf[AO_RADIO_LOTS], *b;
754 fifo_space = CC115L_FIFO_SIZE;
757 ao_radio_strobe(CC115L_SFTX);
762 cnt = (*fill)(buf, sizeof(buf));
763 trace_add(trace_line, __LINE__, cnt, "send data count");
770 /* At the last buffer, set the total length */
772 ao_radio_set_len(total & 0xff);
773 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED);
775 ao_radio_set_len(0xff);
776 ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE);
781 uint8_t this_len = cnt;
783 /* Wait for some space in the fifo */
784 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
785 trace_add(trace_line, __LINE__, this_len, "wait for space");
786 ao_radio_wait_fifo();
788 if (ao_radio_abort || ao_radio_done)
790 trace_add(trace_line, __LINE__, fifo_space, "got space");
791 if (this_len > fifo_space)
792 this_len = fifo_space;
798 ao_radio_fifo_write(b, this_len);
801 ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
802 ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
809 if (ao_radio_abort || ao_radio_done)
814 ao_radio_wait_done();
819 ao_radio_send_aprs(ao_radio_fill_func fill)
822 _ao_radio_send_lots(fill, AO_RADIO_MODE_APRS);
827 const static char *cc115l_state_name[] = {
828 [CC115L_STATUS_STATE_IDLE] = "IDLE",
829 [CC115L_STATUS_STATE_TX] = "TX",
830 [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
831 [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE",
832 [CC115L_STATUS_STATE_SETTLING] = "SETTLING",
833 [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
836 const static struct ao_cc115l_reg ao_cc115l_reg[] = {
837 { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
838 { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
839 { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
840 { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" },
841 { .addr = CC115L_SYNC1, .name = "SYNC1" },
842 { .addr = CC115L_SYNC0, .name = "SYNC0" },
843 { .addr = CC115L_PKTLEN, .name = "PKTLEN" },
844 { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" },
845 { .addr = CC115L_CHANNR, .name = "CHANNR" },
846 { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" },
847 { .addr = CC115L_FREQ2, .name = "FREQ2" },
848 { .addr = CC115L_FREQ1, .name = "FREQ1" },
849 { .addr = CC115L_FREQ0, .name = "FREQ0" },
850 { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" },
851 { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" },
852 { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" },
853 { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" },
854 { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" },
855 { .addr = CC115L_DEVIATN, .name = "DEVIATN" },
856 { .addr = CC115L_MCSM1, .name = "MCSM1" },
857 { .addr = CC115L_MCSM0, .name = "MCSM0" },
858 { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" },
859 { .addr = CC115L_FREND0, .name = "FREND0" },
860 { .addr = CC115L_FSCAL3, .name = "FSCAL3" },
861 { .addr = CC115L_FSCAL2, .name = "FSCAL2" },
862 { .addr = CC115L_FSCAL1, .name = "FSCAL1" },
863 { .addr = CC115L_FSCAL0, .name = "FSCAL0" },
864 { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" },
865 { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" },
866 { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" },
867 { .addr = CC115L_TEST2, .name = "TEST2" },
868 { .addr = CC115L_TEST1, .name = "TEST1" },
869 { .addr = CC115L_TEST0, .name = "TEST0" },
870 { .addr = CC115L_PARTNUM, .name = "PARTNUM" },
871 { .addr = CC115L_VERSION, .name = "VERSION" },
872 { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" },
873 { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" },
874 { .addr = CC115L_TXBYTES, .name = "TXBYTES" },
875 { .addr = CC115L_PA, .name = "PA" },
878 #define AO_NUM_CC115L_REG (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0])
880 static void ao_radio_show(void) {
881 uint8_t status = ao_radio_status();
885 status = ao_radio_status();
886 printf ("Status: %02x\n", status);
887 printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1);
888 printf ("STATE: %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]);
889 printf ("MARC: %02x\n", ao_radio_get_marcstate());
891 for (i = 0; i < AO_NUM_CC115L_REG; i++)
892 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name);
896 static void ao_radio_beep(void) {
900 static void ao_radio_packet(void) {
901 static const uint8_t packet[] = {
903 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
904 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
905 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
906 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
912 ao_radio_send(packet, sizeof (packet));
915 #endif /* CC115L_DEBUG */
924 ao_packet_slave_stop();
930 static const struct ao_cmds ao_radio_cmds[] = {
931 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
934 { ao_radio_aprs, "G\0Send APRS packet" },
936 { ao_radio_show, "R\0Show CC115L status" },
937 { ao_radio_beep, "b\0Emit an RDF beacon" },
938 { ao_radio_packet, "p\0Send a test packet" },
948 ao_radio_configured = 0;
949 ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN));
952 AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN));
953 for (i = 0; i < 10000; i++) {
954 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
957 AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN);
959 ao_panic(AO_PANIC_SELF_TEST_CC115L);
962 /* Enable the fifo threhold interrupt pin */
963 ao_enable_port(AO_CC115L_FIFO_INT_PORT);
964 ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN,
965 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
968 /* Enable the tx done interrupt pin */
969 ao_enable_port(AO_CC115L_DONE_INT_PORT);
970 ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN,
971 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
976 ao_cmd_register(&ao_radio_cmds[0]);