Add in existing flight pieces: flight/report/log
authorKeith Packard <keithp@keithp.com>
Wed, 15 Apr 2009 02:08:01 +0000 (19:08 -0700)
committerKeith Packard <keithp@keithp.com>
Wed, 15 Apr 2009 02:08:01 +0000 (19:08 -0700)
These pieces come from the old telemetrum firmware.

Signed-off-by: Keith Packard <keithp@keithp.com>
Makefile
ao.h
ao_adc.c
ao_cmd.c
ao_ee.c
ao_flight.c [new file with mode: 0644]
ao_log.c [new file with mode: 0644]
ao_report.c [new file with mode: 0644]
ao_timer.c

index 909bb462d9e34a32180adc2460a58c5c1648e662..f8c9c73a7b22aaba15e1619f69a388ff65a96f56 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -20,9 +20,12 @@ SRC = \
        ao_cmd.c \
        ao_dma.c \
        ao_ee.c \
+       ao_flight.c \
        ao_led.c \
+       ao_log.c \
        ao_mutex.c \
        ao_panic.c \
+       ao_report.c \
        ao_task.c \
        ao_timer.c \
        ao_usb.c \
diff --git a/ao.h b/ao.h
index 82678595d53e549da12f13adfb94041f8cbeece1..5574f30fe156fb7262c2e983b0e748496772eae8 100644 (file)
--- a/ao.h
+++ b/ao.h
@@ -29,7 +29,7 @@
 /* Stack runs from above the allocated __data space to 0xfe, which avoids
  * writing to 0xff as that triggers the stack overflow indicator
  */
-#define AO_STACK_START 0x75
+#define AO_STACK_START 0x7f
 #define AO_STACK_END   0xfe
 #define AO_STACK_SIZE  (AO_STACK_END - AO_STACK_START + 1)
 
@@ -78,6 +78,7 @@ ao_start_scheduler(void);
 #define AO_PANIC_DMA           2       /* Attempt to start DMA while active */
 #define AO_PANIC_MUTEX         3       /* Mis-using mutex API */
 #define AO_PANIC_EE            4       /* Mis-using eeprom API */
+#define AO_PANIC_LOG           5       /* Failing to read/write log data */
 
 /* Stop the operating system, beeping and blinking the reason */
 void
@@ -111,7 +112,7 @@ ao_timer_init(void);
  * ao_adc.c
  */
 
-#define ADC_RING       128
+#define AO_ADC_RING    128
 
 /*
  * One set of samples read from the A/D converter
@@ -130,7 +131,7 @@ struct ao_adc {
  * A/D data is stored in a ring, with the next sample to be written
  * at ao_adc_head
  */
-extern volatile __xdata struct ao_adc  ao_adc_ring[ADC_RING];
+extern volatile __xdata struct ao_adc  ao_adc_ring[AO_ADC_RING];
 extern volatile __data uint8_t         ao_adc_head;
 
 /* Trigger a conversion sequence (called from the timer interrupt) */
@@ -325,26 +326,174 @@ ao_mutex_put(__xdata uint8_t *ao_mutex);
 #define AO_EE_CONFIG_BLOCK     ((uint16_t) (AO_EE_DATA_SIZE / AO_EE_BLOCK_SIZE))
 
 void
-ao_ee_flush(void);
+ao_ee_flush(void) __reentrant;
 
 /* Write to the eeprom */
 uint8_t
-ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len);
+ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant;
 
 /* Read from the eeprom */
 uint8_t
-ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len);
+ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant;
 
 /* Write the config block (at the end of the eeprom) */
 uint8_t
-ao_ee_write_config(uint8_t *buf, uint16_t len);
+ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant;
 
 /* Read the config block (at the end of the eeprom) */
 uint8_t
-ao_ee_read_config(uint8_t *buf, uint16_t len);
+ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant;
 
 /* Initialize the EEPROM code */
 void
 ao_ee_init(void);
 
+/*
+ * ao_log.c
+ */
+
+/*
+ * The data log is recorded in the eeprom as a sequence
+ * of data packets.
+ *
+ * Each packet starts with a 4-byte header that has the
+ * packet type, the packet checksum and the tick count. Then
+ * they all contain 2 16 bit values which hold packet-specific
+ * data.
+ * 
+ * For each flight, the first packet
+ * is FLIGHT packet, indicating the serial number of the
+ * device and a unique number marking the number of flights
+ * recorded by this device.
+ *
+ * During flight, data from the accelerometer and barometer
+ * are recorded in SENSOR packets, using the raw 16-bit values
+ * read from the A/D converter.
+ *
+ * Also during flight, but at a lower rate, the deployment
+ * sensors are recorded in DEPLOY packets. The goal here is to
+ * detect failure in the deployment circuits.
+ *
+ * STATE packets hold state transitions as the flight computer
+ * transitions through different stages of the flight.
+ */
+#define AO_LOG_FLIGHT          'F'
+#define AO_LOG_SENSOR          'A'
+#define AO_LOG_TEMP_VOLT       'T'
+#define AO_LOG_DEPLOY          'D'
+#define AO_LOG_STATE           'S'
+
+#define AO_LOG_POS_NONE                (~0UL)
+
+struct ao_log_record {
+       uint8_t                 type;
+       uint8_t                 csum;
+       uint16_t                tick;
+       union {
+               struct {
+                       uint16_t        serial;
+                       uint16_t        flight;
+               } flight;
+               struct {
+                       int16_t         accel;
+                       int16_t         pres;
+               } sensor;
+               struct {
+                       int16_t         temp;
+                       int16_t         v_batt;
+               } temp_volt;
+               struct {
+                       int16_t         drogue;
+                       int16_t         main;
+               } deploy;
+               struct {
+                       uint16_t        state;
+                       uint16_t        reason;
+               } state;
+               struct {
+                       uint16_t        d0;
+                       uint16_t        d1;
+               } anon;
+       } u;
+};
+
+/* Write a record to the eeprom log */
+void
+ao_log_data(struct ao_log_record *log);
+
+/* Flush the log */
+void
+ao_log_flush(void);
+
+/* Log dumping API:
+ * ao_log_dump_first() - get first log record
+ * ao_log_dump_next()  - get next log record
+ */
+extern __xdata struct ao_log_record ao_log_dump;
+
+/* Retrieve first log record for the current flight */
+uint8_t
+ao_log_dump_first(void);
+
+/* return next log record for the current flight */
+uint8_t
+ao_log_dump_next(void);
+
+/* Logging thread main routine */
+void
+ao_log(void);
+
+/* Start logging to eeprom */
+void
+ao_log_start(void);
+
+/* Initialize the logging system */
+void
+ao_log_init(void);
+
+/*
+ * ao_flight.c
+ */
+
+enum ao_flight_state {
+       ao_flight_startup,
+       ao_flight_idle,
+       ao_flight_launchpad,
+       ao_flight_boost,
+       ao_flight_coast,
+       ao_flight_apogee,
+       ao_flight_drogue,
+       ao_flight_main,
+       ao_flight_landed,
+       ao_flight_invalid
+};
+
+extern __xdata struct ao_adc   ao_flight_data;
+extern __data enum flight_state        ao_flight_state;
+extern __data uint16_t                 ao_flight_state_tick;
+extern __data int16_t                  ao_flight_accel;
+extern __data int16_t                  ao_flight_pres;
+extern __data int16_t                  ao_ground_pres;
+extern __data int16_t                  ao_ground_accel;
+extern __data int16_t                  ao_min_pres;
+extern __data uint16_t                 ao_launch_time;
+
+/* Flight thread */
+void
+ao_flight(void);
+
+/* Initialize flight thread */
+void
+ao_flight_init(void);
+
+/*
+ * ao_report.c
+ */
+
+void
+ao_report_notify(void);
+
+void
+ao_report_init(void);
+
 #endif /* _AO_H_ */
index 549cc9440847070868fa392d0423782e744da595..8834f26e10c2f52ef1b2cb8f1c06e29faed5d3a2 100644 (file)
--- a/ao_adc.c
+++ b/ao_adc.c
@@ -18,7 +18,7 @@
 
 #include "ao.h"
 
-volatile __xdata struct ao_adc ao_adc_ring[ADC_RING];
+volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
 volatile __data uint8_t                ao_adc_head;
 
 void
@@ -38,7 +38,7 @@ ao_adc_get(__xdata struct ao_adc *packet)
 {
        uint8_t i = ao_adc_head;
        if (i == 0)
-               i = ADC_RING;
+               i = AO_ADC_RING;
        i--;
        memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc));
 }
@@ -60,7 +60,7 @@ ao_adc_isr(void) interrupt 1
                /* record this conversion series */
                ao_adc_ring[ao_adc_head].tick = ao_time();
                ao_adc_head++;
-               if (ao_adc_head == ADC_RING)
+               if (ao_adc_head == AO_ADC_RING)
                        ao_adc_head = 0;
                ao_wakeup(ao_adc_ring);
        }
index fd87f87edc36b6615d5c1e15f577cc7f81e44769..303f9bc5eaf7021c7552f5170d03a665031ff0bd 100644 (file)
--- a/ao_cmd.c
+++ b/ao_cmd.c
@@ -463,20 +463,18 @@ debug_output(void)
 static void
 dump_log(void)
 {
-#if 0
        uint8_t more;
 
-       for (more = log_first(); more; more = log_next()) {
-               putchar(log_dump.type);
+       for (more = ao_log_dump_first(); more; more = ao_log_dump_next()) {
+               putchar(ao_log_dump.type);
                putchar(' ');
-               put16(log_dump.tick);
+               put16(ao_log_dump.tick);
                putchar(' ');
-               put16(log_dump.u.anon.d0);
+               put16(ao_log_dump.u.anon.d0);
                putchar(' ');
-               put16(log_dump.u.anon.d1);
+               put16(ao_log_dump.u.anon.d1);
                putchar('\n');
        }
-#endif
 }
 
 static const uint8_t help_txt[] = 
diff --git a/ao_ee.c b/ao_ee.c
index 8e2e94d55be133ea8eec40ae664fa0346a929ed8..e731ba2a0b401bef36a8162a7097b57861a0baac 100644 (file)
--- a/ao_ee.c
+++ b/ao_ee.c
@@ -216,15 +216,15 @@ ao_ee_read_block(void)
        ao_ee_cs_high();
 }
        
-void
-ao_ee_flush(void)
+static void
+ao_ee_flush_internal(void)
 {
        if (ao_ee_block_dirty) {
                ao_ee_write_block();
                ao_ee_block_dirty = 0;
        }
 }
-
+       
 static void
 ao_ee_fill(uint16_t block)
 {
@@ -236,7 +236,7 @@ ao_ee_fill(uint16_t block)
 }
 
 uint8_t
-ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len)
+ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant
 {
        uint16_t block;
        uint16_t this_len;
@@ -262,7 +262,7 @@ ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len)
                        if (this_len != 256)
                                ao_ee_fill(block);
                        else {
-                               ao_ee_flush();
+                               ao_ee_flush_internal();
                                ao_ee_block = block;
                        }
                        memcpy(ao_ee_data + this_off, buf, this_len);
@@ -277,7 +277,7 @@ ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len)
 }
 
 uint8_t
-ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len)
+ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant
 {
        uint16_t block;
        uint16_t this_len;
@@ -311,12 +311,20 @@ ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len)
        return 1;
 }
 
+void
+ao_ee_flush(void) __reentrant
+{
+       ao_mutex_get(&ao_ee_mutex); {
+               ao_ee_flush_internal();
+       } ao_mutex_put(&ao_ee_mutex);
+}
+
 /*
  * Read/write the config block, which is in
  * the last block of the ao_eeprom
  */
 uint8_t
-ao_ee_write_config(uint8_t *buf, uint16_t len)
+ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant
 {
        if (len > AO_EE_BLOCK_SIZE)
                return 0;
@@ -329,7 +337,7 @@ ao_ee_write_config(uint8_t *buf, uint16_t len)
 }
 
 uint8_t
-ao_ee_read_config(uint8_t *buf, uint16_t len)
+ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant
 {
        if (len > AO_EE_BLOCK_SIZE)
                return 0;
diff --git a/ao_flight.c b/ao_flight.c
new file mode 100644 (file)
index 0000000..f31b4cd
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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"
+
+/* Main flight thread. */
+
+__xdata struct ao_adc  ao_flight_data;
+__data enum flight_state       ao_flight_state;
+__data uint16_t                        ao_flight_state_tick;
+__data int16_t                 ao_flight_accel;
+__data int16_t                 ao_flight_pres;
+__data int16_t                 ao_ground_pres;
+__data int16_t                 ao_ground_accel;
+__data int16_t                 ao_min_pres;
+__data uint16_t                        ao_launch_time;
+
+/* Accelerometer calibration
+ *
+ * We're sampling the accelerometer through a resistor divider which
+ * consists of 5k and 10k resistors. This multiplies the values by 2/3.
+ * That goes into the cc1111 A/D converter, which is running at 11 bits
+ * of precision with the bits in the MSB of the 16 bit value. Only positive
+ * values are used, so values should range from 0-32752 for 0-3.3V. The
+ * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what
+ * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV,
+ * for a final computation of:
+ *
+ * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g
+ *
+ * Zero g was measured at 16000 (we would expect 16384)
+ */
+
+#define ACCEL_G                265
+#define ACCEL_ZERO_G   16000
+#define ACCEL_NOSE_UP  (ACCEL_ZERO_G - ACCEL_G * 2 /3)
+#define ACCEL_BOOST    (ACCEL_NOSE_UP - ACCEL_G * 2)
+
+/*
+ * Barometer calibration
+ *
+ * We directly sample the barometer. The specs say:
+ *
+ * Pressure range: 15-115 kPa
+ * Voltage at 115kPa: 2.82
+ * Output scale: 27mV/kPa
+ * 
+ * If we want to detect launch with the barometer, we need
+ * a large enough bump to not be fooled by noise. At typical
+ * launch elevations (0-2000m), a 200Pa pressure change cooresponds
+ * to about a 20m elevation change. This is 5.4mV, or about 3LSB.
+ * As all of our calculations are done in 16 bits, we'll actually see a change
+ * of 16 times this though
+ *
+ * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa
+ */
+
+#define BARO_kPa       268
+#define BARO_LAUNCH    (BARO_kPa / 5)  /* .2kPa */
+#define BARO_APOGEE    (BARO_kPa / 10) /* .1kPa */
+
+/* We also have a clock, which can be used to sanity check things in
+ * case of other failures
+ */
+
+#define BOOST_TICKS_MAX        AO_SEC_TO_TICKS(10)
+
+void
+ao_flight(void)
+{
+       __data static uint8_t   nsamples = 0;
+       
+       for (;;) {
+               ao_sleep(&ao_adc_ring);
+               ao_adc_get(&ao_flight_data);
+               ao_flight_accel -= ao_flight_accel >> 4;
+               ao_flight_accel += ao_flight_data.accel >> 4;
+               ao_flight_pres -= ao_flight_pres >> 4;
+               ao_flight_pres += ao_flight_data.pres >> 4;
+               
+               switch (ao_flight_state) {
+               case ao_flight_startup:
+                       if (nsamples < 100) {
+                               ++nsamples;
+                               continue;
+                       }
+                       ao_ground_accel = ao_flight_accel;
+                       ao_ground_pres = ao_flight_pres;
+                       ao_min_pres = ao_flight_pres;
+                       if (ao_flight_accel < ACCEL_NOSE_UP) {
+                               ao_flight_state = ao_flight_launchpad;
+                               ao_flight_state_tick = ao_time();
+                               ao_report_notify();
+                       } else {
+                               ao_flight_state = ao_flight_idle;
+                               ao_flight_state_tick = ao_time();
+                               ao_report_notify();
+                       }
+                       break;
+               case ao_flight_launchpad:
+                       if (ao_flight_accel < ACCEL_BOOST || 
+                           ao_flight_pres + BARO_LAUNCH < ao_ground_pres)
+                       {
+                               ao_flight_state = ao_flight_boost;
+                               ao_flight_state_tick = ao_time();
+                               ao_log_start();
+                               ao_report_notify();
+                               break;
+                       }
+                       break;
+               case ao_flight_boost:
+                       if (ao_flight_accel > ACCEL_ZERO_G ||
+                           (int16_t) (ao_flight_data.tick - ao_launch_time) > BOOST_TICKS_MAX)
+                       {
+                               ao_flight_state = ao_flight_coast;
+                               ao_flight_state_tick = ao_time();
+                               ao_report_notify();
+                               break;
+                       }
+                       break;
+               case ao_flight_coast:
+                       if (ao_flight_pres < ao_min_pres)
+                               ao_min_pres = ao_flight_pres;
+                       if (ao_flight_pres - BARO_APOGEE > ao_min_pres) {
+                               ao_flight_state = ao_flight_apogee;
+                               ao_flight_state_tick = ao_time();
+                               ao_report_notify();
+                       }
+                       break;
+               case ao_flight_apogee:
+                       break;
+               }
+       }
+}
+
+static __xdata struct ao_task  flight_task;
+
+void
+ao_flight_init(void)
+{
+       ao_flight_state = ao_flight_startup;
+
+       ao_add_task(&flight_task, ao_flight);
+}
+
diff --git a/ao_log.c b/ao_log.c
new file mode 100644 (file)
index 0000000..112ea51
--- /dev/null
+++ b/ao_log.c
@@ -0,0 +1,189 @@
+/*
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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"
+
+__data uint32_t                ao_log_current_pos;
+__data uint32_t                ao_log_start_pos;
+__xdata uint8_t                ao_log_running;
+__xdata uint8_t                ao_log_mutex;
+
+static uint8_t
+ao_log_csum(uint8_t *b)
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_record); i++)
+               sum += *b++;
+       return -sum;
+}
+
+void
+ao_log_data(struct ao_log_record *log)
+{
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_running) {
+                       ao_ee_write(ao_log_current_pos,
+                                   (uint8_t *) log,
+                                   sizeof (struct ao_log_record));
+                       ao_log_current_pos += sizeof (struct ao_log_record);
+                       if (ao_log_current_pos >= AO_EE_DATA_SIZE)
+                               ao_log_current_pos = 0;
+                       if (ao_log_current_pos == ao_log_start_pos)
+                               ao_log_running = 0;
+               }
+       } ao_mutex_put(&ao_log_mutex);
+}
+
+void
+ao_log_flush(void)
+{
+       ao_ee_flush();
+}
+
+__xdata struct ao_log_record ao_log_dump;
+static __data uint16_t ao_log_dump_flight;
+static __data uint32_t ao_log_dump_pos;
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &ao_log_dump) != 0)
+               return 0;
+       return 1;
+}
+
+static uint8_t
+ao_log_dump_scan(void)
+{
+       if (!ao_ee_read(0, (uint8_t *) &ao_log_dump, sizeof (struct ao_log_record)))
+               ao_panic(AO_PANIC_LOG);
+       if (ao_log_dump_check_data() && ao_log_dump.type == AO_LOG_FLIGHT) {
+               ao_log_dump_flight = ao_log_dump.u.flight.flight;
+               return 1;
+       } else {
+               ao_log_dump_flight = 0;
+               return 0;
+       }
+}
+
+uint8_t
+ao_log_dump_first(void)
+{
+       ao_log_dump_pos = 0;
+       if (!ao_log_dump_scan())
+               return 0;
+       return 1;
+}
+
+uint8_t
+ao_log_dump_next(void)
+{
+       ao_log_dump_pos += sizeof (struct ao_log_record);
+       if (ao_log_dump_pos >= AO_EE_DEVICE_SIZE)
+               return 0;
+       if (!ao_ee_read(ao_log_dump_pos, (uint8_t *) &ao_log_dump,
+                       sizeof (struct ao_log_record)))
+               return 0;
+       return ao_log_dump_check_data();
+}
+
+uint8_t        ao_log_adc_pos;
+enum flight_state ao_log_state;
+
+void
+ao_log(void)
+{
+       static __xdata struct ao_log_record     log;
+       
+       ao_log_dump_scan();
+
+       while (!ao_log_running)
+               ao_sleep(&ao_log_running);
+       
+       log.type = AO_LOG_FLIGHT;
+       log.tick = ao_flight_state_tick;
+       log.u.flight.serial = 0;
+       log.u.flight.flight = ao_log_dump_flight + 1;
+       ao_log_data(&log);
+       for (;;) {
+               /* Write state change to EEPROM */
+               if (ao_flight_state != ao_log_state) {
+                       ao_log_state = ao_flight_state;
+                       log.type = AO_LOG_STATE;
+                       log.tick = ao_flight_state_tick;
+                       log.u.state.state = ao_log_state;
+                       log.u.state.reason = 0;
+                       ao_log_data(&log);
+               }
+               /* Write samples to EEPROM */
+               while (ao_log_adc_pos != ao_adc_head) {
+                       log.type = AO_LOG_SENSOR;
+                       log.tick = ao_adc_ring[ao_log_adc_pos].tick;
+                       log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel;
+                       log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres;
+                       ao_log_data(&log);
+                       if (ao_log_adc_pos == 0) {
+                               log.type = AO_LOG_TEMP_VOLT;
+                               log.tick = ao_adc_ring[ao_log_adc_pos].tick;
+                               log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp;
+                               log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt;
+                               ao_log_data(&log);
+                               log.type = AO_LOG_DEPLOY;
+                               log.tick = ao_adc_ring[ao_log_adc_pos].tick;
+                               log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d;
+                               log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m;
+                               ao_log_data(&log);
+                       }
+                       ao_log_adc_pos++;
+                       if (ao_log_adc_pos == AO_ADC_RING)
+                               ao_log_adc_pos = 0;
+               }
+               
+               /* Wait for a while */
+               ao_delay(AO_MS_TO_TICKS(100));
+       }
+}
+
+void
+ao_log_start(void)
+{
+       /* start logging */
+       ao_log_running = 1;
+       ao_wakeup(&ao_log_running);
+}
+
+static __xdata struct ao_task ao_log_task;
+
+void
+ao_log_init(void)
+{
+       ao_log_running = 0;
+
+       /* For now, just log the flight starting at the begining of eeprom */
+       ao_log_start_pos = 0;
+       ao_log_current_pos = ao_log_start_pos;
+       ao_log_state = ao_flight_invalid;
+
+       /* Create a task to log events to eeprom */
+       ao_add_task(&ao_log_task, ao_log);
+}
diff --git a/ao_report.c b/ao_report.c
new file mode 100644 (file)
index 0000000..1cc883b
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 const char * __xdata flight_reports[] = {
+       "...",          /* startup, 'S' */
+       "..",           /* idle 'I' */
+       ".--.",         /* launchpad 'P' */
+       "-...",         /* boost 'B' */
+       "-.-.",         /* coast 'C' */
+       ".-",           /* apogee 'A' */
+       "-..",          /* drogue 'D' */
+       "--",           /* main 'M' */
+       ".-..",         /* landed 'L' */
+       ".-.-.-",       /* invalid */
+};
+
+#if 1
+#define signal(time)   ao_beep_for(AO_BEEP_MID, time)
+#else
+#define signal(time)   ao_led_for(AO_LED_RED, time)
+#endif
+#define pause(time)    ao_delay(time)
+
+static void
+ao_report_state(void)
+{
+       char *r = flight_reports[ao_flight_state];
+       char c;
+
+       if (!r)
+               return;
+       while (c = *r++) {
+               if (c == '.')
+                       signal(AO_MS_TO_TICKS(200));
+               else
+                       signal(AO_MS_TO_TICKS(600));
+               pause(AO_MS_TO_TICKS(200));
+       }
+}
+
+static __xdata ao_report_wait;
+
+void
+ao_report_notify(void)
+{
+       ao_wakeup(&ao_report_wait);
+}
+
+void
+ao_report(void)
+{
+       for(;;) {
+               ao_report_state();
+               ao_sleep(&ao_report_wait);
+       }
+}
+
+static __xdata struct ao_task ao_report_task;
+
+void
+ao_report_init(void)
+{
+       ao_add_task(&ao_report_task, ao_report);
+}
index 9583a388d26983e01b0b9bdb2788ba3073d06f43..702159b73f64f0bb918a6e3417c3b971ff5c13a4 100644 (file)
@@ -42,10 +42,16 @@ ao_delay(uint16_t ticks)
 #define T1_CLOCK_DIVISOR       8       /* 24e6/8 = 3e6 */
 #define T1_SAMPLE_TIME         30000   /* 3e6/30000 = 100 */
 
+__data uint8_t ao_adc_interval = 1;
+__data uint8_t ao_adc_count;
+
 void ao_timer_isr(void) interrupt 9
 {
        ++ao_tick_count;
-       ao_adc_poll();
+       if (++ao_adc_count >= ao_adc_interval) {
+               ao_adc_count = 0;
+               ao_adc_poll();
+       }
        ao_wakeup(DATA_TO_XDATA(&ao_tick_count));
 }