altos: Add SPI-based companion board support
authorKeith Packard <keithp@keithp.com>
Sat, 9 Jul 2011 23:59:16 +0000 (16:59 -0700)
committerKeith Packard <keithp@keithp.com>
Sun, 14 Aug 2011 01:46:12 +0000 (18:46 -0700)
This sends current flight state information and retrieves companion
data to include in telemetry.

Signed-off-by: Keith Packard <keithp@keithp.com>
12 files changed:
src/Makefile.proto
src/ao.h
src/ao_companion.c [new file with mode: 0644]
src/ao_ee.c
src/ao_flash.c
src/ao_m25.c
src/ao_pins.h
src/ao_spi.c
src/ao_telemetrum.c
src/ao_telemetry.c
src/telemetrum-v1.0/Makefile.defs
src/telemetrum-v1.1/Makefile.defs

index d4a8c4ea173a0681bd8c698091455e3c80b34c5e..8f98d3544101a15b058668f70dc2ae2d490f0e0d 100644 (file)
@@ -150,6 +150,12 @@ SKY_DRIVER_SRC = \
 BTM_DRIVER_SRC = \
        ao_btm.c
 
+#
+# Companion port driver source
+#
+COMPANION_SRC = \
+       ao_companion.c
+
 #
 # Tasks run on TeleMetrum
 #
index 1c8f5bbf0b8c88cf0e79f93d41ec29b649f5e3d1..de47f3df2f22242e344e6454101f01de5ff89790 100644 (file)
--- a/src/ao.h
+++ b/src/ao.h
@@ -965,6 +965,34 @@ ao_serial_init(void);
  * ao_spi.c
  */
 
+extern __xdata uint8_t ao_spi_mutex;
+
+#define ao_spi_get_mask(reg,mask) do {\
+       ao_mutex_get(&ao_spi_mutex); \
+       (reg) &= ~(mask); \
+       } while (0)
+
+#define ao_spi_put_mask(reg,mask) do { \
+       (reg) |= (mask); \
+       ao_mutex_put(&ao_spi_mutex); \
+       } while (0)
+
+#define ao_spi_get_bit(bit) do {\
+       ao_mutex_get(&ao_spi_mutex); \
+       (bit) = 0; \
+       } while (0)
+
+#define ao_spi_put_bit(bit) do { \
+       (bit) = 1; \
+       ao_mutex_put(&ao_spi_mutex); \
+       } while (0)
+
+/*
+ * The SPI mutex must be held to call either of these
+ * functions -- this mutex covers the entire SPI operation,
+ * from chip select low to chip select high
+ */
+
 void
 ao_spi_send(void __xdata *block, uint16_t len) __reentrant;
 
@@ -1089,12 +1117,29 @@ struct ao_telemetry_satellite {
        /* 32 */
 };
 
+#define AO_TELEMETRY_COMPANION         0x07
+
+#define AO_COMPANION_MAX_CHANNELS      12
+
+struct ao_telemetry_companion {
+       uint16_t                                serial;         /*  0 */
+       uint16_t                                tick;           /*  2 */
+       uint8_t                                 type;           /*  4 */
+       uint8_t                                 board_id;       /*  5 */
+
+       uint8_t                                 update_period;  /*  6 */
+       uint8_t                                 channels;       /*  7 */
+       uint16_t                                companion_data[AO_COMPANION_MAX_CHANNELS];      /*  8 */
+       /* 32 */
+};
+       
 union ao_telemetry_all {
        struct ao_telemetry_generic             generic;
        struct ao_telemetry_sensor              sensor;
        struct ao_telemetry_configuration       configuration;
        struct ao_telemetry_location            location;
        struct ao_telemetry_satellite           satellite;
+       struct ao_telemetry_companion           companion;
 };
 
 /*
@@ -1529,8 +1574,33 @@ ao_btm_isr(void)
 #endif
        ;
 
-
 void
 ao_btm_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;
+};
+
+extern __pdata uint8_t                         ao_companion_running;
+extern __xdata struct ao_companion_setup       ao_companion_setup;
+extern __xdata uint8_t                         ao_companion_mutex;
+extern __xdata uint16_t                                ao_companion_data[AO_COMPANION_MAX_CHANNELS];
+
+void
+ao_companion_init(void);
+
 #endif /* _AO_H_ */
diff --git a/src/ao_companion.c b/src/ao_companion.c
new file mode 100644 (file)
index 0000000..8db3273
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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"
+
+#define COMPANION_SELECT()     ao_spi_get_bit(COMPANION_CS)
+#define COMPANION_DESELECT()   ao_spi_put_bit(COMPANION_CS)
+
+static __xdata struct ao_companion_command     ao_companion_command;
+__xdata struct ao_companion_setup              ao_companion_setup;
+
+__xdata uint16_t       ao_companion_data[AO_COMPANION_MAX_CHANNELS];
+__pdata uint8_t                ao_companion_running;
+__xdata uint8_t                ao_companion_mutex;
+
+static void
+ao_companion_send_command(uint8_t command)
+{
+       ao_companion_command.command = command;
+       ao_companion_command.flight_state = ao_flight_state;
+       ao_companion_command.tick = ao_time();
+       ao_spi_send(&ao_companion_command, sizeof (ao_companion_command));
+}
+
+static uint8_t
+ao_companion_get_setup(void)
+{
+       COMPANION_SELECT();
+       ao_companion_send_command(AO_COMPANION_SETUP);
+       ao_spi_recv(&ao_companion_setup, sizeof (ao_companion_setup));
+       COMPANION_DESELECT();
+       if (ao_companion_setup.board_id != ~ao_companion_setup.board_id)
+               return 0;
+       return 1;
+}
+
+static void
+ao_companion_get_data(void)
+{
+       COMPANION_SELECT();
+       ao_companion_send_command(AO_COMPANION_FETCH);
+       ao_mutex_get(&ao_companion_mutex);
+       ao_spi_recv(&ao_companion_data, ao_companion_setup.channels * 2);
+       ao_mutex_put(&ao_companion_mutex);
+       COMPANION_DESELECT();
+}
+
+void
+ao_companion(void)
+{
+       if (!ao_companion_get_setup())
+               ao_exit();
+       ao_companion_running = 1;
+       for (;;) {
+               ao_delay(ao_companion_setup.update_period);
+               ao_companion_get_data();
+       }
+}
+
+void
+ao_companion_status(void) __reentrant
+{
+}
+
+__code struct ao_cmds ao_companion_cmds[] = {
+       { ao_companion_status,  "L\0Companion link status" },
+       { 0, NULL },
+};
+
+static __xdata struct ao_task ao_companion_task;
+
+void
+ao_companion_init(void)
+{
+       COMPANION_CS_PORT |= COMPANION_CS_MASK; /* raise all CS pins */
+       COMPANION_CS_DIR |= COMPANION_CS_MASK;  /* set CS pins as outputs */
+       COMPANION_CS_SEL &= ~COMPANION_CS_MASK; /* set CS pins as GPIO */
+
+       ao_cmd_register(&ao_companion_cmds[0]);
+
+       ao_add_task(&ao_companion_task, ao_companion, "companion");
+}
index 83863af562af58bb6f9ff337fda21af8aec0ff4c..a2fe8dc19a974384706b4cc5b0b7efcd1fdb90ed 100644 (file)
@@ -49,19 +49,9 @@ static __xdata uint8_t ao_ee_mutex;
        _asm nop _endasm; \
 } while(0)
 
-static void ao_ee_cs_low(void)
-{
-       ao_ee_delay();
-       EE_CS = 0;
-       ao_ee_delay();
-}
+#define ao_ee_cs_low() ao_spi_get_bit(EE_CS)
 
-static void ao_ee_cs_high(void)
-{
-       ao_ee_delay();
-       EE_CS = 1;
-       ao_ee_delay();
-}
+#define ao_ee_cs_high()        ao_spi_put_bit(EE_CS)
 
 struct ao_ee_instruction {
        uint8_t instruction;
index 00e9639869cdf0a0a5b1345cbb3da4c22213c1ff..bb40f6f708b95515d165da8e131031639474593b 100644 (file)
@@ -43,19 +43,9 @@ __xdata uint8_t ao_flash_mutex;
        _asm nop _endasm; \
 } while(0)
 
-void ao_flash_cs_low(void)
-{
-       ao_flash_delay();
-       FLASH_CS = 0;
-       ao_flash_delay();
-}
+#define ao_flash_cs_low()      ao_spi_get_bit(FLASH_CS)
 
-void ao_flash_cs_high(void)
-{
-       ao_flash_delay();
-       FLASH_CS = 1;
-       ao_flash_delay();
-}
+#define ao_flash_cs_high()     ao_spi_put_bit(FLASH_CS)
 
 struct ao_flash_instruction {
        uint8_t instruction;
index 208c69ba84677c9690b7f023487e92111b7aa530..d7208273ff49714353e4992e323d1adc89c63528 100644 (file)
@@ -99,8 +99,8 @@ static __xdata uint8_t ao_m25_mutex;
 
 static __xdata uint8_t ao_m25_instruction[4];
 
-#define M25_SELECT(cs)                 (SPI_CS_PORT &= ~(cs))
-#define M25_DESELECT(cs)               (SPI_CS_PORT |= (cs))
+#define M25_SELECT(cs)         ao_spi_get_mask(SPI_CS_PORT,cs)
+#define M25_DESELECT(cs)       ao_spi_put_mask(SPI_CS_PORT,cs)
 
 #define M25_BLOCK_SHIFT                        16
 #define M25_BLOCK                      65536L
index 89907b9c03c3b6090084839bb29980f41cea81bb..e1f5459f902e4f7446cf7e0076f673eaa9cbf386 100644 (file)
        #define PACKET_HAS_MASTER       0
        #define PACKET_HAS_SLAVE        1
 
+       #define HAS_COMPANION           1
+       #define COMPANION_CS_ON_P1      1
+       #define COMPANION_CS_MASK       0x4     /* CS1 is P1_2 */
+       #define COMPANION_CS            P1_2
+
        #define AO_LED_RED              1
        #define LEDS_AVAILABLE          (AO_LED_RED)
        #define HAS_EXTERNAL_TEMP       0
        #define PACKET_HAS_MASTER       0
        #define PACKET_HAS_SLAVE        1
 
+       #define HAS_COMPANION           1
+       #define COMPANION_CS_ON_P1      1
+       #define COMPANION_CS_MASK       0x4     /* CS1 is P1_2 */
+       #define COMPANION_CS            P1_2
+
        #define AO_LED_RED              1
        #define LEDS_AVAILABLE          (AO_LED_RED)
        #define HAS_EXTERNAL_TEMP       0
 
 #endif /* DBG_ON_P0 */
 
+#if COMPANION_CS_ON_P1
+       #define COMPANION_CS_PORT       P1
+       #define COMPANION_CS_SEL        P1SEL
+       #define COMPANION_CS_DIR        P1DIR
+#endif
+
 #if SPI_CS_ON_P1
        #define SPI_CS_PORT     P1
        #define SPI_CS_SEL      P1SEL
index bd52a0d45694516fa643a9d7c376ac8c68543192..fbe613c759762bc4766f8ab47e9c56362fcc2d88 100644 (file)
 
 #include "ao.h"
 
+/* Shared mutex to protect SPI bus, must cover the entire
+ * operation, from CS low to CS high. This means that any SPI
+ * user must protect the SPI bus with this mutex
+ */
 __xdata uint8_t        ao_spi_mutex;
 __xdata uint8_t ao_spi_dma_in_done;
 __xdata uint8_t ao_spi_dma_out_done;
@@ -36,7 +40,6 @@ static __xdata uint8_t ao_spi_const = 0xff;
 void
 ao_spi_send(void __xdata *block, uint16_t len) __reentrant
 {
-       ao_mutex_get(&ao_spi_mutex);
        ao_dma_set_transfer(ao_spi_dma_in_id,
                            &U0DBUFXADDR,
                            &ao_spi_const,
@@ -64,7 +67,6 @@ ao_spi_send(void __xdata *block, uint16_t len) __reentrant
        ao_dma_trigger(ao_spi_dma_out_id);
        __critical while (!ao_spi_dma_in_done)
                ao_sleep(&ao_spi_dma_in_done);
-       ao_mutex_put(&ao_spi_mutex);
 }
 
 /* Receive bytes over SPI.
@@ -76,7 +78,6 @@ ao_spi_send(void __xdata *block, uint16_t len) __reentrant
 void
 ao_spi_recv(void __xdata *block, uint16_t len) __reentrant
 {
-       ao_mutex_get(&ao_spi_mutex);
        ao_dma_set_transfer(ao_spi_dma_in_id,
                            &U0DBUFXADDR,
                            block,
@@ -104,7 +105,6 @@ ao_spi_recv(void __xdata *block, uint16_t len) __reentrant
        ao_dma_trigger(ao_spi_dma_out_id);
        __critical while (!ao_spi_dma_in_done)
                ao_sleep(&ao_spi_dma_in_done);
-       ao_mutex_put(&ao_spi_mutex);
 }
 
 /*
index 6fa70b3a45b46bc5d0225aa6028dab0d2c51f541..f560740a455eb26484234478246063389c172c39 100644 (file)
@@ -61,6 +61,9 @@ main(void)
        ao_igniter_init();
 #if HAS_DBG
        ao_dbg_init();
+#endif
+#if HAS_COMPANION
+       ao_companion_init();
 #endif
        ao_config_init();
        ao_start_scheduler();
index 52f818ed3c09628d3ffe5aa51c4567c95c93a16d..15ba4302b3fb28b1eb707c68b707d2ba5ba37758 100644 (file)
@@ -25,6 +25,10 @@ static __pdata int8_t ao_telemetry_config_cur;
 static __pdata int8_t ao_telemetry_loc_cur;
 static __pdata int8_t ao_telemetry_sat_cur;
 #endif
+#if HAS_COMPANION
+static __pdata int8_t ao_telemetry_companion_max;
+static __pdata int8_t ao_telemetry_companion_cur;
+#endif
 static __pdata uint8_t ao_rdf = 0;
 static __pdata uint16_t ao_rdf_time;
 
@@ -149,6 +153,26 @@ ao_send_satellite(void)
 }
 #endif
 
+#if HAS_COMPANION
+static void
+ao_send_companion(void)
+{
+       if (--ao_telemetry_companion_cur <= 0) {
+               telemetry.generic.type = AO_TELEMETRY_COMPANION;
+               telemetry.companion.board_id = ao_companion_setup.board_id;
+               telemetry.companion.update_period = ao_companion_setup.update_period;
+               telemetry.companion.channels = ao_companion_setup.channels;
+               ao_mutex_get(&ao_companion_mutex);
+               memcpy(&telemetry.companion.companion_data,
+                      ao_companion_data,
+                      ao_companion_setup.channels * 2);
+               ao_mutex_put(&ao_companion_mutex);
+               ao_radio_send(&telemetry, sizeof (telemetry));
+               ao_telemetry_companion_cur = ao_telemetry_companion_max;
+       }
+}
+#endif
+
 void
 ao_telemetry(void)
 {
@@ -168,6 +192,10 @@ ao_telemetry(void)
 
 
                        ao_send_sensor();
+#if HAS_COMPANION
+                       if (ao_companion_running)
+                               ao_send_companion();
+#endif
                        ao_send_configuration();
 #if HAS_GPS
                        ao_send_location();
@@ -193,10 +221,25 @@ void
 ao_telemetry_set_interval(uint16_t interval)
 {
        ao_telemetry_interval = interval;
+
+#if HAS_COMPANION
+       if (!ao_companion_setup.update_period)
+               ao_companion_setup.update_period = AO_SEC_TO_TICKS(1);
+       ao_telemetry_companion_max = ao_companion_setup.update_period / interval;
+       ao_telemetry_companion_cur = 1;
+#endif
+
        ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval;
+#if HAS_COMPANION
+       ao_telemetry_config_cur = ao_telemetry_companion_cur;
+       if (ao_telemetry_config_max > ao_telemetry_config_cur)
+               ao_telemetry_config_cur++;
+#else
        ao_telemetry_config_cur = 1;
+#endif
+
 #if HAS_GPS
-       ao_telemetry_loc_cur = 1;
+       ao_telemetry_loc_cur = ao_telemetry_config_cur;
        if (ao_telemetry_config_max > ao_telemetry_loc_cur)
                ao_telemetry_loc_cur++;
        ao_telemetry_sat_cur = ao_telemetry_loc_cur;
index a60a501aabb42532e2ef594db94cbf6480d43fee..5eefc3929222c1a36fea7a7691c77dee8c89bc2c 100644 (file)
@@ -5,6 +5,7 @@ SRC = \
        $(SPI_DRIVER_SRC) \
        $(FLASH_DRIVER_SRC) \
        $(SKY_DRIVER_SRC) \
+       $(COMPANION_SRC) \
        $(DBG_SRC)
 
 PRODUCT=TeleMetrum-v1.0
index f38226c66bd8dab47a840d068074a38ca205c163..3c8b8793af37a636f83b2283be1a27b80e1ef570 100644 (file)
@@ -5,6 +5,7 @@ SRC = \
        $(SPI_DRIVER_SRC) \
        $(M25_DRIVER_SRC) \
        $(SKY_DRIVER_SRC) \
+       $(COMPANION_SRC) \
        $(DBG_SRC)
 
 PRODUCT=TeleMetrum-v1.1