add static test start and stop commands to radio protocol for telefiretwo
[fw/altos] / src / drivers / ao_pad.c
index 144cbd70a8834e4053e67c6bebec423e68ae8175..28c00fe33ed51385a9384c08af5328a5d6b6b3b0 100644 (file)
@@ -3,7 +3,8 @@
  *
  * 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.
+ * 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
@@ -29,6 +30,10 @@ static __pdata uint8_t       ao_pad_box;
 static __xdata uint8_t ao_pad_disabled;
 static __pdata uint16_t        ao_pad_packet_time;
 
+#ifndef AO_PAD_RSSI_MINIMUM
+#define AO_PAD_RSSI_MINIMUM    -90
+#endif
+
 #define DEBUG  1
 
 #if DEBUG
@@ -36,8 +41,8 @@ static __pdata uint8_t        ao_pad_debug;
 #define PRINTD(...) (ao_pad_debug ? (printf(__VA_ARGS__), 0) : 0)
 #define FLUSHD()    (ao_pad_debug ? (flush(), 0) : 0)
 #else
-#define PRINTD(...) 
-#define FLUSHD()    
+#define PRINTD(...)
+#define FLUSHD()
 #endif
 
 static void
@@ -46,7 +51,11 @@ ao_siren(uint8_t v)
 #ifdef AO_SIREN
        ao_gpio_set(AO_SIREN_PORT, AO_SIREN_PIN, AO_SIREN, v);
 #else
+#if HAS_BEEP
        ao_beep(v ? AO_BEEP_MID : 0);
+#else
+       (void) v;
+#endif
 #endif
 }
 
@@ -55,13 +64,15 @@ ao_strobe(uint8_t v)
 {
 #ifdef AO_STROBE
        ao_gpio_set(AO_STROBE_PORT, AO_STROBE_PIN, AO_STROBE, v);
+#else
+       (void) v;
 #endif
 }
 
 static void
 ao_pad_run(void)
 {
-       uint8_t pins;
+       AO_PORT_TYPE    pins;
 
        for (;;) {
                while (!ao_pad_ignite)
@@ -86,18 +97,28 @@ ao_pad_run(void)
                if (ao_pad_ignite & (1 << 3))
                        pins |= (1 << AO_PAD_PIN_3);
 #endif
-               AO_PAD_PORT = (AO_PAD_PORT & (~AO_PAD_ALL_PINS)) | pins;
+               PRINTD("ignite pins 0x%x\n", pins);
+               ao_gpio_set_bits(AO_PAD_PORT, pins);
                while (ao_pad_ignite) {
                        ao_pad_ignite = 0;
 
                        ao_delay(AO_PAD_FIRE_TIME);
                }
-               AO_PAD_PORT &= ~(AO_PAD_ALL_PINS);
+               ao_gpio_clr_bits(AO_PAD_PORT, pins);
+               PRINTD("turn off pins 0x%x\n", pins);
        }
 }
 
 #define AO_PAD_ARM_SIREN_INTERVAL      200
 
+#ifndef AO_PYRO_R_PYRO_SENSE
+#define AO_PYRO_R_PYRO_SENSE   100
+#define AO_PYRO_R_SENSE_GND    27
+#define AO_FIRE_R_POWER_FET    100
+#define AO_FIRE_R_FET_SENSE    100
+#define AO_FIRE_R_SENSE_GND    27
+#endif
+
 static void
 ao_pad_monitor(void)
 {
@@ -105,7 +126,7 @@ ao_pad_monitor(void)
        uint8_t                 sample;
        __pdata uint8_t         prev = 0, cur = 0;
        __pdata uint8_t         beeping = 0;
-       __xdata struct ao_data  *packet;
+       __xdata volatile struct ao_data *packet;
        __pdata uint16_t        arm_beep_time = 0;
 
        sample = ao_data_head;
@@ -116,29 +137,39 @@ ao_pad_monitor(void)
                                ao_sleep((void *) DATA_TO_XDATA(&ao_data_head));
                        );
 
+
                packet = &ao_data_ring[sample];
                sample = ao_data_ring_next(sample);
 
                pyro = packet->adc.pyro;
 
-#define VOLTS_TO_PYRO(x) ((int16_t) ((x) * 27.0 / 127.0 / 3.3 * 32767.0))
+#define VOLTS_TO_PYRO(x) ((int16_t) ((x) * ((1.0 * AO_PYRO_R_SENSE_GND) / \
+                                           (1.0 * (AO_PYRO_R_SENSE_GND + AO_PYRO_R_PYRO_SENSE)) / 3.3 * AO_ADC_MAX)))
 
+
+#define VOLTS_TO_FIRE(x) ((int16_t) ((x) * ((1.0 * AO_FIRE_R_SENSE_GND) / \
+                                           (1.0 * (AO_FIRE_R_SENSE_GND + AO_FIRE_R_FET_SENSE)) / 3.3 * AO_ADC_MAX)))
+
+               /* convert ADC value to voltage in tenths, then add .2 for the diode drop */
+               query.battery = (packet->adc.batt + 96) / 192 + 2;
                cur = 0;
                if (pyro > VOLTS_TO_PYRO(10)) {
                        query.arm_status = AO_PAD_ARM_STATUS_ARMED;
                        cur |= AO_LED_ARMED;
-               } else if (pyro < VOLTS_TO_PYRO(5)) {
-                       query.arm_status = AO_PAD_ARM_STATUS_DISARMED;
-                       arm_beep_time = 0;
-               } else {
+#if AO_FIRE_R_POWER_FET
+               } else if (pyro > VOLTS_TO_PYRO(5)) {
                        if ((ao_time() % 100) < 50)
                                cur |= AO_LED_ARMED;
                        query.arm_status = AO_PAD_ARM_STATUS_UNKNOWN;
                        arm_beep_time = 0;
+#endif
+               } else {
+                       query.arm_status = AO_PAD_ARM_STATUS_DISARMED;
+                       arm_beep_time = 0;
                }
                if ((ao_time() - ao_pad_packet_time) > AO_SEC_TO_TICKS(2))
                        cur |= AO_LED_RED;
-               else if (ao_radio_cmac_rssi < -90)
+               else if (ao_radio_cmac_rssi < AO_PAD_RSSI_MINIMUM)
                        cur |= AO_LED_AMBER;
                else
                        cur |= AO_LED_GREEN;
@@ -159,22 +190,39 @@ ao_pad_monitor(void)
                         *      27k            /
                         *              gnd ---
                         *
+                        *              v_pyro \
+                        *      200k            igniter
+                        *              output /
+                        *      200k           \
+                        *              sense   relay
+                        *      22k            /
+                        *              gnd ---
+                        *
                         *      If the relay is closed, then sense will be 0
                         *      If no igniter is present, then sense will be v_pyro * 27k/227k = pyro * 127 / 227 ~= pyro/2
                         *      If igniter is present, then sense will be v_pyro * 27k/127k ~= v_pyro / 20 = pyro
                         */
 
+#if AO_FIRE_R_POWER_FET
                        if (sense <= pyro / 8) {
                                status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_CLOSED;
                                if ((ao_time() % 100) < 50)
                                        cur |= AO_LED_CONTINUITY(c);
-                       }
-                       else if (pyro / 8 * 3 <= sense && sense <= pyro / 8 * 5)
+                       } else
+                       if (pyro / 8 * 3 <= sense && sense <= pyro / 8 * 5)
                                status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN;
                        else if (pyro / 8 * 7 <= sense) {
                                status = AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN;
                                cur |= AO_LED_CONTINUITY(c);
                        }
+#else
+                       if (sense >= pyro / 8 * 5) {
+                               status = AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN;
+                               cur |= AO_LED_CONTINUITY(c);
+                       } else {
+                               status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN;
+                       }
+#endif
                        query.igniter_status[c] = status;
                }
                if (cur != prev) {
@@ -234,8 +282,14 @@ ao_pad_read_box(void)
        l = byte & 0xf;
        return h * 10 + l;
 }
-#else
-#define ao_pad_read_box()      0
+#endif
+
+#if HAS_FIXED_PAD_BOX
+#define ao_pad_read_box()      ao_config.pad_box
+#endif
+
+#ifdef PAD_BOX
+#define ao_pad_read_box()      PAD_BOX
 #endif
 
 static void
@@ -255,14 +309,14 @@ ao_pad(void)
                if (ret != AO_RADIO_CMAC_OK)
                        continue;
                ao_pad_packet_time = ao_time();
-               
+
                ao_pad_box = ao_pad_read_box();
 
                PRINTD ("tick %d box %d (me %d) cmd %d channels %02x\n",
                        command.tick, command.box, ao_pad_box, command.cmd, command.channels);
 
                switch (command.cmd) {
-               case AO_LAUNCH_ARM:
+               case AO_PAD_ARM:
                        if (command.box != ao_pad_box) {
                                PRINTD ("box number mismatch\n");
                                break;
@@ -282,10 +336,9 @@ ao_pad(void)
                        PRINTD ("armed\n");
                        ao_pad_armed = command.channels;
                        ao_pad_arm_time = ao_time();
+                       break;
 
-                       /* fall through ... */
-
-               case AO_LAUNCH_QUERY:
+               case AO_PAD_QUERY:
                        if (command.box != ao_pad_box) {
                                PRINTD ("box number mismatch\n");
                                break;
@@ -304,7 +357,7 @@ ao_pad(void)
                                query.igniter_status[3]);
                        ao_radio_cmac_send(&query, sizeof (query));
                        break;
-               case AO_LAUNCH_FIRE:
+               case AO_PAD_FIRE:
                        if (!ao_pad_armed) {
                                PRINTD ("not armed\n");
                                break;
@@ -314,11 +367,23 @@ ao_pad(void)
                                        ao_pad_arm_time, ao_time());
                                break;
                        }
-                       time_difference = command.tick - ao_time();
-                       if (time_difference < 0)
-                               time_difference = -time_difference;
-                       if (time_difference > 10) {
-                               PRINTD ("time different too large %d\n", time_difference);
+                       PRINTD ("ignite\n");
+                       ao_pad_ignite = ao_pad_armed;
+                       ao_pad_arm_time = ao_time();
+                       ao_wakeup(&ao_pad_ignite);
+                       break;
+               }
+               case AO_PAD_STATIC:
+                       if (!ao_pad_armed) {
+                               PRINTD ("not armed\n");
+                               break;
+                       }
+#ifdef HAS_LOG
+                       if (!ao_log_running) ao_log_start();
+#endif
+                       if ((uint16_t) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) {
+                               PRINTD ("late pad arm_time %d time %d\n",
+                                       ao_pad_arm_time, ao_time());
                                break;
                        }
                        PRINTD ("ignite\n");
@@ -327,6 +392,12 @@ ao_pad(void)
                        ao_wakeup(&ao_pad_ignite);
                        break;
                }
+               case AO_PAD_ENDSTATIC:
+#ifdef HAS_LOG
+                       ao_log_stop();
+#endif
+                       break;
+               }
        }
 }
 
@@ -362,14 +433,26 @@ ao_pad_test(void)
 void
 ao_pad_manual(void)
 {
+       uint8_t ignite;
+       int     repeat;
        ao_cmd_white();
        if (!ao_match_word("DoIt"))
                return;
        ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
-       ao_pad_ignite = 1 << ao_cmd_lex_i;
-       ao_wakeup(&ao_pad_ignite);
+       ignite = 1 << ao_cmd_lex_i;
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success) {
+               repeat = 1;
+               ao_cmd_status = ao_cmd_success;
+       } else
+               repeat = ao_cmd_lex_i;
+       while (repeat-- > 0) {
+               ao_pad_ignite = ignite;
+               ao_wakeup(&ao_pad_ignite);
+               ao_delay(AO_PAD_FIRE_TIME>>1);
+       }
 }
 
 static __xdata struct ao_task ao_pad_task;