BTM_DRIVER_SRC = \
ao_btm.c
+#
+# Companion port driver source
+#
+COMPANION_SRC = \
+ ao_companion.c
+
#
# Tasks run on TeleMetrum
#
* 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;
/* 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;
};
/*
#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_ */
--- /dev/null
+/*
+ * 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");
+}
_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;
_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;
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
#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
#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;
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,
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.
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,
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);
}
/*
ao_igniter_init();
#if HAS_DBG
ao_dbg_init();
+#endif
+#if HAS_COMPANION
+ ao_companion_init();
#endif
ao_config_init();
ao_start_scheduler();
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;
}
#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)
{
ao_send_sensor();
+#if HAS_COMPANION
+ if (ao_companion_running)
+ ao_send_companion();
+#endif
ao_send_configuration();
#if HAS_GPS
ao_send_location();
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;
$(SPI_DRIVER_SRC) \
$(FLASH_DRIVER_SRC) \
$(SKY_DRIVER_SRC) \
+ $(COMPANION_SRC) \
$(DBG_SRC)
PRODUCT=TeleMetrum-v1.0
$(SPI_DRIVER_SRC) \
$(M25_DRIVER_SRC) \
$(SKY_DRIVER_SRC) \
+ $(COMPANION_SRC) \
$(DBG_SRC)
PRODUCT=TeleMetrum-v1.1