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 5b17494..58659af 100644 (file)
--- a/src/ao.h
+++ b/src/ao.h
@@ -391,14 +391,10 @@ ao_cmd_init(void);
  * 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);
 
@@ -838,6 +834,15 @@ struct ao_telemetry {
        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)
@@ -880,22 +885,16 @@ 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
-ao_radio_recv(__xdata struct ao_radio_recv *recv) __reentrant;
+ao_radio_recv(__xdata void *data, uint8_t size) __reentrant;
 
 void
-ao_radio_rdf(int ms);
+ao_radio_recv_abort(void);
 
 void
-ao_radio_abort(void);
+ao_radio_rdf(int ms);
 
 void
 ao_radio_rdf_abort(void);
index 88b52dc..fd33e2c 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_radio_abort();
+       ao_radio_recv_abort();
 }
 
 #if HAS_ADC
index 946666a..6052964 100644 (file)
@@ -107,8 +107,6 @@ ao_dma_abort(uint8_t id)
        uint8_t mask = (1 << id);
        DMAARM = 0x80 | mask;
        DMAIRQ &= ~mask;
-       *(ao_dma_done[id]) |= AO_DMA_ABORTED;
-       ao_wakeup(ao_dma_done[id]);
 }
 
 void
@@ -124,7 +122,7 @@ ao_dma_isr(void) __interrupt 8
                        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;
                }
index f019d3b..1e7f510 100644 (file)
@@ -23,7 +23,7 @@ __pdata uint8_t ao_monitor_led;
 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;
@@ -31,7 +31,7 @@ ao_monitor(void)
        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;
 
@@ -85,7 +85,7 @@ ao_set_monitor(uint8_t monitoring)
        ao_monitoring = monitoring;
        ao_wakeup(&ao_monitoring);
        if (!ao_monitoring)
-               ao_radio_abort();
+               ao_radio_recv_abort();
 }
 
 static void
index d52f2a6..9896149 100644 (file)
@@ -33,8 +33,6 @@ void
 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);
@@ -43,22 +41,7 @@ ao_packet_send(void)
                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);
 }
 
@@ -70,51 +53,56 @@ ao_packet_recv(void)
 #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
 
-       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;
-                       ao_tx_packet.seq = ao_rx_packet.packet.ack;
                        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
index 641b49f..3b23ad9 100644 (file)
@@ -77,8 +77,6 @@ ao_packet_master_check_busy(void)
 void
 ao_packet_master(void)
 {
-       uint8_t status;
-
        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);
-               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;
index 9b78767..3040d78 100644 (file)
 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) {
-               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();
                }
@@ -47,7 +44,7 @@ ao_packet_slave_stop(void)
 {
        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();
index cafa701..362b73a 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_abort;
 __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) {
-               ao_dma_abort(ao_radio_dma);
+               ao_radio_recv_abort();
                RFIF &= ~ RFIF_IM_TIMEOUT;
        } else if (RFIF & RFIF_IM_DONE) {
                ao_radio_done = 1;
@@ -338,14 +339,14 @@ ao_radio_get(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,
-                           telemetry,
+                           packet,
                            &RFDXADDR,
-                           sizeof (struct ao_telemetry),
+                           size,
                            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
-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,
-                           radio,
-                           sizeof (struct ao_radio_recv),
+                           packet,
+                           size,
                            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;
-       __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();
-       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
@@ -390,8 +411,9 @@ ao_radio_rdf(int ms)
        uint8_t i;
        uint8_t pkt_len;
 
+       ao_radio_abort = 0;
        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];
 
@@ -419,28 +441,22 @@ ao_radio_rdf(int ms)
                            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();
 }
 
-void
-ao_radio_abort(void)
-{
-       ao_dma_abort(ao_radio_dma);
-       ao_radio_idle();
-}
-
 void
 ao_radio_rdf_abort(void)
 {
-       if (ao_radio_rdf_running)
-               ao_radio_abort();
+       ao_radio_abort = 1;
+       ao_wakeup(&ao_radio_done);
 }
 
 
index 88ac142..277c3ce 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);
-               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)