summaryrefslogtreecommitdiff
path: root/src/ao_radio.c
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2010-11-26 16:14:15 -0800
committerKeith Packard <keithp@keithp.com>2010-12-22 20:39:40 -0800
commit07213dc34fa20470a4b36a327a83d75b0f010ebb (patch)
treea85d444ab7d2ccf01153c15e6fb2adf8473b602f /src/ao_radio.c
parentb62580855c5144f5bc7e0172289bce08814d9472 (diff)
altos: clean up radio abort paths. Share radio code.
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>
Diffstat (limited to 'src/ao_radio.c')
-rw-r--r--src/ao_radio.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/src/ao_radio.c b/src/ao_radio.c
index cafa7010..362b73aa 100644
--- a/src/ao_radio.c
+++ b/src/ao_radio.c
@@ -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);
}