altos: clean up radio abort paths. Share radio code.
authorKeith Packard <keithp@keithp.com>
Sat, 27 Nov 2010 00:14:15 +0000 (16:14 -0800)
committerKeith Packard <keithp@keithp.com>
Thu, 23 Dec 2010 04:39:40 +0000 (20:39 -0800)
Instead of aborting the DMA and radio operation and expecting that to
be handled reasonably by the radio receiving task, rewrite things so
that the abort function just wakes the receiving task while that
terminates the DMA and cleans up the radio.

This eliminates all kinds of nasty bugs dealing with radio abort
smashing the radio registers at the wrong time, or interrupting a
radio transmission.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/ao.h
src/ao_config.c
src/ao_dma.c
src/ao_monitor.c
src/ao_packet.c
src/ao_packet_master.c
src/ao_packet_slave.c
src/ao_radio.c
src/ao_telemetry.c

index 5b174947c57ba893a74ae56e43dacffbaf132f92..58659af578416754a95bc99872959405eb796352 100644 (file)
--- a/src/ao.h
+++ b/src/ao.h
@@ -391,14 +391,10 @@ ao_cmd_init(void);
  * ao_dma.c
  */
 
  * ao_dma.c
  */
 
-/* Allocate a DMA channel. the 'done' parameter will be set
- * when the dma is finished or aborted and will be used to
- * wakeup any waiters
+/* Allocate a DMA channel. the 'done' parameter will be set when the
+ * dma is finished and will be used to wakeup any waiters
  */
 
  */
 
-#define AO_DMA_DONE    1
-#define AO_DMA_ABORTED 2
-
 uint8_t
 ao_dma_alloc(__xdata uint8_t * done);
 
 uint8_t
 ao_dma_alloc(__xdata uint8_t * done);
 
@@ -838,6 +834,15 @@ struct ao_telemetry {
        struct ao_gps_tracking_data     gps_tracking;
 };
 
        struct ao_gps_tracking_data     gps_tracking;
 };
 
+/*
+ * ao_radio_recv tacks on rssi and status bytes
+ */
+struct ao_telemetry_recv {
+       struct ao_telemetry     telemetry;
+       int8_t                  rssi;
+       uint8_t                 status;
+};
+
 /* Set delay between telemetry reports (0 to disable) */
 
 #define AO_TELEMETRY_INTERVAL_PAD      AO_MS_TO_TICKS(1000)
 /* Set delay between telemetry reports (0 to disable) */
 
 #define AO_TELEMETRY_INTERVAL_PAD      AO_MS_TO_TICKS(1000)
@@ -880,22 +885,16 @@ void
 ao_radio_set_rdf(void);
 
 void
 ao_radio_set_rdf(void);
 
 void
-ao_radio_send(__xdata struct ao_telemetry *telemetry) __reentrant;
-
-struct ao_radio_recv {
-       struct ao_telemetry     telemetry;
-       int8_t                  rssi;
-       uint8_t                 status;
-};
+ao_radio_send(__xdata void *data, uint8_t size) __reentrant;
 
 uint8_t
 
 uint8_t
-ao_radio_recv(__xdata struct ao_radio_recv *recv) __reentrant;
+ao_radio_recv(__xdata void *data, uint8_t size) __reentrant;
 
 void
 
 void
-ao_radio_rdf(int ms);
+ao_radio_recv_abort(void);
 
 void
 
 void
-ao_radio_abort(void);
+ao_radio_rdf(int ms);
 
 void
 ao_radio_rdf_abort(void);
 
 void
 ao_radio_rdf_abort(void);
index 88b52dc05950ebfe37f950bdb7673551387b63b2..fd33e2cc2569b6229a4b81a8b01518102031512b 100644 (file)
@@ -141,7 +141,7 @@ ao_config_radio_channel_set(void) __reentrant
        ao_config_dirty = 1;
        ao_mutex_put(&ao_config_mutex);
        ao_config_radio_channel_show();
        ao_config_dirty = 1;
        ao_mutex_put(&ao_config_mutex);
        ao_config_radio_channel_show();
-       ao_radio_abort();
+       ao_radio_recv_abort();
 }
 
 #if HAS_ADC
 }
 
 #if HAS_ADC
index 946666abc6ff9993410fa7c155479c43c6a1e511..6052964a5fb7e323445195488033da1216bb4b7c 100644 (file)
@@ -107,8 +107,6 @@ ao_dma_abort(uint8_t id)
        uint8_t mask = (1 << id);
        DMAARM = 0x80 | mask;
        DMAIRQ &= ~mask;
        uint8_t mask = (1 << id);
        DMAARM = 0x80 | mask;
        DMAIRQ &= ~mask;
-       *(ao_dma_done[id]) |= AO_DMA_ABORTED;
-       ao_wakeup(ao_dma_done[id]);
 }
 
 void
 }
 
 void
@@ -124,7 +122,7 @@ ao_dma_isr(void) __interrupt 8
                        DMAIF = 0;
                        /* Clear the completed ID */
                        DMAIRQ = ~mask;
                        DMAIF = 0;
                        /* Clear the completed ID */
                        DMAIRQ = ~mask;
-                       *(ao_dma_done[id]) |= AO_DMA_DONE;
+                       *(ao_dma_done[id]) = 1;
                        ao_wakeup(ao_dma_done[id]);
                        break;
                }
                        ao_wakeup(ao_dma_done[id]);
                        break;
                }
index f019d3b431a0481af12620280e58b8e87f845624..1e7f5102f09676509e624d555bf9fe7eb54c9df0 100644 (file)
@@ -23,7 +23,7 @@ __pdata uint8_t ao_monitor_led;
 void
 ao_monitor(void)
 {
 void
 ao_monitor(void)
 {
-       __xdata struct ao_radio_recv recv;
+       __xdata struct ao_telemetry_recv recv;
        __xdata char callsign[AO_MAX_CALLSIGN+1];
        uint8_t state;
        int16_t rssi;
        __xdata char callsign[AO_MAX_CALLSIGN+1];
        uint8_t state;
        int16_t rssi;
@@ -31,7 +31,7 @@ ao_monitor(void)
        for (;;) {
                __critical while (!ao_monitoring)
                        ao_sleep(&ao_monitoring);
        for (;;) {
                __critical while (!ao_monitoring)
                        ao_sleep(&ao_monitoring);
-               if (!ao_radio_recv(&recv))
+               if (!ao_radio_recv(&recv, sizeof (recv)))
                        continue;
                state = recv.telemetry.flight_state;
 
                        continue;
                state = recv.telemetry.flight_state;
 
@@ -85,7 +85,7 @@ ao_set_monitor(uint8_t monitoring)
        ao_monitoring = monitoring;
        ao_wakeup(&ao_monitoring);
        if (!ao_monitoring)
        ao_monitoring = monitoring;
        ao_wakeup(&ao_monitoring);
        if (!ao_monitoring)
-               ao_radio_abort();
+               ao_radio_recv_abort();
 }
 
 static void
 }
 
 static void
index d52f2a68b89815ee9f89896dbc874e8eed966cc2..9896149cbff480efe10c67d5e3846c670554fe14 100644 (file)
@@ -33,8 +33,6 @@ void
 ao_packet_send(void)
 {
        ao_led_on(AO_LED_RED);
 ao_packet_send(void)
 {
        ao_led_on(AO_LED_RED);
-       ao_radio_get();
-
        /* If any tx data is pending then copy it into the tx packet */
        if (ao_packet_tx_used && ao_tx_packet.len == 0) {
                memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used);
        /* If any tx data is pending then copy it into the tx packet */
        if (ao_packet_tx_used && ao_tx_packet.len == 0) {
                memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used);
@@ -43,22 +41,7 @@ ao_packet_send(void)
                ao_packet_tx_used = 0;
                ao_wakeup(&tx_data);
        }
                ao_packet_tx_used = 0;
                ao_wakeup(&tx_data);
        }
-       ao_radio_done = 0;
-       ao_dma_set_transfer(ao_radio_dma,
-                           &ao_tx_packet,
-                           &RFDXADDR,
-                           sizeof (struct ao_packet),
-                           DMA_CFG0_WORDSIZE_8 |
-                           DMA_CFG0_TMODE_SINGLE |
-                           DMA_CFG0_TRIGGER_RADIO,
-                           DMA_CFG1_SRCINC_1 |
-                           DMA_CFG1_DESTINC_0 |
-                           DMA_CFG1_PRIORITY_HIGH);
-       ao_dma_start(ao_radio_dma);
-       RFST = RFST_STX;
-       __critical while (!ao_radio_done)
-               ao_sleep(&ao_radio_done);
-       ao_radio_put();
+       ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet));
        ao_led_off(AO_LED_RED);
 }
 
        ao_led_off(AO_LED_RED);
 }
 
@@ -70,51 +53,56 @@ ao_packet_recv(void)
 #ifdef AO_LED_GREEN
        ao_led_on(AO_LED_GREEN);
 #endif
 #ifdef AO_LED_GREEN
        ao_led_on(AO_LED_GREEN);
 #endif
-       ao_radio_get();
-       ao_dma_set_transfer(ao_radio_dma,
-                           &RFDXADDR,
-                           &ao_rx_packet,
-                           sizeof (struct ao_packet_recv),
-                           DMA_CFG0_WORDSIZE_8 |
-                           DMA_CFG0_TMODE_SINGLE |
-                           DMA_CFG0_TRIGGER_RADIO,
-                           DMA_CFG1_SRCINC_0 |
-                           DMA_CFG1_DESTINC_1 |
-                           DMA_CFG1_PRIORITY_HIGH);
-       ao_dma_start(ao_radio_dma);
-       RFST = RFST_SRX;
-       __critical while (!ao_radio_dma_done)
-                          if (ao_sleep(&ao_radio_dma_done) != 0)
-                                  ao_radio_abort();
-       dma_done = ao_radio_dma_done;
-       ao_radio_put();
+       dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv));
 #ifdef AO_LED_GREEN
        ao_led_off(AO_LED_GREEN);
 #endif
 
 #ifdef AO_LED_GREEN
        ao_led_off(AO_LED_GREEN);
 #endif
 
-       if (dma_done & AO_DMA_DONE) {
-               if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
-                       return AO_DMA_ABORTED;
-               if (ao_rx_packet.packet.len == AO_PACKET_SYN) {
+       /* Check to see if we got a valid packet */
+       if (!dma_done)
+               return 0;
+       if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
+               return 0;
+
+       /* SYN packets carry no data */
+       if (ao_rx_packet.packet.len == AO_PACKET_SYN) {
+               rx_seq = ao_rx_packet.packet.seq;
+               ao_tx_packet.seq = ao_rx_packet.packet.ack;
+               ao_tx_packet.ack = rx_seq;
+       } else if (ao_rx_packet.packet.len) {
+
+               /* Check for incoming data at the next sequence and
+                * for an empty data buffer
+                */
+               if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) &&
+                   ao_packet_rx_used == ao_packet_rx_len) {
+
+                       /* Copy data to the receive data buffer and set up the
+                        * offsets
+                        */
+                       memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len);
+                       ao_packet_rx_used = 0;
+                       ao_packet_rx_len = ao_rx_packet.packet.len;
+
+                       /* Mark the sequence that we've received to
+                        * let the sender know when we return a packet
+                        */
                        rx_seq = ao_rx_packet.packet.seq;
                        rx_seq = ao_rx_packet.packet.seq;
-                       ao_tx_packet.seq = ao_rx_packet.packet.ack;
                        ao_tx_packet.ack = rx_seq;
                        ao_tx_packet.ack = rx_seq;
-               } else if (ao_rx_packet.packet.len) {
-                       if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && ao_packet_rx_used == ao_packet_rx_len) {
-                               memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len);
-                               ao_packet_rx_used = 0;
-                               ao_packet_rx_len = ao_rx_packet.packet.len;
-                               rx_seq = ao_rx_packet.packet.seq;
-                               ao_tx_packet.ack = rx_seq;
-                               ao_wakeup(&ao_stdin_ready);
-                       }
-               }
-               if (ao_rx_packet.packet.ack == ao_tx_packet.seq) {
-                       ao_tx_packet.len = 0;
-                       ao_wakeup(&ao_tx_packet);
+
+                       /* Poke anyone looking for received data */
+                       ao_wakeup(&ao_stdin_ready);
                }
        }
                }
        }
-       return dma_done;
+
+       /* If the other side has seen the latest data we queued,
+        * wake up any task waiting to send data and let them go again
+        */
+       if (ao_rx_packet.packet.ack == ao_tx_packet.seq) {
+               ao_tx_packet.len = 0;
+               ao_wakeup(&ao_tx_packet);
+       }
+       return 1;
 }
 
 #ifndef PACKET_HAS_MASTER
 }
 
 #ifndef PACKET_HAS_MASTER
index 641b49f411a48a5c5821e376f055a9872d754363..3b23ad92c882396f543a169c02053dbe1b7afcd7 100644 (file)
@@ -77,8 +77,6 @@ ao_packet_master_check_busy(void)
 void
 ao_packet_master(void)
 {
 void
 ao_packet_master(void)
 {
-       uint8_t status;
-
        ao_config_get();
        ao_radio_set_packet();
        ao_tx_packet.addr = ao_serial_number;
        ao_config_get();
        ao_radio_set_packet();
        ao_tx_packet.addr = ao_serial_number;
@@ -92,8 +90,7 @@ ao_packet_master(void)
                        ao_packet_master_busy();
                ao_packet_master_check_busy();
                ao_alarm(ao_packet_master_delay);
                        ao_packet_master_busy();
                ao_packet_master_check_busy();
                ao_alarm(ao_packet_master_delay);
-               status = ao_packet_recv();
-               if (status & AO_DMA_DONE) {
+               if (ao_packet_recv()) {
                        /* if we can transmit data, do so */
                        if (ao_packet_tx_used && ao_tx_packet.len == 0)
                                continue;
                        /* if we can transmit data, do so */
                        if (ao_packet_tx_used && ao_tx_packet.len == 0)
                                continue;
index 9b78767f55282b4e77c0f28f806124728151fccc..3040d781091fd88c0956f6258879938ec3dcbb4b 100644 (file)
 void
 ao_packet_slave(void)
 {
 void
 ao_packet_slave(void)
 {
-       uint8_t status;
-
        ao_radio_set_packet();
        ao_tx_packet.addr = ao_serial_number;
        ao_tx_packet.len = AO_PACKET_SYN;
        while (ao_packet_enable) {
        ao_radio_set_packet();
        ao_tx_packet.addr = ao_serial_number;
        ao_tx_packet.len = AO_PACKET_SYN;
        while (ao_packet_enable) {
-               status = ao_packet_recv();
-               if (status & AO_DMA_DONE) {
+               if (ao_packet_recv()) {
                        memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN);
                        ao_packet_send();
                }
                        memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN);
                        ao_packet_send();
                }
@@ -47,7 +44,7 @@ ao_packet_slave_stop(void)
 {
        if (ao_packet_enable) {
                ao_packet_enable = 0;
 {
        if (ao_packet_enable) {
                ao_packet_enable = 0;
-               ao_radio_abort();
+               ao_radio_recv_abort();
                while (ao_packet_task.wchan) {
                        ao_wake_task(&ao_packet_task);
                        ao_yield();
                while (ao_packet_task.wchan) {
                        ao_wake_task(&ao_packet_task);
                        ao_yield();
index cafa7010b0ab29e802d3694dcb2de187e102faf6..362b73aa3053c67452ace38ce15fa879aed4d0bb 100644 (file)
@@ -272,6 +272,7 @@ static __code uint8_t packet_setup[] = {
 __xdata uint8_t        ao_radio_dma;
 __xdata uint8_t ao_radio_dma_done;
 __xdata uint8_t ao_radio_done;
 __xdata uint8_t        ao_radio_dma;
 __xdata uint8_t ao_radio_dma_done;
 __xdata uint8_t ao_radio_done;
+__xdata uint8_t ao_radio_abort;
 __xdata uint8_t ao_radio_mutex;
 
 void
 __xdata uint8_t ao_radio_mutex;
 
 void
@@ -279,7 +280,7 @@ ao_radio_general_isr(void) __interrupt 16
 {
        S1CON &= ~0x03;
        if (RFIF & RFIF_IM_TIMEOUT) {
 {
        S1CON &= ~0x03;
        if (RFIF & RFIF_IM_TIMEOUT) {
-               ao_dma_abort(ao_radio_dma);
+               ao_radio_recv_abort();
                RFIF &= ~ RFIF_IM_TIMEOUT;
        } else if (RFIF & RFIF_IM_DONE) {
                ao_radio_done = 1;
                RFIF &= ~ RFIF_IM_TIMEOUT;
        } else if (RFIF & RFIF_IM_DONE) {
                ao_radio_done = 1;
@@ -338,14 +339,14 @@ ao_radio_get(void)
 
 
 void
 
 
 void
-ao_radio_send(__xdata struct ao_telemetry *telemetry) __reentrant
+ao_radio_send(__xdata void *packet, uint8_t size) __reentrant
 {
        ao_radio_get();
        ao_radio_done = 0;
        ao_dma_set_transfer(ao_radio_dma,
 {
        ao_radio_get();
        ao_radio_done = 0;
        ao_dma_set_transfer(ao_radio_dma,
-                           telemetry,
+                           packet,
                            &RFDXADDR,
                            &RFDXADDR,
-                           sizeof (struct ao_telemetry),
+                           size,
                            DMA_CFG0_WORDSIZE_8 |
                            DMA_CFG0_TMODE_SINGLE |
                            DMA_CFG0_TRIGGER_RADIO,
                            DMA_CFG0_WORDSIZE_8 |
                            DMA_CFG0_TMODE_SINGLE |
                            DMA_CFG0_TRIGGER_RADIO,
@@ -360,13 +361,14 @@ ao_radio_send(__xdata struct ao_telemetry *telemetry) __reentrant
 }
 
 uint8_t
 }
 
 uint8_t
-ao_radio_recv(__xdata struct ao_radio_recv *radio) __reentrant
+ao_radio_recv(__xdata void *packet, uint8_t size) __reentrant
 {
 {
+       ao_radio_abort = 0;
        ao_radio_get();
        ao_dma_set_transfer(ao_radio_dma,
                            &RFDXADDR,
        ao_radio_get();
        ao_dma_set_transfer(ao_radio_dma,
                            &RFDXADDR,
-                           radio,
-                           sizeof (struct ao_radio_recv),
+                           packet,
+                           size,
                            DMA_CFG0_WORDSIZE_8 |
                            DMA_CFG0_TMODE_SINGLE |
                            DMA_CFG0_TRIGGER_RADIO,
                            DMA_CFG0_WORDSIZE_8 |
                            DMA_CFG0_TMODE_SINGLE |
                            DMA_CFG0_TRIGGER_RADIO,
@@ -375,13 +377,32 @@ ao_radio_recv(__xdata struct ao_radio_recv *radio) __reentrant
                            DMA_CFG1_PRIORITY_HIGH);
        ao_dma_start(ao_radio_dma);
        RFST = RFST_SRX;
                            DMA_CFG1_PRIORITY_HIGH);
        ao_dma_start(ao_radio_dma);
        RFST = RFST_SRX;
-       __critical while (!ao_radio_dma_done)
-               ao_sleep(&ao_radio_dma_done);
+       __critical while (!ao_radio_dma_done && !ao_radio_abort)
+                          ao_sleep(&ao_radio_dma_done);
+
+       /* If recv was aborted, clean up by stopping the DMA engine
+        * and idling the radio
+        */
+       if (!ao_radio_dma_done) {
+               ao_dma_abort(ao_radio_dma);
+               ao_radio_idle();
+       }
        ao_radio_put();
        ao_radio_put();
-       return (ao_radio_dma_done & AO_DMA_DONE);
+       return ao_radio_dma_done;
+}
+
+/*
+ * Wake up a task waiting to receive a radio packet
+ * and tell them to abort the transfer
+ */
+
+void
+ao_radio_recv_abort(void)
+{
+       ao_radio_abort = 1;
+       ao_wakeup(&ao_radio_dma_done);
 }
 
 }
 
-__xdata ao_radio_rdf_running;
 __xdata ao_radio_rdf_value = 0x55;
 
 void
 __xdata ao_radio_rdf_value = 0x55;
 
 void
@@ -390,8 +411,9 @@ ao_radio_rdf(int ms)
        uint8_t i;
        uint8_t pkt_len;
 
        uint8_t i;
        uint8_t pkt_len;
 
+       ao_radio_abort = 0;
        ao_radio_get();
        ao_radio_get();
-       ao_radio_rdf_running = 1;
+       ao_radio_done = 0;
        for (i = 0; i < sizeof (rdf_setup); i += 2)
                RF[rdf_setup[i]] = rdf_setup[i+1];
 
        for (i = 0; i < sizeof (rdf_setup); i += 2)
                RF[rdf_setup[i]] = rdf_setup[i+1];
 
@@ -419,28 +441,22 @@ ao_radio_rdf(int ms)
                            DMA_CFG1_PRIORITY_HIGH);
        ao_dma_start(ao_radio_dma);
        RFST = RFST_STX;
                            DMA_CFG1_PRIORITY_HIGH);
        ao_dma_start(ao_radio_dma);
        RFST = RFST_STX;
-
-       __critical while (!ao_radio_dma_done)
-               ao_sleep(&ao_radio_dma_done);
-       ao_radio_rdf_running = 0;
-       ao_radio_idle();
+       __critical while (!ao_radio_done && !ao_radio_abort)
+                          ao_sleep(&ao_radio_done);
+       if (!ao_radio_done) {
+               ao_dma_abort(ao_radio_dma);
+               ao_radio_idle();
+       }
        for (i = 0; i < sizeof (telemetry_setup); i += 2)
                RF[telemetry_setup[i]] = telemetry_setup[i+1];
        ao_radio_put();
 }
 
        for (i = 0; i < sizeof (telemetry_setup); i += 2)
                RF[telemetry_setup[i]] = telemetry_setup[i+1];
        ao_radio_put();
 }
 
-void
-ao_radio_abort(void)
-{
-       ao_dma_abort(ao_radio_dma);
-       ao_radio_idle();
-}
-
 void
 ao_radio_rdf_abort(void)
 {
 void
 ao_radio_rdf_abort(void)
 {
-       if (ao_radio_rdf_running)
-               ao_radio_abort();
+       ao_radio_abort = 1;
+       ao_wakeup(&ao_radio_done);
 }
 
 
 }
 
 
index 88ac142c99c3502bfc2b3b4bb742cd88cb17bb7e..277c3ce01e4a30c807279e551f6663d688ab51de 100644 (file)
@@ -52,7 +52,7 @@ ao_telemetry(void)
                memcpy(&telemetry.gps, &ao_gps_data, sizeof (struct ao_gps_data));
                memcpy(&telemetry.gps_tracking, &ao_gps_tracking_data, sizeof (struct ao_gps_tracking_data));
                ao_mutex_put(&ao_gps_mutex);
                memcpy(&telemetry.gps, &ao_gps_data, sizeof (struct ao_gps_data));
                memcpy(&telemetry.gps_tracking, &ao_gps_tracking_data, sizeof (struct ao_gps_tracking_data));
                ao_mutex_put(&ao_gps_mutex);
-               ao_radio_send(&telemetry);
+               ao_radio_send(&telemetry, sizeof (telemetry));
                ao_delay(ao_telemetry_interval);
                if (ao_rdf &&
                    (int16_t) (ao_time() - ao_rdf_time) >= 0)
                ao_delay(ao_telemetry_interval);
                if (ao_rdf &&
                    (int16_t) (ao_time() - ao_rdf_time) >= 0)