#include "ao.h"
-static __xdata struct ao_packet_recv rx_packet;
-static __xdata struct ao_packet tx_packet;
+__xdata struct ao_packet_recv ao_rx_packet;
+__xdata struct ao_packet ao_tx_packet;
+__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
+
static __xdata char tx_data[AO_PACKET_MAX];
static __xdata char rx_data[AO_PACKET_MAX];
-static __pdata uint8_t rx_len, rx_used, tx_used;
static __pdata uint8_t rx_seq;
-static __xdata uint16_t ao_packet_timer_delay;
-static __xdata uint8_t ao_packet_timer_cancelled;
-
-static __xdata struct ao_task ao_packet_task;
-static __xdata struct ao_task ao_packet_timer_task;
-static __xdata uint8_t ao_packet_enable;
-static __xdata uint8_t ao_packet_master_sleeping;
-
-void
-ao_packet_timer(void) __reentrant
-{
- uint16_t delay;
-
- while (ao_packet_enable) {
-
- /* wait until the timer task is needed
- */
- while (!ao_packet_timer_delay && ao_packet_enable)
- ao_sleep(&ao_packet_timer_delay);
-
- delay = ao_packet_timer_delay;
- ao_packet_timer_delay = 0;
-
- /* pause waiting for either a timeout or
- * a timer cancel
- */
- ao_delay(delay);
-
- /* if not canceled, abort the receive
- */
- if (!ao_packet_timer_cancelled) {
- printf ("packet timeout\n"); flush();
- ao_radio_abort(AO_DMA_TIMEOUT);
- }
- }
- ao_exit();
-}
-
-void
-ao_packet_timer_set(uint16_t delay)
-{
- ao_packet_timer_delay = delay;
- ao_packet_timer_cancelled = 0;
- ao_wakeup(&ao_packet_timer_delay);
-}
-
-void
-ao_packet_timer_cancel(void)
-{
- ao_packet_timer_cancelled = 1;
- ao_packet_timer_delay = 0;
- ao_wake_task(&ao_packet_timer_task);
-}
+__xdata struct ao_task ao_packet_task;
+__xdata uint8_t ao_packet_enable;
+__xdata uint8_t ao_packet_master_sleeping;
void
ao_packet_send(void)
{
- ao_config_get();
- ao_mutex_get(&ao_radio_mutex);
- ao_radio_idle();
- RF_CHANNR = ao_config.radio_channel;
+ 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_tx_packet.len = ao_packet_tx_used;
+ ao_tx_packet.seq++;
+ ao_packet_tx_used = 0;
+ ao_wakeup(&tx_data);
+ }
+ ao_radio_done = 0;
ao_dma_set_transfer(ao_radio_dma,
- &tx_packet,
+ &ao_tx_packet,
&RFDXADDR,
sizeof (struct ao_packet),
DMA_CFG0_WORDSIZE_8 |
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_mutex_put(&ao_radio_mutex);
+ __critical while (!ao_radio_done)
+ ao_sleep(&ao_radio_done);
+ ao_radio_put();
+ ao_led_off(AO_LED_RED);
}
uint8_t
{
uint8_t dma_done;
- ao_config_get();
- ao_mutex_get(&ao_radio_mutex);
- ao_radio_idle();
- RF_CHANNR = ao_config.radio_channel;
+#ifdef AO_LED_GREEN
+ ao_led_on(AO_LED_GREEN);
+#endif
+ ao_radio_get();
ao_dma_set_transfer(ao_radio_dma,
&RFDXADDR,
- &rx_packet,
+ &ao_rx_packet,
sizeof (struct ao_packet_recv),
DMA_CFG0_WORDSIZE_8 |
DMA_CFG0_TMODE_SINGLE |
ao_dma_start(ao_radio_dma);
RFST = RFST_SRX;
__critical while (!ao_radio_dma_done)
- ao_sleep(&ao_radio_dma_done);
+ if (ao_sleep(&ao_radio_dma_done) != 0)
+ ao_radio_abort();
dma_done = ao_radio_dma_done;
- ao_mutex_put(&ao_radio_mutex);
+ ao_radio_put();
+#ifdef AO_LED_GREEN
+ ao_led_off(AO_LED_GREEN);
+#endif
if (dma_done & AO_DMA_DONE) {
- printf ("rssi %d status %x\n", rx_packet.rssi, rx_packet.status); flush();
- if (!(rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) {
- printf ("bad crc\n"); flush();
-// return AO_DMA_ABORTED;
- }
- if (rx_packet.packet.len) {
- if (rx_packet.packet.seq == rx_seq + 1 && rx_used == rx_len)
- {
- memcpy(rx_data, rx_packet.packet.d, rx_packet.packet.len);
- rx_used = 0;
- rx_len = rx_packet.packet.len;
- rx_seq = rx_packet.packet.seq;
- tx_packet.ack = rx_seq;
- ao_wakeup(&rx_data);
+ if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
+ return AO_DMA_ABORTED;
+ 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) {
+ 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 (rx_packet.packet.ack == tx_packet.seq) {
- tx_packet.len = 0;
- ao_wakeup(&tx_packet);
+ if (ao_rx_packet.packet.ack == ao_tx_packet.seq) {
+ ao_tx_packet.len = 0;
+ ao_wakeup(&ao_tx_packet);
}
}
return dma_done;
}
-void
-ao_packet_slave(void)
-{
- tx_packet.addr = ao_serial_number;
- ao_radio_set_packet();
- while (ao_packet_enable) {
- ao_packet_recv();
- ao_led_toggle(AO_LED_GREEN);
- ao_delay(AO_MS_TO_TICKS(100));
- ao_packet_send();
- ao_led_toggle(AO_LED_RED);
- }
- ao_exit();
-}
-
-/* Thread for the master side of the packet link */
-
-void
-ao_packet_master(void)
-{
- uint8_t status;
- tx_packet.addr = ao_serial_number;
- ao_radio_set_packet();
- while (ao_packet_enable) {
- ao_delay(AO_MS_TO_TICKS(100));
- ao_packet_send();
- ao_led_toggle(AO_LED_RED);
- ao_packet_timer_set(AO_MS_TO_TICKS(1000));
- status = ao_packet_recv();
- ao_packet_timer_cancel();
- if (status & AO_DMA_DONE) {
- ao_led_toggle(AO_LED_GREEN);
- ao_packet_master_sleeping = 1;
- ao_sleep(AO_MS_TO_TICKS(1000));
- ao_packet_master_sleeping = 0;
- }
- }
- ao_exit();
-}
+#ifndef PACKET_HAS_MASTER
+#define PACKET_HAS_MASTER 1
+#endif
+#if PACKET_HAS_MASTER
void
ao_packet_flush(void)
{
- if (!tx_used)
- return;
-
- /* Wait for previous packet to be received
+ /* If there is data to send, and this is the master,
+ * then poke the master to send all queued data
*/
- while (tx_packet.len)
- ao_sleep(&tx_packet);
-
- /* Prepare next packet
- */
- if (tx_used) {
- memcpy(&tx_packet.d, tx_data, tx_used);
- tx_packet.len = tx_used;
- tx_packet.seq++;
- tx_used = 0;
-
- if (ao_packet_master_sleeping)
- ao_wake_task(&ao_packet_task);
- }
+ if (ao_packet_tx_used && ao_packet_master_sleeping)
+ ao_wake_task(&ao_packet_task);
}
+#endif /* PACKET_HAS_MASTER */
void
-ao_packet_putchar(char c)
+ao_packet_putchar(char c) __reentrant
{
- while (tx_used == AO_PACKET_MAX && ao_packet_enable)
+ while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) {
+#if PACKET_HAS_MASTER
ao_packet_flush();
+#endif
+ ao_sleep(&tx_data);
+ }
if (ao_packet_enable)
- tx_data[tx_used++] = c;
+ tx_data[ao_packet_tx_used++] = c;
}
char
-ao_packet_getchar(void) __critical
+ao_packet_pollchar(void) __critical
{
- while (rx_used == rx_len && ao_packet_enable)
- ao_sleep(&rx_data);
-
if (!ao_packet_enable)
- return 0;
+ return AO_READ_AGAIN;
- return rx_data[rx_used++];
-}
+ if (ao_packet_rx_used == ao_packet_rx_len)
+ return AO_READ_AGAIN;
-static void
-ao_packet_echo(void) __reentrant
-{
- uint8_t c;
- while (ao_packet_enable) {
- c = ao_packet_getchar();
- if (ao_packet_enable)
- putchar(c);
- }
- ao_exit();
-}
-
-static __xdata struct ao_task ao_packet_echo_task;
-
-static void
-ao_packet_forward(void) __reentrant
-{
- char c;
- ao_packet_enable = 1;
- ao_cmd_white();
-
- ao_radio_set_packet();
- if (ao_cmd_lex_c == 'm') {
- while ((c = getchar()) != '~')
- ao_packet_send();
- } else {
- for (;;) {
- ao_packet_recv();
- ao_led_toggle(AO_LED_GREEN);
- if (rx_packet.packet.d[0] == (uint8_t) '@')
- break;
- }
- }
- ao_packet_enable = 0;
- return;
-#if 0
- if (ao_cmd_lex_c == 'm') {
- ao_add_task(&ao_packet_timer_task, ao_packet_timer, "timeout");
- ao_add_task(&ao_packet_task, ao_packet_master, "master");
- }
- else
- ao_add_task(&ao_packet_task, ao_packet_slave, "slave");
- ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo");
- while ((c = getchar()) != '~') {
- ao_packet_putchar(c);
- if (c == '\n')
- ao_packet_flush();
- }
- ao_packet_enable = 0;
- ao_radio_abort();
- while (ao_packet_echo_task.wchan || ao_packet_task.wchan) {
- ao_wake_task(&ao_packet_echo_task);
- ao_wake_task(&ao_packet_task);
- }
-#endif
-}
-
-__code struct ao_cmds ao_packet_cmds[] = {
- { 'p', ao_packet_forward, "p {m|s} Remote packet link. m=master, s=slave" },
- { 0, ao_packet_forward, NULL },
-};
-
-void
-ao_packet_init(void)
-{
- ao_cmd_register(&ao_packet_cmds[0]);
+ return rx_data[ao_packet_rx_used++];
}