TELE_COMMON_SRC = \
ao_gps_print.c \
ao_packet.c \
+ ao_packet_slave.c \
ao_state.c
#
#
TELE_RECEIVER_SRC =\
ao_monitor.c \
+ ao_packet_master.c \
ao_rssi.c
#
#define AO_PANIC_EE 4 /* Mis-using eeprom API */
#define AO_PANIC_LOG 5 /* Failing to read/write log data */
#define AO_PANIC_CMD 6 /* Too many command sets registered */
+#define AO_PANIC_STDIO 7 /* Too many stdio handlers registered */
/* Stop the operating system, beeping and blinking the reason */
void
* ao_stdio.c
*/
+#define AO_READ_AGAIN ((char) -1)
+
+struct ao_stdio {
+ char (*pollchar)(void);
+ void (*putchar)(char c) __reentrant;
+ void (*flush)(void);
+};
+
void
flush(void);
+extern __xdata uint8_t ao_stdin_ready;
+
+void
+ao_add_stdio(char (*pollchar)(void),
+ void (*putchar)(char) __reentrant,
+ void (*flush)(void));
+
/*
* ao_ignite.c
*/
uint8_t status;
};
+extern __xdata struct ao_packet_recv ao_rx_packet;
+extern __xdata struct ao_packet ao_tx_packet;
+extern __xdata struct ao_task ao_packet_task;
+extern __xdata uint8_t ao_packet_enable;
+extern __xdata uint8_t ao_packet_master_sleeping;
+extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
+
+void
+ao_packet_send(void);
+
+uint8_t
+ao_packet_recv(void);
+
+void
+ao_packet_flush(void);
+
+void
+ao_packet_putchar(char c) __reentrant;
+
+char
+ao_packet_pollchar(void) __critical;
+
+/* ao_packet_master.c */
+
+void
+ao_packet_master_init(void);
+
+/* ao_packet_slave.c */
+
+void
+ao_packet_slave_start(void);
+
+void
+ao_packet_slave_stop(void);
+
void
-ao_packet_init(void);
+ao_packet_slave_init(void);
#endif /* _AO_H_ */
} else {
ao_flight_state = ao_flight_idle;
- /* Turn on the Green LED in idle mode
+ /* Turn on packet system in idle mode
*/
- ao_led_on(AO_LED_GREEN);
+ ao_packet_slave_start();
ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
}
/* signal successful initialization by turning off the LED */
#define ao_usb_disable()
#define ao_telemetry_set_interval(x)
#define ao_rdf_set(rdf)
+#define ao_packet_slave_start()
enum ao_igniter {
ao_igniter_drogue = 0,
#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 struct ao_task ao_packet_task;
-static __xdata uint8_t ao_packet_enable;
-static __xdata uint8_t ao_packet_master_sleeping;
+__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_led_on(AO_LED_RED);
ao_config_get();
ao_mutex_get(&ao_radio_mutex);
- if (tx_used && tx_packet.len == 0) {
- memcpy(&tx_packet.d, tx_data, tx_used);
- tx_packet.len = tx_used;
- tx_packet.seq++;
- tx_used = 0;
+ 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_idle();
ao_radio_done = 0;
RF_CHANNR = ao_config.radio_channel;
ao_dma_set_transfer(ao_radio_dma,
- &tx_packet,
+ &ao_tx_packet,
&RFDXADDR,
sizeof (struct ao_packet),
DMA_CFG0_WORDSIZE_8 |
RF_CHANNR = ao_config.radio_channel;
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_led_off(AO_LED_GREEN);
if (dma_done & AO_DMA_DONE) {
- if (!(rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
+ if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
return AO_DMA_ABORTED;
- if (rx_packet.packet.len == AO_PACKET_SYN) {
- rx_seq = rx_packet.packet.seq;
- tx_packet.seq = rx_packet.packet.ack;
- tx_packet.ack = rx_seq;
- } else if (rx_packet.packet.len) {
- if (rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && rx_used == rx_len) {
-#if 0
- printf ("rx len %3d seq %3d ack %3d\n",
- rx_packet.packet.len,
- rx_packet.packet.seq,
- rx_packet.packet.ack);
- flush();
-#endif
- 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.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)
-{
- ao_radio_set_packet();
- tx_packet.addr = ao_serial_number;
- tx_packet.len = AO_PACKET_SYN;
- while (ao_packet_enable) {
- ao_packet_recv();
- ao_packet_send();
- }
- ao_exit();
-}
-
-/* Thread for the master side of the packet link */
-
-void
-ao_packet_master(void)
-{
- uint8_t status;
-
- ao_radio_set_packet();
- tx_packet.addr = ao_serial_number;
- tx_packet.len = AO_PACKET_SYN;
- while (ao_packet_enable) {
- ao_packet_send();
- ao_alarm(AO_MS_TO_TICKS(100));
- status = ao_packet_recv();
- if (status & AO_DMA_DONE) {
- /* if we can transmit data, do so */
- if (tx_used && tx_packet.len == 0)
- continue;
- ao_packet_master_sleeping = 1;
- ao_delay(AO_MS_TO_TICKS(1000));
- ao_packet_master_sleeping = 0;
- }
- }
- ao_exit();
-}
-
void
ao_packet_flush(void)
{
/* If there is data to send, and this is the master,
* then poke the master to send all queued data
*/
- if (tx_used && ao_packet_master_sleeping)
+ if (ao_packet_tx_used && ao_packet_master_sleeping)
ao_wake_task(&ao_packet_task);
}
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) {
ao_packet_flush();
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) {
- /* poke the master to get more data */
- if (ao_packet_master_sleeping)
- ao_wake_task(&ao_packet_task);
- ao_sleep(&rx_data);
- }
-
if (!ao_packet_enable)
- return 0;
+ return AO_READ_AGAIN;
- return rx_data[rx_used++];
-}
-
-static void
-ao_packet_echo(void) __reentrant
-{
- uint8_t c;
- while (ao_packet_enable) {
- c = ao_packet_getchar();
- if (ao_packet_enable) {
- putchar(c);
- if (c == (uint8_t) '\n' || c == (uint8_t) '\r')
- flush();
- }
- }
- 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();
-
- if (ao_cmd_lex_c == 'm')
- 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);
- 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);
- }
-}
-
-__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 },
-};
+ if (ao_packet_rx_used == ao_packet_rx_len)
+ return AO_READ_AGAIN;
-void
-ao_packet_init(void)
-{
- ao_cmd_register(&ao_packet_cmds[0]);
+ return rx_data[ao_packet_rx_used++];
}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+static char
+ao_packet_getchar(void)
+{
+ char c;
+ while ((c = ao_packet_pollchar()) == AO_READ_AGAIN)
+ {
+ if (!ao_packet_enable)
+ break;
+ if (ao_packet_master_sleeping)
+ ao_wake_task(&ao_packet_task);
+ ao_sleep(&ao_stdin_ready);
+ }
+ return c;
+}
+
+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 __xdata uint16_t ao_packet_master_delay;
+static __xdata uint16_t ao_packet_master_time;
+
+#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100)
+#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000)
+#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000)
+
+static void
+ao_packet_master_busy(void)
+{
+ ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
+ ao_packet_master_time = ao_time();
+}
+
+static void
+ao_packet_master_check_busy(void)
+{
+ int16_t idle;
+ if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT)
+ return;
+ idle = (int16_t) (ao_time() - ao_packet_master_time);
+
+ if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT)
+ ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG;
+}
+
+void
+ao_packet_master(void)
+{
+ uint8_t status;
+
+ ao_radio_set_packet();
+ ao_tx_packet.addr = ao_serial_number;
+ ao_tx_packet.len = AO_PACKET_SYN;
+ ao_packet_master_time = ao_time();
+ ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
+ while (ao_packet_enable) {
+ ao_packet_send();
+ if (ao_tx_packet.len)
+ 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 we can transmit data, do so */
+ if (ao_packet_tx_used && ao_tx_packet.len == 0)
+ continue;
+ if (ao_rx_packet.packet.len)
+ ao_packet_master_busy();
+ else
+ flush();
+ ao_packet_master_sleeping = 1;
+ ao_delay(ao_packet_master_delay);
+ ao_packet_master_sleeping = 0;
+ }
+ }
+ ao_exit();
+}
+
+static void
+ao_packet_forward(void) __reentrant
+{
+ char c;
+ ao_packet_enable = 1;
+ ao_cmd_white();
+
+ flush();
+ ao_set_monitor(0);
+ ao_add_task(&ao_packet_task, ao_packet_master, "master");
+ ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo");
+ while ((c = getchar()) != '~') {
+ if (c == '\r') c = '\n';
+ ao_packet_putchar(c);
+ }
+ 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);
+ ao_yield();
+ }
+}
+
+
+
+__code struct ao_cmds ao_packet_master_cmds[] = {
+ { 'p', ao_packet_forward, "p Remote packet link." },
+ { 0, ao_packet_forward, NULL },
+};
+
+void
+ao_packet_master_init(void)
+{
+ ao_cmd_register(&ao_packet_master_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+void
+ao_packet_slave(void)
+{
+ ao_radio_set_packet();
+ ao_tx_packet.addr = ao_serial_number;
+ ao_tx_packet.len = AO_PACKET_SYN;
+ while (ao_packet_enable) {
+ ao_packet_recv();
+ ao_packet_send();
+ }
+ ao_exit();
+}
+
+void
+ao_packet_slave_start(void)
+{
+ ao_packet_enable = 1;
+ ao_add_task(&ao_packet_task, ao_packet_slave, "slave");
+}
+
+void
+ao_packet_slave_stop(void)
+{
+ ao_packet_enable = 0;
+ ao_radio_abort();
+ while (ao_packet_task.wchan) {
+ ao_wake_task(&ao_packet_task);
+ ao_yield();
+ }
+ ao_radio_set_telemetry();
+}
+
+void
+ao_packet_slave_init(void)
+{
+ ao_add_stdio(ao_packet_pollchar,
+ ao_packet_putchar,
+ ao_packet_flush);
+}
* Basic I/O functions to support SDCC stdio package
*/
+#define AO_NUM_STDIOS 2
+
+static __xdata struct ao_stdio stdios[AO_NUM_STDIOS];
+static __data int8_t ao_cur_stdio;
+static __data int8_t ao_num_stdios;
+
void
putchar(char c)
{
if (c == '\n')
- ao_usb_putchar('\r');
- ao_usb_putchar(c);
+ (*stdios[ao_cur_stdio].putchar)('\r');
+ (*stdios[ao_cur_stdio].putchar)(c);
}
void
flush(void)
{
- ao_usb_flush();
+ stdios[ao_cur_stdio].flush();
}
+__xdata uint8_t ao_stdin_ready;
+
char
-getchar(void)
+getchar(void) __reentrant
+{
+ char c;
+ int8_t stdio = ao_cur_stdio;
+
+ for (;;) {
+ c = stdios[stdio].pollchar();
+ if (c != AO_READ_AGAIN)
+ break;
+ if (++stdio == ao_num_stdios)
+ stdio = 0;
+ if (stdio == ao_cur_stdio)
+ ao_sleep(&ao_stdin_ready);
+ }
+ ao_cur_stdio = stdio;
+ return c;
+}
+
+void
+ao_add_stdio(char (*pollchar)(void),
+ void (*putchar)(char),
+ void (*flush)(void))
{
- return ao_usb_getchar();
+ if (ao_num_stdios == AO_NUM_STDIOS)
+ ao_panic(AO_PANIC_STDIO);
+ stdios[ao_num_stdios].pollchar = pollchar;
+ stdios[ao_num_stdios].putchar = putchar;
+ stdios[ao_num_stdios].flush = flush;
+ ao_num_stdios++;
}
ao_monitor_init(AO_LED_GREEN, TRUE);
ao_rssi_init(AO_LED_RED);
ao_radio_init();
- ao_packet_init();
+ ao_packet_slave_init();
+ ao_packet_master_init();
ao_config_init();
ao_start_scheduler();
}
ao_gps_report_init();
ao_telemetry_init();
ao_radio_init();
- ao_packet_init();
+ ao_packet_slave_init();
ao_igniter_init();
ao_config_init();
ao_start_scheduler();
ao_wakeup(&ao_usb_in_bytes);
if (USBOIF & (1 << AO_USB_OUT_EP))
- ao_wakeup(&ao_usb_out_bytes);
+ ao_wakeup(&ao_stdin_ready);
if (USBCIF & USBCIF_RSTIF)
ao_usb_set_interrupts();
}
void
-ao_usb_putchar(char c) __critical
+ao_usb_putchar(char c) __critical __reentrant
{
if (!ao_usb_running)
return;
}
char
-ao_usb_getchar(void) __critical
+ao_usb_pollchar(void) __critical
{
- __xdata char c;
+ char c;
while (ao_usb_out_bytes == 0) {
- for (;;) {
- USBINDEX = AO_USB_OUT_EP;
- if ((USBCSOL & USBCSOL_OUTPKT_RDY) != 0)
- break;
- ao_sleep(&ao_usb_out_bytes);
- }
+ USBINDEX = AO_USB_OUT_EP;
+ if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0)
+ return AO_READ_AGAIN;
ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
}
--ao_usb_out_bytes;
return c;
}
+char
+ao_usb_getchar(void)
+{
+ char c;
+
+ while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)
+ ao_sleep(&ao_stdin_ready);
+ return c;
+}
+
void
ao_usb_enable(void)
{
ao_usb_enable();
ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
+ ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
}