Add igniters and update flight control algorithm
authorKeith Packard <keithp@keithp.com>
Fri, 24 Apr 2009 05:17:44 +0000 (22:17 -0700)
committerKeith Packard <keithp@keithp.com>
Fri, 24 Apr 2009 15:39:00 +0000 (08:39 -0700)
Makefile
ao.h
ao_adc.c
ao_flight.c
ao_flight_test.c [new file with mode: 0644]
ao_ignite.c [new file with mode: 0644]
ao_log.c
ao_monitor.c
ao_telemetrum.c

index 2a6b7adc4f217b4dba59d3b4e2b416de154281dc..a391c510cd56b258f3b2937c066175d706870f97 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -61,7 +61,8 @@ TELE_DRIVER_SRC = \
 #
 TM_DRIVER_SRC = \
        ao_adc.c \
 #
 TM_DRIVER_SRC = \
        ao_adc.c \
-       ao_ee.c
+       ao_ee.c \
+       ao_ignite.c
 
 #
 # Tasks run on TeleMetrum
 
 #
 # Tasks run on TeleMetrum
@@ -193,3 +194,6 @@ clean:
        rm -f $(PROGS) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
 
 install:
        rm -f $(PROGS) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
 
 install:
+
+ao_flight_test: ao_flight.c ao_flight_test.c
+       cc -g -o $@ ao_flight_test.c
diff --git a/ao.h b/ao.h
index b10f1b34c1d2502cdd60c0252da5bfcc00447830..137a01437adba91dbaca9adf312833cece0e8986 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
  */
 /* 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 0x68
+#define AO_STACK_START 0x70
 #define AO_STACK_END   0xfe
 #define AO_STACK_SIZE  (AO_STACK_END - AO_STACK_START + 1)
 
 #define AO_STACK_END   0xfe
 #define AO_STACK_SIZE  (AO_STACK_END - AO_STACK_START + 1)
 
@@ -123,6 +123,8 @@ ao_timer_init(void);
  */
 
 #define AO_ADC_RING    64
  */
 
 #define AO_ADC_RING    64
+#define ao_adc_ring_next(n)    (((n) + 1) & (AO_ADC_RING - 1))
+#define ao_adc_ring_prev(n)    (((n) - 1) & (AO_ADC_RING - 1))
 
 /*
  * One set of samples read from the A/D converter
 
 /*
  * One set of samples read from the A/D converter
@@ -544,7 +546,7 @@ enum ao_flight_state {
 };
 
 extern __xdata struct ao_adc           ao_flight_data;
 };
 
 extern __xdata struct ao_adc           ao_flight_data;
-extern __pdata enum flight_state       ao_flight_state;
+extern __pdata enum ao_flight_state    ao_flight_state;
 extern __pdata uint16_t                        ao_flight_tick;
 extern __pdata int16_t                 ao_flight_accel;
 extern __pdata int16_t                 ao_flight_pres;
 extern __pdata uint16_t                        ao_flight_tick;
 extern __pdata int16_t                 ao_flight_accel;
 extern __pdata int16_t                 ao_flight_pres;
@@ -734,5 +736,30 @@ ao_monitor_init(void);
 void
 flush(void);
 
 void
 flush(void);
 
+/*
+ * ao_ignite.c
+ */
+
+enum ao_igniter {
+       ao_igniter_drogue = 0,
+       ao_igniter_main = 1
+};
+
+void
+ao_ignite(enum ao_igniter igniter);
+
+enum ao_igniter_status {
+       ao_igniter_unknown,     /* unknown status (ambiguous voltage) */
+       ao_igniter_ready,       /* continuity detected */
+       ao_igniter_active,      /* igniter firing */
+       ao_igniter_open,        /* open circuit detected */
+};
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter);
+
+void
+ao_igniter_init(void);
+
 #endif /* _AO_H_ */
 
 #endif /* _AO_H_ */
 
index 82e1b01b7ad72eacf5eda1b7fa3234251c2f9832..639c5f6c3b9281f6096c3d3b7308a4c7cacf53b5 100644 (file)
--- a/ao_adc.c
+++ b/ao_adc.c
@@ -35,10 +35,7 @@ ao_adc_sleep(void)
 void
 ao_adc_get(__xdata struct ao_adc *packet)
 {
 void
 ao_adc_get(__xdata struct ao_adc *packet)
 {
-       uint8_t i = ao_adc_head;
-       if (i == 0)
-               i = AO_ADC_RING;
-       i--;
+       uint8_t i = ao_adc_ring_prev(ao_adc_head);
        memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc));
 }
 
        memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc));
 }
 
@@ -58,9 +55,7 @@ ao_adc_isr(void) interrupt 1
        } else {
                /* record this conversion series */
                ao_adc_ring[ao_adc_head].tick = ao_time();
        } else {
                /* record this conversion series */
                ao_adc_ring[ao_adc_head].tick = ao_time();
-               ao_adc_head++;
-               if (ao_adc_head == AO_ADC_RING)
-                       ao_adc_head = 0;
+               ao_adc_head = ao_adc_ring_next(ao_adc_head);
                ao_wakeup(ao_adc_ring);
        }
 }
                ao_wakeup(ao_adc_ring);
        }
 }
index 3aff866aa664c27a8383e5d8a6ed51f948aaa51b..5998f291c42881e7c361af105b03659c0be8deb9 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#ifndef AO_FLIGHT_TEST
 #include "ao.h"
 #include "ao.h"
+#endif
 
 /* Main flight thread. */
 
 
 /* Main flight thread. */
 
-__xdata struct ao_adc          ao_flight_data;         /* last acquired data */
-__pdata enum flight_state      ao_flight_state;        /* current flight state */
+__pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
 __pdata uint16_t               ao_flight_tick;         /* time of last data */
 __pdata int16_t                        ao_flight_accel;        /* filtered acceleration */
 __pdata int16_t                        ao_flight_pres;         /* filtered pressure */
 __pdata uint16_t               ao_flight_tick;         /* time of last data */
 __pdata int16_t                        ao_flight_accel;        /* filtered acceleration */
 __pdata int16_t                        ao_flight_pres;         /* filtered pressure */
@@ -44,6 +45,9 @@ __pdata int16_t                       ao_interval_max_accel;
 __pdata int16_t                        ao_interval_min_pres;
 __pdata int16_t                        ao_interval_max_pres;
 
 __pdata int16_t                        ao_interval_min_pres;
 __pdata int16_t                        ao_interval_max_pres;
 
+__data uint8_t ao_flight_adc;
+__xdata int16_t ao_accel, ao_prev_accel, ao_pres;
+
 #define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(5)
 
 /* Accelerometer calibration
 #define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(5)
 
 /* Accelerometer calibration
@@ -66,6 +70,7 @@ __pdata int16_t                       ao_interval_max_pres;
 #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)
 #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)
+#define ACCEL_LAND     (ACCEL_G / 10)
 
 /*
  * Barometer calibration
 
 /*
  * Barometer calibration
@@ -96,23 +101,45 @@ __pdata int16_t                    ao_interval_max_pres;
  * case of other failures
  */
 
  * case of other failures
  */
 
-#define BOOST_TICKS_MAX        AO_SEC_TO_TICKS(10)
+#define BOOST_TICKS_MAX        AO_SEC_TO_TICKS(15)
+
+/* This value is scaled in a weird way. It's a running total of accelerometer
+ * readings minus the ground accelerometer reading. That means it measures
+ * velocity, and quite accurately too. As it gets updated 100 times a second,
+ * it's scaled by 100
+ */
+__data int32_t ao_flight_vel;
+
+/* convert m/s to velocity count */
+#define VEL_MPS_TO_COUNT(mps) ((int32_t) ((int32_t) (mps) * (int32_t) 100 / (int32_t) ACCEL_G))
 
 void
 ao_flight(void)
 {
        __pdata static uint8_t  nsamples = 0;
        
 
 void
 ao_flight(void)
 {
        __pdata static uint8_t  nsamples = 0;
        
+       ao_flight_adc = ao_adc_head;
+       ao_prev_accel = 0;
+       ao_accel = 0;
+       ao_pres = 0;
        for (;;) {
                ao_sleep(&ao_adc_ring);
        for (;;) {
                ao_sleep(&ao_adc_ring);
-               ao_adc_get(&ao_flight_data);
+               while (ao_flight_adc != ao_adc_head) {
+                       ao_accel = ao_adc_ring[ao_flight_adc].accel;
+                       ao_pres = ao_adc_ring[ao_flight_adc].pres;
+                       ao_flight_tick = ao_adc_ring[ao_flight_adc].tick;
+                       ao_flight_vel += (int32_t) (((ao_accel + ao_prev_accel) >> 4) - (ao_ground_accel << 1));
+                       ao_prev_accel = ao_accel;
+                       ao_flight_adc = ao_adc_ring_next(ao_flight_adc);
+               }
                ao_flight_accel -= ao_flight_accel >> 4;
                ao_flight_accel -= ao_flight_accel >> 4;
-               ao_flight_accel += ao_flight_data.accel >> 4;
+               ao_flight_accel += ao_accel >> 4;
                ao_flight_pres -= ao_flight_pres >> 4;
                ao_flight_pres -= ao_flight_pres >> 4;
-               ao_flight_pres += ao_flight_data.pres >> 4;
-               ao_flight_tick = ao_time();
+               ao_flight_pres += ao_pres >> 4;
                
                
-               ao_flight_tick = ao_time();
+               if (ao_flight_pres < ao_min_pres)
+                       ao_min_pres = ao_flight_pres;
+
                if ((int16_t) (ao_flight_tick - ao_interval_end) >= 0) {
                        ao_interval_max_pres = ao_interval_cur_max_pres;
                        ao_interval_min_pres = ao_interval_cur_min_pres;
                if ((int16_t) (ao_flight_tick - ao_interval_end) >= 0) {
                        ao_interval_max_pres = ao_interval_cur_max_pres;
                        ao_interval_min_pres = ao_interval_cur_min_pres;
@@ -131,11 +158,12 @@ ao_flight(void)
                        ao_ground_pres = ao_flight_pres;
                        ao_min_pres = ao_flight_pres;
                        ao_main_pres = ao_ground_pres - BARO_MAIN;
                        ao_ground_pres = ao_flight_pres;
                        ao_min_pres = ao_flight_pres;
                        ao_main_pres = ao_ground_pres - BARO_MAIN;
+                       ao_flight_vel = 0;
                        
                        ao_interval_end = ao_flight_tick;
                        
                        
                        ao_interval_end = ao_flight_tick;
                        
-                       /* Go to launchpad state if the nose is pointing up and the battery is charged */
-                       if (ao_flight_accel < ACCEL_NOSE_UP && ao_flight_data.v_batt > 23000) {
+                       /* Go to launchpad state if the nose is pointing up */
+                       if (ao_flight_accel < ACCEL_NOSE_UP) {
                                ao_flight_state = ao_flight_launchpad;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        } else {
                                ao_flight_state = ao_flight_launchpad;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        } else {
@@ -152,6 +180,12 @@ ao_flight(void)
                        ao_led_off(AO_LED_RED);
                        break;
                case ao_flight_launchpad:
                        ao_led_off(AO_LED_RED);
                        break;
                case ao_flight_launchpad:
+
+                       /* pad to boost:
+                        *
+                        * accelerometer: > 2g
+                        * barometer: > 20m vertical motion
+                        */
                        if (ao_flight_accel < ACCEL_BOOST || 
                            ao_flight_pres + BARO_LAUNCH < ao_ground_pres)
                        {
                        if (ao_flight_accel < ACCEL_BOOST || 
                            ao_flight_pres + BARO_LAUNCH < ao_ground_pres)
                        {
@@ -162,8 +196,14 @@ ao_flight(void)
                        }
                        break;
                case ao_flight_boost:
                        }
                        break;
                case ao_flight_boost:
-                       if (ao_flight_accel > ACCEL_ZERO_G ||
-                           (int16_t) (ao_flight_data.tick - ao_launch_time) > BOOST_TICKS_MAX)
+
+                       /* boost to coast:
+                        *
+                        * accelerometer: start to fall at > 1/4 G
+                        * time: boost for more than 15 seconds
+                        */
+                       if (ao_flight_accel > ao_ground_accel + (ACCEL_G >> 2) ||
+                           (int16_t) (ao_flight_tick - ao_launch_time) > BOOST_TICKS_MAX)
                        {
                                ao_flight_state = ao_flight_coast;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        {
                                ao_flight_state = ao_flight_coast;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
@@ -171,31 +211,60 @@ ao_flight(void)
                        }
                        break;
                case ao_flight_coast:
                        }
                        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) {
+                       
+                       /* coast to apogee detect:
+                        * 
+                        * accelerometer: integrated velocity < 200 m/s
+                        * barometer: fall at least 500m from max altitude
+                        */
+                       if (ao_flight_vel < VEL_MPS_TO_COUNT(200) ||
+                           ao_flight_pres - (5 * BARO_kPa) > ao_min_pres)
+                       {
                                ao_flight_state = ao_flight_apogee;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
                        break;
                case ao_flight_apogee:
                                ao_flight_state = ao_flight_apogee;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
                        break;
                case ao_flight_apogee:
-//                     ao_ignite(AO_IGNITE_DROGUE);
-                       ao_flight_state = ao_flight_drogue;
-                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+
+                       /* apogee to drogue deploy:
+                        *
+                        * accelerometer: integrated velocity < 10m/s
+                        * barometer: fall at least 10m
+                        */
+                       if (ao_flight_vel < VEL_MPS_TO_COUNT(-10) ||
+                           ao_flight_pres - BARO_APOGEE > ao_min_pres)
+                       {
+                               ao_ignite(ao_igniter_drogue);
+                               ao_flight_state = ao_flight_drogue;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
                        break; 
                case ao_flight_drogue:
                        break; 
                case ao_flight_drogue:
-                       if (ao_flight_pres >= ao_main_pres) {
-//                             ao_ignite(AO_IGNITE_MAIN);
+                       
+                       /* drogue to main deploy:
+                        *
+                        * accelerometer: abs(velocity) > 50m/s
+                        * barometer: reach main deploy altitude
+                        */
+                       if (ao_flight_vel < VEL_MPS_TO_COUNT(-50) ||
+                           ao_flight_vel > VEL_MPS_TO_COUNT(50) ||
+                           ao_flight_pres >= ao_main_pres)
+                       {
+                               ao_ignite(ao_igniter_main);
                                ao_flight_state = ao_flight_main;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
                                ao_flight_state = ao_flight_main;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
-                       if ((ao_interval_max_pres - ao_interval_min_pres) < BARO_LAND) {
-                               ao_flight_state = ao_flight_landed;
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       }
-                       break;
+                       /* fall through... */
                case ao_flight_main:
                case ao_flight_main:
-                       if ((ao_interval_max_pres - ao_interval_min_pres) < BARO_LAND) {
+
+                       /* drogue/main to land:
+                        *
+                        * accelerometer: value stable
+                        * barometer: altitude stable
+                        */
+                       if ((ao_interval_max_accel - ao_interval_min_accel) < ACCEL_LAND ||
+                            (ao_interval_max_pres - ao_interval_min_pres) < BARO_LAND)
+                       {
                                ao_flight_state = ao_flight_landed;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
                                ao_flight_state = ao_flight_landed;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
diff --git a/ao_flight_test.c b/ao_flight_test.c
new file mode 100644 (file)
index 0000000..a88d2b1
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define AO_ADC_RING    64
+#define ao_adc_ring_next(n)    (((n) + 1) & (AO_ADC_RING - 1))
+#define ao_adc_ring_prev(n)    (((n) - 1) & (AO_ADC_RING - 1))
+
+/*
+ * One set of samples read from the A/D converter
+ */
+struct ao_adc {
+       uint16_t        tick;           /* tick when the sample was read */
+       int16_t         accel;          /* accelerometer */
+       int16_t         pres;           /* pressure sensor */
+       int16_t         temp;           /* temperature sensor */
+       int16_t         v_batt;         /* battery voltage */
+       int16_t         sense_d;        /* drogue continuity sense */
+       int16_t         sense_m;        /* main continuity sense */
+};
+
+#define __pdata
+#define __data
+#define __xdata
+
+enum ao_flight_state {
+       ao_flight_startup = 0,
+       ao_flight_idle = 1,
+       ao_flight_launchpad = 2,
+       ao_flight_boost = 3,
+       ao_flight_coast = 4,
+       ao_flight_apogee = 5,
+       ao_flight_drogue = 6,
+       ao_flight_main = 7,
+       ao_flight_landed = 8,
+       ao_flight_invalid = 9
+};
+
+struct ao_adc ao_adc_ring[AO_ADC_RING];
+uint8_t ao_adc_head;
+
+#define ao_led_on(l)
+#define ao_led_off(l)
+#define ao_timer_set_adc_interval(i)
+#define ao_wakeup(wchan) ao_dump_state()
+
+enum ao_igniter {
+       ao_igniter_drogue = 0,
+       ao_igniter_main = 1
+};
+
+void
+ao_ignite(enum ao_igniter igniter)
+{
+       printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main");
+}
+
+struct ao_task {
+       int dummy;
+};
+
+#define ao_add_task(t,f,n)
+
+#define ao_log_start()
+#define ao_log_stop()
+
+#define AO_MS_TO_TICKS(ms)     ((ms) / 10)
+#define AO_SEC_TO_TICKS(s)     ((s) * 100)
+
+#define AO_FLIGHT_TEST
+
+struct ao_adc ao_adc_static;
+
+FILE *emulator_in;
+
+void
+ao_dump_state(void);
+
+void
+ao_sleep(void *wchan);
+       
+#include "ao_flight.c"
+
+void
+ao_insert(void)
+{
+       ao_adc_ring[ao_adc_head] = ao_adc_static;
+       ao_adc_head = ao_adc_ring_next(ao_adc_head);
+       if (ao_flight_state != ao_flight_startup) {
+               printf("tick %04x accel %04x pres %04x\n", 
+                      ao_adc_static.tick,
+                      ao_adc_static.accel,
+                      ao_adc_static.pres);
+       }
+}
+
+static int     ao_records_read = 0;
+
+void
+ao_sleep(void *wchan)
+{
+       ao_dump_state();
+       if (wchan == &ao_adc_ring) {
+               char            type;
+               uint16_t        tick;
+               uint16_t        a, b;
+               int             ret;
+
+               for (;;) {
+                       if (ao_records_read > 20 && ao_flight_state == ao_flight_startup)
+                       {
+                               ao_insert();
+                               return;
+                       }
+
+                       ret = fscanf(emulator_in, "%c %hx %hx %hx\n", &type, &tick, &a, &b);
+                       if (ret == EOF) {
+                               ao_insert();
+                               return;
+                       }
+                       if (ret != 4)
+                               continue;
+                       switch (type) {
+                       case 'F':
+                               break;
+                       case 'S':
+                               break;
+                       case 'A':
+                               ao_adc_static.tick = tick;
+                               ao_adc_static.accel = a;
+                               ao_adc_static.pres = b;
+                               ao_records_read++;
+                               ao_insert();
+                               return;
+                       case 'T':
+                               ao_adc_static.tick = tick;
+                               ao_adc_static.temp = a;
+                               ao_adc_static.v_batt = b;
+                               break;
+                       case 'D':
+                       case 'G':
+                       case 'N':
+                       case 'W':
+                       case 'H':
+                               break;
+                       }
+               }
+               
+       }
+}
+
+const char const * const ao_state_names[] = {
+       "startup", "idle", "pad", "boost", "coast",
+       "apogee", "drogue", "main", "landed", "invalid"
+};
+
+static int16_t altitude[2048] = {
+#include "altitude.h"
+};
+
+#define GRAVITY 9.80665
+#define COUNTS_PER_G 264.8
+
+void
+ao_dump_state(void)
+{
+       if (ao_flight_state == ao_flight_startup)
+               return;
+       printf ("\t%s accel %g vel %g alt %d\n",
+               ao_state_names[ao_flight_state],
+               (ao_flight_accel - ao_ground_accel) / COUNTS_PER_G * GRAVITY,
+               (double) ao_flight_vel,
+               altitude[ao_flight_pres >> 4]);
+       if (ao_flight_state == ao_flight_landed)
+               exit(0);
+}
+
+int
+main (int argc, char **argv)
+{
+       emulator_in = fopen (argv[1], "r");
+       if (!emulator_in) {
+               perror(argv[1]);
+               exit(1);
+       }
+       ao_flight_init();
+       ao_flight();
+}
diff --git a/ao_ignite.c b/ao_ignite.c
new file mode 100644 (file)
index 0000000..acb9399
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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"
+
+#define AO_IGNITER_DROGUE      P2_3
+#define AO_IGNITER_MAIN                P2_4
+
+/* XXX test these values with real igniters */
+#define AO_IGNITER_OPEN                100
+#define AO_IGNITER_CLOSED      20000
+#define AO_IGNITER_FIRE_TIME   AO_MS_TO_TICKS(50)
+#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(200)
+
+struct ao_ignition {
+       uint8_t request;
+       uint8_t fired;
+       uint8_t firing;
+};
+
+__xdata struct ao_ignition ao_ignition[2];
+
+void
+ao_ignite(enum ao_igniter igniter) __critical
+{
+       ao_ignition[igniter].request = 1;
+       ao_wakeup(&ao_ignition[0]);
+}
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter)
+{
+       __xdata struct ao_adc adc;
+       __xdata int16_t value;
+       __xdata uint8_t request, firing, fired;
+
+       __critical {
+               ao_adc_sleep();
+               ao_adc_get(&adc);
+               request = ao_ignition[igniter].request;
+               fired = ao_ignition[igniter].fired;
+               firing = ao_ignition[igniter].firing;
+       }
+       if (firing || (request && !fired))
+               return ao_igniter_active;
+
+       value = (AO_IGNITER_CLOSED>>1);
+       switch (igniter) {
+       case ao_igniter_drogue:
+               value = adc.sense_d;
+               break;
+       case ao_igniter_main:
+               value = adc.sense_m;
+               break;
+       }
+       if (value < AO_IGNITER_OPEN)
+               return ao_igniter_open;
+       else if (value > AO_IGNITER_CLOSED)
+               return ao_igniter_ready;
+       else
+               return ao_igniter_unknown;
+}
+
+void
+ao_igniter_fire(enum ao_igniter igniter) __critical
+{
+       ao_ignition[igniter].firing = 1;
+       switch (igniter) {
+       case ao_igniter_drogue:
+               AO_IGNITER_DROGUE = 1;
+               ao_delay(AO_IGNITER_FIRE_TIME);
+               AO_IGNITER_DROGUE = 0;
+               break;
+       case ao_igniter_main:
+               AO_IGNITER_MAIN = 1;
+               ao_delay(AO_IGNITER_FIRE_TIME);
+               AO_IGNITER_MAIN = 0;
+               break;
+       }
+       ao_ignition[igniter].firing = 0;
+}
+
+void
+ao_igniter(void)
+{
+       __xdata enum ao_ignter igniter;
+       __xdata enum ao_igniter_status status;
+
+       for (;;) {
+               ao_sleep(&ao_ignition);
+               for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) {
+                       if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) {
+                               ao_igniter_fire(igniter);
+                               ao_delay(AO_IGNITER_CHARGE_TIME);
+                               status = ao_igniter_status(igniter);
+                               if (status == ao_igniter_open)
+                                       ao_ignition[igniter].fired = 1;
+                       }
+               }
+       }
+}
+
+__xdata struct ao_task ao_igniter_task;
+
+void
+ao_igniter_init(void)
+{
+       ao_add_task(&ao_igniter_task, ao_igniter, "igniter");
+}
index 1b473c14eb1d6f3702696c399260c944517d34d1..c74893f87af9a61b11d4343ae6a21b0b69630e5a 100644 (file)
--- a/ao_log.c
+++ b/ao_log.c
@@ -153,9 +153,7 @@ ao_log(void)
                                log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m;
                                ao_log_data(&log);
                        }
                                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;
+                       ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos);
                }
                
                /* Wait for a while */
                }
                
                /* Wait for a while */
index 3db5e42d8a5563c64af6cdc63b19a5c1eaaa75ee..845b63bf624840e0ea4914fc7f98d0fec0fe87d9 100644 (file)
@@ -52,6 +52,7 @@ ao_monitor(void)
                       recv.telemetry.adc.sense_m);
                ao_gps_print(&recv.telemetry.gps);
                ao_usb_flush();
                       recv.telemetry.adc.sense_m);
                ao_gps_print(&recv.telemetry.gps);
                ao_usb_flush();
+               ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(10));
        }
 }
 
        }
 }
 
index d2e05eb5847cb10cf1b94adf2e66e5bdd4d5af84..0a4b3a499b207b0ecf15b553cd6f2218159db661 100644 (file)
@@ -41,6 +41,7 @@ main(void)
        ao_gps_init();
        ao_telemetry_init();
        ao_radio_init();
        ao_gps_init();
        ao_telemetry_init();
        ao_radio_init();
+       ao_igniter_init();
        ao_dbg_init();
        ao_start_scheduler();
 }
        ao_dbg_init();
        ao_start_scheduler();
 }