* 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);
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)
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);
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
uint8_t mask = (1 << id);
DMAARM = 0x80 | mask;
DMAIRQ &= ~mask;
- *(ao_dma_done[id]) |= AO_DMA_ABORTED;
- ao_wakeup(ao_dma_done[id]);
}
void
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;
}
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;
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;
ao_monitoring = monitoring;
ao_wakeup(&ao_monitoring);
if (!ao_monitoring)
- ao_radio_abort();
+ ao_radio_recv_abort();
}
static 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);
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);
}
#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
void
ao_packet_master(void)
{
- uint8_t status;
-
ao_config_get();
ao_radio_set_packet();
ao_tx_packet.addr = ao_serial_number;
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;
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();
}
{
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();
__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
{
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;
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,
}
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,
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
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];
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);
}
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)