altos-avr: Add SPI-slave companion support
authorKeith Packard <keithp@keithp.com>
Thu, 14 Jul 2011 04:20:06 +0000 (21:20 -0700)
committerKeith Packard <keithp@keithp.com>
Thu, 14 Jul 2011 04:21:33 +0000 (21:21 -0700)
Listen on the SPI slave port for commands from TeleMetrum.
Run logging during flight, based on flight state.
Return recent data for telemetry.

Signed-off-by: Keith Packard <keithp@keithp.com>
src-avr/ao.h
src-avr/ao_log_telescience.c
src-avr/ao_spi_slave.c [new file with mode: 0644]
src-avr/telescience/Makefile

index ecb334641b777a0409d6924077ec0d1fb87d2374..c548c618f87edc6281cb65adc9298bdf442d7e0b 100644 (file)
@@ -1421,4 +1421,33 @@ ao_btm_init(void);
 void
 ao_debug_init(void);
 
+/* ao_spi_slave.c */
+
+void
+ao_spi_slave_read(uint8_t *data, int len);
+
+void
+ao_spi_slave_write(uint8_t *data, int len);
+
+void
+ao_spi_slave_init(void);
+
+/* ao_companion.c */
+
+#define AO_COMPANION_SETUP             1
+#define AO_COMPANION_FETCH             2
+
+struct ao_companion_command {
+       uint8_t         command;
+       uint8_t         flight_state;
+       uint16_t        tick;
+};
+
+struct ao_companion_setup {
+       uint16_t        board_id;
+       uint16_t        board_id_inverse;
+       uint8_t         update_period;
+       uint8_t         channels;
+};
+
 #endif /* _AO_H_ */
index ef5a1c97d3e03c386cea94968918e5f126c64028..6022ad21ab66077f453483885c746bb92c98b195 100644 (file)
  */
 
 #include "ao.h"
+#include "ao_product.h"
 
 static struct ao_task ao_log_task;
+static struct ao_task ao_spi_task;
 
 uint8_t        ao_log_running;
 uint8_t                ao_log_mutex;
@@ -231,6 +233,43 @@ ao_log_delete(void)
                printf ("Erased\n");
 }
 
+void
+ao_spi_telescience(void)
+{
+       static union {
+               struct ao_companion_command     command;
+               struct ao_companion_setup       setup;
+               struct ao_adc                   data;
+       } u;
+
+       for (;;) {
+               ao_spi_slave_read((uint8_t *) &u.command, sizeof (struct ao_companion_command));
+               switch (u.command.command) {
+               case AO_COMPANION_SETUP:
+                       u.setup.board_id = AO_idProduct_NUMBER;
+                       u.setup.board_id_inverse = ~AO_idProduct_NUMBER;
+                       u.setup.update_period = 10;
+                       u.setup.channels = NUM_ADC;
+                       ao_spi_slave_write((uint8_t *) &u.setup,
+                                          sizeof (struct ao_companion_setup));
+                       break;
+               case AO_COMPANION_FETCH:
+                       ao_adc_get(&u.data);
+                       ao_spi_slave_write((uint8_t *) &u.data.adc,
+                                          NUM_ADC * sizeof (uint16_t));
+                       if (u.command.flight_state >= ao_flight_boost &&
+                           u.command.flight_state < ao_flight_landed) {
+                               if (!ao_log_running)
+                                       ao_log_start();
+                       } else {
+                               if (ao_log_running)
+                                       ao_log_stop();
+                       }
+                       break;
+               }
+       }
+}
+
 const struct ao_cmds ao_log_cmds[] = {
        { ao_log_set,   "L <0 off, 1 on>\0Set logging mode" },
        { ao_log_list,  "l\0List stored flight logs" },
@@ -238,25 +277,13 @@ const struct ao_cmds ao_log_cmds[] = {
        { 0,    NULL },
 };
 
-ISR(PCINT0_vect)
-{
-       ao_log_check_pin();
-}
-
 void
 ao_log_init(void)
 {
        ao_log_running = 0;
 
-       DDRB &= ~(1 << DDB0);
-
-       PORTB |= (1 << PORTB0);         /* Pull input up; require input to log */
-
-       PCMSK0 |= (1 << PCINT0);        /* Enable PCINT0 pin change */
-
-       PCICR |= (1 << PCIE0);          /* Enable pin change interrupt */
-
        ao_cmd_register(&ao_log_cmds[0]);
 
        ao_add_task(&ao_log_task, ao_log_telescience, "log");
+       ao_add_task(&ao_spi_task, ao_spi_telescience, "spi");
 }
diff --git a/src-avr/ao_spi_slave.c b/src-avr/ao_spi_slave.c
new file mode 100644 (file)
index 0000000..5f1990d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2011 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"
+
+__xdata struct ao_fifo ao_spi_slave_rx_fifo;
+__xdata struct ao_fifo ao_spi_slave_tx_fifo;
+
+static volatile uint8_t        ao_spi_slave_tx_started;
+
+static void
+ao_spi_slave_tx_start(void)
+{
+       if (!ao_spi_slave_tx_started && !ao_fifo_empty(ao_spi_slave_tx_fifo)) {
+               ao_spi_slave_tx_started = 1;
+               ao_fifo_remove(ao_spi_slave_tx_fifo, SPDR);
+       }
+}
+
+ISR(SPI_STC_vect)
+{
+       uint8_t spsr;
+
+       spsr = SPSR;
+       if (SPIF & (1 << SPIF)) {
+               uint8_t byte = SPDR;
+               if (!ao_fifo_full(ao_spi_slave_rx_fifo))
+                       ao_fifo_insert(ao_spi_slave_rx_fifo, byte);
+               ao_spi_slave_tx_started = 0;
+               ao_spi_slave_tx_start();
+               ao_wakeup(&ao_spi_slave_rx_fifo);
+               ao_wakeup(&ao_spi_slave_tx_fifo);
+       }
+}
+
+static void
+ao_spi_slave_put(uint8_t b) __critical
+{
+       cli();
+       while (ao_fifo_full(ao_spi_slave_tx_fifo))
+               ao_sleep(&ao_spi_slave_tx_fifo);
+       ao_fifo_insert(ao_spi_slave_tx_fifo, b);
+       ao_spi_slave_tx_start();
+       sei();
+}
+
+static uint8_t
+ao_spi_slave_get(void) __critical
+{
+       uint8_t b;
+
+       cli();
+       while (ao_fifo_empty(ao_spi_slave_rx_fifo))
+               ao_sleep(&ao_spi_slave_rx_fifo);
+       ao_fifo_remove(ao_spi_slave_rx_fifo, b);
+       sei();
+       return b;
+}
+
+void
+ao_spi_slave_read(uint8_t *data, int len)
+{
+       while (len--) {
+               ao_spi_slave_put(0);
+               *data++ = ao_spi_slave_get();
+       }
+}
+
+void
+ao_spi_slave_write(uint8_t *data, int len)
+{
+       while (len--) {
+               ao_spi_slave_put(*data++);
+               (void) ao_spi_slave_get();
+       }
+}
+
+void
+ao_spi_slave_init(void)
+{
+       SPCR = (1 << SPIE) |            /* Enable SPI interrupts */
+               (1 << SPE) |            /* Enable SPI */
+               (0 << DORD) |           /* MSB first */
+               (0 << MSTR) |           /* Slave mode */
+               (0 << CPOL) |           /* Clock low when idle */
+               (0 << CPHA);            /* Sample at leading clock edge */
+}
index 41580d8d18294cc4266a822d493beac8d6b5ef76..b50559a91af8adce5272697cbd9b874748f34267 100644 (file)
@@ -51,6 +51,7 @@ ALTOS_SRC = \
        ao_led.c \
        ao_usb_avr.c \
        ao_adc_avr.c \
+       ao_spi_slave.c \
        ao_log_telescience.c \
        $(TELESCIENCE_STORAGE)