altos: Rework packet receive for cc1120
[fw/altos] / src / drivers / ao_cc1120.c
index 5d51fbcd518a51df934ae649849cdfe364eacb32..1b907940f6f1d5104c13fa43da120f9dfc1b882e 100644 (file)
@@ -41,8 +41,10 @@ extern const uint32_t        ao_radio_cal;
 
 #define FOSC   32000000
 
+#define ao_radio_try_select(task_id)   ao_spi_try_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz, task_id)
 #define ao_radio_select()      ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz)
 #define ao_radio_deselect()    ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
+#define ao_radio_spi_send_sync(d,l)    ao_spi_send_sync((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
@@ -107,7 +109,7 @@ ao_radio_reg_write(uint16_t addr, uint8_t value)
 }
 
 static void
-ao_radio_burst_read_start (uint16_t addr)
+_ao_radio_burst_read_start (uint16_t addr)
 {
        uint8_t data[2];
        uint8_t d;
@@ -124,8 +126,8 @@ ao_radio_burst_read_start (uint16_t addr)
                           addr);
                d = 1;
        }
-       ao_radio_select();
-       ao_radio_spi_send(data, d);
+
+       ao_radio_spi_send_sync(data, d);
 }
 
 static void
@@ -209,7 +211,7 @@ ao_radio_tx_fifo_space(void)
        return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
 }
 
-#if 0
+#if CC1120_DEBUG
 static uint8_t
 ao_radio_status(void)
 {
@@ -275,11 +277,13 @@ static void
 ao_radio_idle(void)
 {
        for (;;) {
-               uint8_t state = ao_radio_strobe(CC1120_SIDLE);
-               if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
+               uint8_t state = (ao_radio_strobe(CC1120_SIDLE) >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK;
+               if (state == CC1120_STATUS_STATE_IDLE)
                        break;
-               if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_TX_FIFO_ERROR)
+               if (state == CC1120_STATUS_STATE_TX_FIFO_ERROR)
                        ao_radio_strobe(CC1120_SFTX);
+               if (state == CC1120_STATUS_STATE_RX_FIFO_ERROR)
+                       ao_radio_strobe(CC1120_SFRX);
        }
        /* Flush any pending TX bytes */
        ao_radio_strobe(CC1120_SFTX);
@@ -948,6 +952,11 @@ static uint16_t    rx_data_consumed;
 static uint16_t rx_data_cur;
 static uint8_t rx_ignore;
 static uint8_t rx_waiting;
+static uint8_t rx_starting;
+static uint8_t rx_task_id;
+static uint32_t        rx_fast_start;
+static uint32_t rx_slow_start;
+static uint32_t        rx_missed;
 
 #if AO_PROFILE
 static uint32_t        rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
@@ -962,13 +971,34 @@ ao_radio_rx_isr(void)
 {
        uint8_t d;
 
+       if (rx_task_id) {
+               if (ao_radio_try_select(rx_task_id)) {
+                       ++rx_fast_start;
+                       rx_task_id = 0;
+                       _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
+               } else {
+                       if (rx_ignore)
+                               --rx_ignore;
+                       else {
+                               ao_radio_abort = 1;
+                               rx_missed++;
+                       }
+                       return;
+               }
+       }
+       if (rx_starting) {
+               rx_starting = 0;
+               ao_wakeup(&ao_radio_wake);
+       }
        d = AO_CC1120_SPI.dr;
        AO_CC1120_SPI.dr = 0;
        if (rx_ignore == 0) {
-               if (rx_data_cur >= rx_data_count)
-                       ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
-               else
+               if (rx_data_cur < rx_data_count)
                        rx_data[rx_data_cur++] = d;
+               if (rx_data_cur >= rx_data_count) {
+                       ao_spi_clr_cs(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN));
+                       ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+               }
                if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
 #if AO_PROFILE
                        if (!rx_packet_tick)
@@ -987,24 +1017,20 @@ ao_radio_rx_isr(void)
 static uint16_t
 ao_radio_rx_wait(void)
 {
-       do {
-               if (ao_radio_mcu_wake)
-                       ao_radio_check_marc_status();
-               ao_alarm(AO_MS_TO_TICKS(100));
-               ao_arch_block_interrupts();
-               rx_waiting = 1;
-               while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
-                      !ao_radio_abort &&
-                      !ao_radio_mcu_wake)
-               {
-                       if (ao_sleep(&ao_radio_wake))
-                               ao_radio_abort = 1;
-               }
-               rx_waiting = 0;
-               ao_arch_release_interrupts();
-               ao_clear_alarm();
-       } while (ao_radio_mcu_wake);
-       if (ao_radio_abort)
+       ao_alarm(AO_MS_TO_TICKS(100));
+       ao_arch_block_interrupts();
+       rx_waiting = 1;
+       while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
+              !ao_radio_abort &&
+              !ao_radio_mcu_wake)
+       {
+               if (ao_sleep(&ao_radio_wake))
+                       ao_radio_abort = 1;
+       }
+       rx_waiting = 0;
+       ao_arch_release_interrupts();
+       ao_clear_alarm();
+       if (ao_radio_abort || ao_radio_mcu_wake)
                return 0;
        rx_data_consumed += AO_FEC_DECODE_BLOCK;
 #if AO_PROFILE
@@ -1044,48 +1070,67 @@ ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
         */
        ao_radio_abort = 0;
 
-       /* configure interrupt pin */
        ao_radio_get(len);
-       ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
 
        ao_radio_wake = 0;
        ao_radio_mcu_wake = 0;
 
-       AO_CC1120_SPI.cr2 = 0;
-
-       /* clear any RXNE */
-       (void) AO_CC1120_SPI.dr;
+       ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
 
-       /* Have the radio signal when the preamble quality goes high */
-       ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_PQT_REACHED);
+       /* configure interrupt pin */
+       ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
        ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
-                        AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH);
-       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
+                        AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
+
+       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
        ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
-       ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
+
+       rx_starting = 1;
+       rx_task_id = ao_cur_task->task_id;
 
        ao_radio_strobe(CC1120_SRX);
 
-       /* Wait for the preamble to appear */
-       ao_radio_wait_isr(timeout);
+       if (timeout)
+               ao_alarm(timeout);
+       ao_arch_block_interrupts();
+       while (rx_starting && !ao_radio_abort) {
+               if (ao_sleep(&ao_radio_wake))
+                       ao_radio_abort = 1;
+       }
+       uint8_t rx_task_id_save = rx_task_id;
+       rx_task_id = 0;
+       rx_starting = 0;
+       ao_arch_release_interrupts();
+       if (timeout)
+               ao_clear_alarm();
+
        if (ao_radio_abort) {
                ret = 0;
+               rx_task_id = 0;
                goto abort;
        }
 
-       ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
-       ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
-                        AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
-
-       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
-       ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
-
-       ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
+       if (rx_task_id_save) {
+               ++rx_slow_start;
+               ao_radio_select();
+               _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
+               if (rx_ignore) {
+                       uint8_t ignore = AO_CC1120_SPI.dr;
+                       (void) ignore;
+                       AO_CC1120_SPI.dr = 0;
+                       --rx_ignore;
+               }
+       }
 
        ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
 
        ao_radio_burst_read_stop();
 
+       if (ao_radio_mcu_wake)
+               ao_radio_check_marc_status();
+       if (ao_radio_abort)
+               ret = 0;
+
 abort:
        /* Convert from 'real' rssi to cc1111-style values */
 
@@ -1100,7 +1145,7 @@ abort:
                radio_rssi = AO_RADIO_FROM_RSSI (rssi);
        }
 
-       ao_radio_strobe(CC1120_SIDLE);
+       ao_radio_idle();
 
        ao_radio_put();
 
@@ -1139,7 +1184,7 @@ struct ao_cc1120_reg {
        char            *name;
 };
 
-const static struct ao_cc1120_reg ao_cc1120_reg[] = {
+static const struct ao_cc1120_reg ao_cc1120_reg[] = {
        { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
        { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
        { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
@@ -1320,7 +1365,7 @@ const static struct ao_cc1120_reg ao_cc1120_reg[] = {
 
 static void ao_radio_show(void) {
        uint8_t status = ao_radio_status();
-       int     i;
+       unsigned int    i;
 
        ao_radio_get(0xff);
        status = ao_radio_status();
@@ -1331,6 +1376,10 @@ static void ao_radio_show(void) {
 
        for (i = 0; i < AO_NUM_CC1120_REG; i++)
                printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
+
+       printf("RX fast start: %u\n", rx_fast_start);
+       printf("RX slow start: %u\n", rx_slow_start);
+       printf("RX missed:     %u\n", rx_missed);
        ao_radio_put();
 }
 
@@ -1354,12 +1403,12 @@ static void ao_radio_packet(void) {
 }
 
 void
-ao_radio_test_recv()
+ao_radio_test_recv(void)
 {
        uint8_t bytes[34];
        uint8_t b;
 
-       if (ao_radio_recv(bytes, 34)) {
+       if (ao_radio_recv(bytes, 34, 0)) {
                if (bytes[33] & 0x80)
                        printf ("CRC OK");
                else
@@ -1375,13 +1424,12 @@ ao_radio_test_recv()
 #include <ao_aprs.h>
 
 static void
-ao_radio_aprs()
+ao_radio_aprs(void)
 {
        ao_packet_slave_stop();
        ao_aprs_send();
 }
 #endif
-
 #endif
 
 static const struct ao_cmds ao_radio_cmds[] = {