From: Keith Packard Date: Sat, 27 Nov 2010 00:14:15 +0000 (-0800) Subject: altos: clean up radio abort paths. Share radio code. X-Git-Tag: debian/0.8.1+18+g408a3e0~12 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=07213dc34fa20470a4b36a327a83d75b0f010ebb 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 --- diff --git a/src/ao.h b/src/ao.h index 5b174947..58659af5 100644 --- 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); diff --git a/src/ao_config.c b/src/ao_config.c index 88b52dc0..fd33e2cc 100644 --- a/src/ao_config.c +++ b/src/ao_config.c @@ -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 diff --git a/src/ao_dma.c b/src/ao_dma.c index 946666ab..6052964a 100644 --- a/src/ao_dma.c +++ b/src/ao_dma.c @@ -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; } diff --git a/src/ao_monitor.c b/src/ao_monitor.c index f019d3b4..1e7f5102 100644 --- a/src/ao_monitor.c +++ b/src/ao_monitor.c @@ -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 diff --git a/src/ao_packet.c b/src/ao_packet.c index d52f2a68..9896149c 100644 --- a/src/ao_packet.c +++ b/src/ao_packet.c @@ -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 diff --git a/src/ao_packet_master.c b/src/ao_packet_master.c index 641b49f4..3b23ad92 100644 --- a/src/ao_packet_master.c +++ b/src/ao_packet_master.c @@ -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; diff --git a/src/ao_packet_slave.c b/src/ao_packet_slave.c index 9b78767f..3040d781 100644 --- a/src/ao_packet_slave.c +++ b/src/ao_packet_slave.c @@ -20,14 +20,11 @@ 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(); 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); } diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c index 88ac142c..277c3ce0 100644 --- a/src/ao_telemetry.c +++ b/src/ao_telemetry.c @@ -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)