X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fdrivers%2Fao_cc1200.c;h=105e0d50a80aa072a2147248d1cf57edd4a0e8e2;hp=8f31d2b429104daf2d966374c404e6669d28ccc5;hb=cdaa0d7b272505c49017f409b7c0b8e3240608f0;hpb=2f0ff9675017655846a8abc617b4dc9a3666d0b9 diff --git a/src/drivers/ao_cc1200.c b/src/drivers/ao_cc1200.c index 8f31d2b4..105e0d50 100644 --- a/src/drivers/ao_cc1200.c +++ b/src/drivers/ao_cc1200.c @@ -3,7 +3,8 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,6 +21,9 @@ #include #include #include +#if HAS_PAD +#include +#endif static uint8_t ao_radio_mutex; @@ -28,16 +32,30 @@ static uint8_t ao_radio_abort; /* radio operation should abort */ int8_t ao_radio_rssi; /* Last received RSSI value */ +#ifndef CC1200_DEBUG #define CC1200_DEBUG 0 +#endif + +#ifndef CC1200_LOW_LEVEL_DEBUG #define CC1200_LOW_LEVEL_DEBUG 0 +#endif + #define CC1200_TRACE 0 #define CC1200_APRS_TRACE 0 extern const uint32_t ao_radio_cal; +#ifdef AO_CC1200_FOSC +#define FOSC AO_CC1200_FOSC +#else #define FOSC 40000000 +#endif -#define ao_radio_select() ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_SPI_SPEED_FAST) +#ifndef AO_CC1200_SPI_SPEED +#error AO_CC1200_SPI_SPEED undefined +#endif + +#define ao_radio_select() ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_CC1200_SPI_SPEED) #define ao_radio_deselect() ao_spi_put_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS) #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1200_SPI_BUS) #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1200_SPI_BUS) @@ -172,9 +190,9 @@ ao_radio_fifo_write_fixed(uint8_t data, uint8_t len) } static uint8_t -ao_radio_tx_fifo_space(void) +ao_radio_int_pin(void) { - return CC1200_FIFO_SIZE - ao_radio_reg_read(CC1200_NUM_TXBYTES); + return ao_gpio_get(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN); } static uint8_t @@ -295,20 +313,28 @@ ao_radio_idle(void) * CHANBW = 5.0 (round to 9.5) */ +#if FOSC == 40000000 #define PACKET_SYMBOL_RATE_M 1013008 - #define PACKET_SYMBOL_RATE_E_384 8 +#define PACKET_SYMBOL_RATE_E_96 6 +#define PACKET_SYMBOL_RATE_E_24 4 +#endif + +#if FOSC == 32000000 +#define PACKET_SYMBOL_RATE_M 239914 +#define PACKET_SYMBOL_RATE_E_384 9 +#define PACKET_SYMBOL_RATE_E_96 7 +#define PACKET_SYMBOL_RATE_E_24 5 +#endif /* 200 / 2 = 100 */ #define PACKET_CHAN_BW_384 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_12 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \ (16 << CC1200_CHAN_BW_BB_CIC_DECFACT)) -#define PACKET_SYMBOL_RATE_E_96 6 /* 200 / 10 = 20 */ #define PACKET_CHAN_BW_96 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \ (16 << CC1200_CHAN_BW_BB_CIC_DECFACT)) -#define PACKET_SYMBOL_RATE_E_24 4 /* 200 / 25 = 8 */ #define PACKET_CHAN_BW_24 ((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \ (44 << CC1200_CHAN_BW_BB_CIC_DECFACT)) @@ -461,6 +487,7 @@ static const uint16_t rdf_setup[] = { */ #define APRS_SYMBOL_RATE_E 6 #define APRS_SYMBOL_RATE_M 1013008 +#define APRS_BUFFER_SIZE 64 static const uint16_t aprs_setup[] = { CC1200_DEVIATION_M, APRS_DEV_M, @@ -495,6 +522,9 @@ static const uint16_t aprs_setup[] = { (CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_0 << CC1200_MDMCFG2_SYMBOL_MAP_CFG) | (CC1200_MDMCFG2_UPSAMPLER_P_8 << CC1200_MDMCFG2_UPSAMPLER_P) | (0 << CC1200_MDMCFG2_CFM_DATA_EN)), + CC1200_FIFO_CFG, + ((0 << CC1200_FIFO_CFG_CRC_AUTOFLUSH) | + (APRS_BUFFER_SIZE << CC1200_FIFO_CFG_FIFO_THR)), }; /* @@ -593,14 +623,20 @@ ao_radio_set_mode(uint16_t new_mode) } } - if (changes & AO_RADIO_MODE_BITS_TX_BUF) + if (changes & AO_RADIO_MODE_BITS_TX_BUF) { ao_radio_reg_write(AO_CC1200_INT_GPIO_IOCFG, CC1200_IOCFG_GPIO_CFG_TXFIFO_THR); + ao_exti_set_mode(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH); + } - if (changes & AO_RADIO_MODE_BITS_TX_FINISH) + if (changes & AO_RADIO_MODE_BITS_TX_FINISH) { ao_radio_reg_write(AO_CC1200_INT_GPIO_IOCFG, CC1200_IOCFG_GPIO_CFG_PKT_SYNC_RXTX); + ao_exti_set_mode(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH); + } - if (changes & AO_RADIO_MODE_BITS_RX) - ao_radio_reg_write(AO_CC1200_INT_GPIO_IOCFG, CC1200_IOCFG_GPIO_CFG_PKT_SYNC_RXTX); + if (changes & AO_RADIO_MODE_BITS_RX) { + ao_radio_reg_write(AO_CC1200_INT_GPIO_IOCFG, CC1200_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP); + ao_exti_set_mode(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN, AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH); + } if (changes & AO_RADIO_MODE_BITS_RDF) ao_radio_set_regs(rdf_setup); @@ -703,30 +739,11 @@ ao_radio_show_state(char *where) static void ao_radio_wait_isr(uint16_t timeout) { - uint8_t state; - - state = ao_radio_state(); - switch (state) { - case CC1200_STATUS_STATE_IDLE: - case CC1200_STATUS_STATE_RX_FIFO_ERROR: - case CC1200_STATUS_STATE_TX_FIFO_ERROR: -#if CC1200_LOW_LEVEL_DEBUG - printf("before wait, state %d\n", state); flush(); -#endif - ao_radio_abort = 1; - return; - } - - if (timeout) - ao_alarm(timeout); - ao_arch_block_interrupts(); while (!ao_radio_wake && !ao_radio_abort) - if (ao_sleep(&ao_radio_wake)) + if (ao_sleep_for(&ao_radio_wake, timeout)) ao_radio_abort = 1; ao_arch_release_interrupts(); - if (timeout) - ao_clear_alarm(); } static void @@ -742,6 +759,8 @@ ao_rdf_start(uint8_t len) static void ao_radio_run(void) { + ao_radio_wake = 0; + ao_radio_abort = 0; ao_radio_start_tx(); ao_radio_wait_isr(0); if (!ao_radio_wake) @@ -788,23 +807,20 @@ ao_radio_rdf_abort(void) ao_wakeup(&ao_radio_wake); } -static void -ao_radio_test_cmd(void) +static uint8_t radio_on; + +void +ao_radio_test_on(void) { - uint8_t mode = 2; - static uint8_t radio_on; - ao_cmd_white(); - if (ao_cmd_lex_c != '\n') { - ao_cmd_decimal(); - mode = (uint8_t) ao_cmd_lex_u32; - } - mode++; - if ((mode & 2) && !radio_on) { + if (!radio_on) { #if HAS_MONITOR ao_monitor_disable(); #endif #if PACKET_HAS_SLAVE ao_packet_slave_stop(); +#endif +#if HAS_PAD + ao_pad_disable(); #endif ao_radio_get(0xff); ao_radio_set_mode(AO_RADIO_MODE_TEST); @@ -819,21 +835,43 @@ ao_radio_test_cmd(void) #endif radio_on = 1; } - if (mode == 3) { - printf ("Hit a character to stop..."); flush(); - getchar(); - putchar('\n'); - } - if ((mode & 1) && radio_on) { +} + +void +ao_radio_test_off(void) +{ + if (radio_on) { ao_radio_idle(); ao_radio_put(); radio_on = 0; #if HAS_MONITOR ao_monitor_enable(); +#endif +#if HAS_PAD + ao_pad_enable(); #endif } } +static void +ao_radio_test_cmd(void) +{ + uint8_t mode = 2; + ao_cmd_white(); + if (ao_cmd_lex_c != '\n') + mode = ao_cmd_decimal(); + mode++; + if ((mode & 2)) + ao_radio_test_on(); + if (mode == 3) { + printf ("Hit a character to stop..."); flush(); + getchar(); + putchar('\n'); + } + if ((mode & 1)) + ao_radio_test_off(); +} + void ao_radio_send(const void *d, uint8_t size) { @@ -845,104 +883,58 @@ ao_radio_send(const void *d, uint8_t size) ao_radio_run(); } - -#define AO_RADIO_LOTS 64 - void ao_radio_send_aprs(ao_radio_fill_func fill) { - uint8_t buf[AO_RADIO_LOTS], *b; + uint8_t buf[APRS_BUFFER_SIZE]; int cnt; int total = 0; uint8_t done = 0; uint8_t started = 0; - uint8_t fifo_space; + ao_radio_abort = 0; ao_radio_get(0xff); - fifo_space = CC1200_FIFO_SIZE; - while (!done) { + ao_radio_wake = 0; + while (!done && !ao_radio_abort) { cnt = (*fill)(buf, sizeof(buf)); if (cnt < 0) { done = 1; cnt = -cnt; } -#if CC1200_APRS_TRACE - printf("APRS fill %d bytes done %d\n", cnt, done); -#endif total += cnt; /* At the last buffer, set the total length */ if (done) ao_radio_set_len(total & 0xff); - b = buf; - while (cnt) { - uint8_t this_len = cnt; - - /* Wait for some space in the fifo */ - while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) { -#if CC1200_APRS_TRACE - printf("APRS space %d cnt %d\n", fifo_space, cnt); flush(); -#endif - ao_radio_wake = 0; - ao_radio_wait_isr(AO_MS_TO_TICKS(1000)); - } - if (ao_radio_abort) - break; - if (this_len > fifo_space) - this_len = fifo_space; - - cnt -= this_len; - - if (done) { - if (cnt) - ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF); - else - ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH); - } else - ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF); - + /* Wait for some space in the fifo */ + while (started && ao_radio_int_pin() != 0 && !ao_radio_abort) { + ao_radio_wake = 0; ao_exti_enable(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN); - - ao_radio_fifo_write(b, this_len); - b += this_len; -#if CC1200_APRS_TRACE - printf("APRS write fifo %d space now %d\n", this_len, ao_radio_tx_fifo_space()); -#endif - if (!started) { -#if CC1200_APRS_TRACE - printf("APRS start\n"); -#endif - ao_radio_strobe(CC1200_STX); -#if CC1200_APRS_TRACE - { int t; - for (t = 0; t < 20; t++) { - uint8_t status = ao_radio_status(); - uint8_t space = ao_radio_tx_fifo_space(); - printf ("status: %02x fifo %d\n", status, space); - if ((status >> 4) == 2) - break; - ao_delay(AO_MS_TO_TICKS(0)); - } - } -#endif - started = 1; - } + ao_radio_wait_isr(AO_MS_TO_TICKS(1000)); } - if (ao_radio_abort) { - ao_radio_idle(); + if (ao_radio_abort) break; + + if (done) + ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH); + else + ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF); + + ao_radio_fifo_write(buf, cnt); + if (!started) { + ao_radio_strobe(CC1200_STX); + started = 1; } } /* Wait for the transmitter to go idle */ - ao_radio_wake = 0; -#if CC1200_APRS_TRACE - printf("APRS wait idle\n"); flush(); -#endif - ao_radio_wait_isr(AO_MS_TO_TICKS(1000)); -#if CC1200_APRS_TRACE - printf("APRS abort %d\n", ao_radio_abort); -#endif + while (started && ao_radio_int_pin() != 0 && !ao_radio_abort) { + ao_radio_wake = 0; + ao_exti_enable(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN); + ao_radio_wait_isr(AO_MS_TO_TICKS(1000)); + } + if (ao_radio_abort) + ao_radio_idle(); ao_radio_put(); } @@ -994,16 +986,81 @@ ao_radio_dump_state(struct ao_radio_state *s) #endif uint8_t -ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout) +ao_radio_recv(void *d, uint8_t size, uint8_t timeout) { - ao_radio_abort = 0; + uint8_t success = 0; + ao_radio_abort = 0; ao_radio_get(size - 2); ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX); ao_radio_wake = 0; ao_radio_start_rx(); - ao_radio_wait_isr(timeout); - if (ao_radio_wake) { + + while (!ao_radio_abort) { + ao_radio_wait_isr(timeout); + if (ao_radio_wake) { + uint8_t marc_status1 = ao_radio_reg_read(CC1200_MARC_STATUS1); + + /* Check the receiver status to see what happened + */ + switch (marc_status1) { + case CC1200_MARC_STATUS1_RX_FINISHED: + case CC1200_MARC_STATUS1_ADDRESS: + case CC1200_MARC_STATUS1_CRC: + /* Normal return, go fetch the bytes from the FIFO + * and give them back to the caller + */ + success = 1; + break; + case CC1200_MARC_STATUS1_RX_TIMEOUT: + case CC1200_MARC_STATUS1_RX_TERMINATION: + case CC1200_MARC_STATUS1_EWOR_SYNC_LOST: + case CC1200_MARC_STATUS1_MAXIMUM_LENGTH: + case CC1200_MARC_STATUS1_RX_FIFO_OVERFLOW: + case CC1200_MARC_STATUS1_RX_FIFO_UNDERFLOW: + /* Something weird happened; reset the radio and + * return failure + */ + success = 0; + break; + default: + /* some other status; go wait for the radio to do something useful + */ + continue; + } + break; + } else { + uint8_t modem_status1 = ao_radio_reg_read(CC1200_MODEM_STATUS1); + + /* Check to see if the packet header has been seen, in which case we'll + * want to keep waiting for the rest of the packet to appear + */ + if (modem_status1 & (1 << CC1200_MODEM_STATUS1_SYNC_FOUND)) + { + ao_radio_abort = 0; + + /* Set a timeout based on the packet length so that we make sure to + * wait long enough to receive the whole thing. + * + * timeout = bits * FEC expansion / rate + */ + switch (ao_config.radio_rate) { + default: + case AO_RADIO_RATE_38400: + timeout = AO_MS_TO_TICKS(size * (8 * 2 * 10) / 384) + 1; + break; + case AO_RADIO_RATE_9600: + timeout = AO_MS_TO_TICKS(size * (8 * 2 * 10) / 96) + 1; + break; + case AO_RADIO_RATE_2400: + timeout = AO_MS_TO_TICKS(size * (8 * 2 * 10) / 24) + 1; + break; + } + } + } + } + + if (success) { int8_t rssi; uint8_t status; @@ -1024,7 +1081,7 @@ ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout) } ao_radio_put(); - return ao_radio_wake; + return success; } @@ -1268,7 +1325,7 @@ static void ao_radio_packet(void) { void ao_radio_test_recv(void) { - uint8_t bytes[34]; + static uint8_t bytes[34]; uint8_t b; if (ao_radio_recv(bytes, 34, 0)) { @@ -1303,14 +1360,15 @@ ao_radio_aprs(void) static void ao_radio_strobe_test(void) { + uint8_t addr; uint8_t r; - ao_cmd_hex(); + addr = ao_cmd_hex(); if (ao_cmd_status != ao_cmd_success) return; - r = ao_radio_strobe(ao_cmd_lex_i); + r = ao_radio_strobe(addr); printf ("Strobe %02x -> %02x (rdy %d state %d)\n", - ao_cmd_lex_i, + addr, r, r >> 7, (r >> 4) & 0x7); @@ -1322,14 +1380,12 @@ ao_radio_write_test(void) uint16_t addr; uint8_t data; - ao_cmd_hex(); + addr = ao_cmd_hex(); if (ao_cmd_status != ao_cmd_success) return; - addr = ao_cmd_lex_i; - ao_cmd_hex(); + data = ao_cmd_hex(); if (ao_cmd_status != ao_cmd_success) return; - data = ao_cmd_lex_i; printf ("Write %04x = %02x\n", addr, data); ao_radio_reg_write(addr, data); } @@ -1340,10 +1396,9 @@ ao_radio_read_test(void) uint16_t addr; uint8_t data; - ao_cmd_hex(); + addr = ao_cmd_hex(); if (ao_cmd_status != ao_cmd_success) return; - addr = ao_cmd_lex_i; data = ao_radio_reg_read(addr); printf ("Read %04x = %02x\n", addr, data); }