altos: Improve labeling of telefire receive packet information
[fw/altos] / src / drivers / ao_pad.c
index b0ec21617d177005da40eba90d9e6192ee1d590c..2592a084261bec25640f0820dfc018c579f44486 100644 (file)
 #include <ao_74hc165.h>
 #include <ao_radio_cmac.h>
 
-static __xdata uint8_t ao_pad_ignite;
-static __xdata struct ao_pad_command   command;
-static __xdata struct ao_pad_query     query;
-static __pdata uint8_t ao_pad_armed;
-static __pdata uint16_t        ao_pad_arm_time;
-static __pdata uint8_t ao_pad_box;
-static __xdata uint8_t ao_pad_disabled;
-static __pdata uint16_t        ao_pad_packet_time;
+static uint8_t ao_pad_ignite;
+static struct ao_pad_command   command;
+static struct ao_pad_query     query;
+static uint8_t ao_pad_armed;
+static uint16_t        ao_pad_arm_time;
+static uint8_t ao_pad_box;
+static uint8_t ao_pad_disabled;
+static uint16_t        ao_pad_packet_time;
 
 #ifndef AO_PAD_RSSI_MINIMUM
 #define AO_PAD_RSSI_MINIMUM    -90
@@ -38,7 +38,7 @@ static __pdata uint16_t       ao_pad_packet_time;
 #define DEBUG  1
 
 #if DEBUG
-static __pdata uint8_t ao_pad_debug;
+static uint8_t ao_pad_debug;
 #define PRINTD(...) (ao_pad_debug ? (printf(__VA_ARGS__), 0) : 0)
 #define FLUSHD()    (ao_pad_debug ? (flush(), 0) : 0)
 #else
@@ -50,7 +50,7 @@ static void
 ao_siren(uint8_t v)
 {
 #ifdef AO_SIREN
-       ao_gpio_set(AO_SIREN_PORT, AO_SIREN_PIN, AO_SIREN, v);
+       ao_gpio_set(AO_SIREN_PORT, AO_SIREN_PIN, v);
 #else
 #if HAS_BEEP
        ao_beep(v ? AO_BEEP_MID : 0);
@@ -64,7 +64,7 @@ static void
 ao_strobe(uint8_t v)
 {
 #ifdef AO_STROBE
-       ao_gpio_set(AO_STROBE_PORT, AO_STROBE_PIN, AO_STROBE, v);
+       ao_gpio_set(AO_STROBE_PORT, AO_STROBE_PIN, v);
 #else
        (void) v;
 #endif
@@ -153,58 +153,75 @@ ao_pad_run(void)
 
 #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
+/* Resistor values needed for various voltage test ratios:
+ *
+ *     Net names involved:
+ *
+ *     V_BATT          Battery power, after the initial power switch
+ *     V_PYRO          Pyro power, after the pyro power switch (and initial power switch)
+ *     PYRO_SENSE      ADC input to sense V_PYRO voltage
+ *     BATT_SENSE      ADC input to sense V_BATT voltage
+ *     IGNITER         FET output to pad (the other pad lead hooks to V_PYRO)
+ *     IGNITER_SENSE   ADC input to sense igniter voltage
+ *
+ *     AO_PAD_R_V_BATT_BATT_SENSE      Resistor from battery rail to battery sense input
+ *     AO_PAD_R_BATT_SENSE_GND         Resistor from battery sense input to ground
+ *
+ *     AO_PAD_R_V_BATT_V_PYRO          Resistor from battery rail to pyro rail
+ *     AO_PAD_R_V_PYRO_PYRO_SENSE      Resistor from pyro rail to pyro sense input
+ *     AO_PAD_R_PYRO_SENSE_GND         Resistor from pyro sense input to ground
+ *
+ *     AO_PAD_R_V_PYRO_IGNITER         Optional resistors from pyro rail to FET igniter output
+ *     AO_PAD_R_IGNITER_IGNITER_SENSE  Resistors from FET igniter output to igniter sense ADC inputs
+ *     AO_PAD_R_IGNITER_SENSE_GND      Resistors from igniter sense ADC inputs to ground
+ */
+
+static int16_t
+ao_pad_decivolt(int16_t adc, int16_t r_plus, int16_t r_minus)
+{
+       int32_t mul = (int32_t) AO_ADC_REFERENCE_DV * (r_plus + r_minus);
+       int32_t div = (int32_t) AO_ADC_MAX * r_minus;
+       return ((int32_t) adc * mul + mul/2) / div;
+}
 
 static void
 ao_pad_monitor(void)
 {
        uint8_t                 c;
        uint8_t                 sample;
-       __pdata uint8_t         prev = 0, cur = 0;
-       __pdata uint8_t         beeping = 0;
-       __xdata volatile struct ao_data *packet;
-       __pdata uint16_t        arm_beep_time = 0;
+       AO_LED_TYPE     prev = 0, cur = 0;
+       uint8_t         beeping = 0;
+       volatile struct ao_data *packet;
+       uint16_t        arm_beep_time = 0;
 
        sample = ao_data_head;
+       ao_led_set(LEDS_AVAILABLE);
+       ao_delay(AO_MS_TO_TICKS(1000));
+       ao_led_set(0);
        for (;;) {
-               __pdata int16_t                 pyro;
+               int16_t                 pyro;
+
                ao_arch_critical(
                        while (sample == ao_data_head)
-                               ao_sleep((void *) DATA_TO_XDATA(&ao_data_head));
+                               ao_sleep((void *) &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) * ((1.0 * AO_PYRO_R_SENSE_GND) / \
-                                           (1.0 * (AO_PYRO_R_SENSE_GND + AO_PYRO_R_PYRO_SENSE)) / 3.3 * AO_ADC_MAX)))
+               /* Reply battery voltage */
+               query.battery = ao_pad_decivolt(packet->adc.batt, AO_PAD_R_V_BATT_BATT_SENSE, AO_PAD_R_BATT_SENSE_GND);
 
+               /* Current pyro voltage */
+               pyro = ao_pad_decivolt(packet->adc.pyro,
+                                      AO_PAD_R_V_PYRO_PYRO_SENSE,
+                                      AO_PAD_R_PYRO_SENSE_GND);
 
-#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)) {
+               if (pyro > query.battery * 7 / 8) {
                        query.arm_status = AO_PAD_ARM_STATUS_ARMED;
                        cur |= AO_LED_ARMED;
-#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;
@@ -217,54 +234,50 @@ ao_pad_monitor(void)
                        cur |= AO_LED_GREEN;
 
                for (c = 0; c < AO_PAD_NUM; c++) {
-                       int16_t         sense = packet->adc.sense[c];
+                       int16_t         sense = ao_pad_decivolt(packet->adc.sense[c],
+                                                               AO_PAD_R_IGNITER_IGNITER_SENSE,
+                                                               AO_PAD_R_IGNITER_SENSE_GND);
                        uint8_t status = AO_PAD_IGNITER_STATUS_UNKNOWN;
 
                        /*
-                        *      pyro is run through a divider, so pyro = v_pyro * 27 / 127 ~= v_pyro / 20
-                        *      v_pyro = pyro * 127 / 27
-                        *
-                        *              v_pyro \
-                        *      100k            igniter
-                        *              output /
-                        *      100k           \
-                        *              sense   relay
-                        *      27k            /
-                        *              gnd ---
+                        *      Here's the resistor stack on each
+                        *      igniter channel. Note that
+                        *      AO_PAD_R_V_PYRO_IGNITER is optional
                         *
-                        *              v_pyro \
-                        *      200k            igniter
-                        *              output /
-                        *      200k           \
-                        *              sense   relay
-                        *      22k            /
-                        *              gnd ---
+                        *                                      v_pyro \
+                        *      AO_PAD_R_V_PYRO_IGNITER                 igniter
+                        *                                      output /
+                        *      AO_PAD_R_IGNITER_IGNITER_SENSE         \
+                        *                                      sense   relay
+                        *      AO_PAD_R_IGNITER_SENSE_GND             /
+                        *                                      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
+#ifdef AO_PAD_R_V_PYRO_IGNITER
                        if (sense <= pyro / 8) {
+                               /* close to zero → relay is closed */
                                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)
-                               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;
                        }
+                       else
 #endif
+                       {
+                               if (sense >= (pyro * 7) / 8) {
+
+                                       /* sense close to pyro voltage; igniter is good
+                                        */
+                                       status = AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN;
+                                       cur |= AO_LED_CONTINUITY(c);
+                               } else {
+
+                                       /* relay not shorted (if we can tell),
+                                        * and igniter not obviously present
+                                        */
+                                       status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN;
+                               }
+                       }
                        query.igniter_status[c] = status;
                }
                if (cur != prev) {
@@ -360,13 +373,12 @@ ao_pad(void)
        int8_t  ret;
 
        ao_pad_box = 0;
-       ao_led_set(0);
        for (;;) {
                FLUSHD();
                while (ao_pad_disabled)
                        ao_sleep(&ao_pad_disabled);
                ret = ao_radio_cmac_recv(&command, sizeof (command), 0);
-               PRINTD ("cmac_recv %d %d\n", ret, ao_radio_cmac_rssi);
+               PRINTD ("receive packet status %d rssi %d\n", ret, ao_radio_cmac_rssi);
                if (ret != AO_RADIO_CMAC_OK)
                        continue;
                ao_pad_packet_time = ao_time();
@@ -394,6 +406,10 @@ ao_pad(void)
                                PRINTD ("time difference too large %d\n", time_difference);
                                break;
                        }
+                       if (query.arm_status != AO_PAD_ARM_STATUS_ARMED) {
+                               PRINTD ("box not armed locally\n");
+                               break;
+                       }
                        PRINTD ("armed\n");
                        ao_pad_armed = command.channels;
                        ao_pad_arm_time = ao_time();
@@ -460,7 +476,7 @@ ao_pad(void)
        }
 }
 
-void
+static void
 ao_pad_test(void)
 {
        uint8_t c;
@@ -489,7 +505,7 @@ ao_pad_test(void)
        }
 }
 
-void
+static void
 ao_pad_manual(void)
 {
        uint8_t ignite;
@@ -497,16 +513,14 @@ ao_pad_manual(void)
        ao_cmd_white();
        if (!ao_match_word("DoIt"))
                return;
-       ao_cmd_decimal();
+       ignite = 1 << ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
-       ignite = 1 << ao_cmd_lex_i;
-       ao_cmd_decimal();
+       repeat = 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);
@@ -514,17 +528,17 @@ ao_pad_manual(void)
        }
 }
 
-static __xdata struct ao_task ao_pad_task;
-static __xdata struct ao_task ao_pad_ignite_task;
-static __xdata struct ao_task ao_pad_monitor_task;
+static struct ao_task ao_pad_task;
+static struct ao_task ao_pad_ignite_task;
+static struct ao_task ao_pad_monitor_task;
 
 #if DEBUG
-void
+static void
 ao_pad_set_debug(void)
 {
-       ao_cmd_decimal();
+       uint16_t r = ao_cmd_decimal();
        if (ao_cmd_status == ao_cmd_success)
-               ao_pad_debug = ao_cmd_lex_i != 0;
+               ao_pad_debug = r != 0;
 }
 
 
@@ -532,14 +546,12 @@ static void
 ao_pad_alarm_debug(void)
 {
        uint8_t which, value;
-       ao_cmd_decimal();
+       which = ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
-       which = ao_cmd_lex_i;
-       ao_cmd_decimal();
+       value = ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
-       value = ao_cmd_lex_i;
        printf ("Set %s to %d\n", which ? "siren" : "strobe", value);
        if (which)
                ao_siren(value);
@@ -548,7 +560,7 @@ ao_pad_alarm_debug(void)
 }
 #endif
 
-__code struct ao_cmds ao_pad_cmds[] = {
+const struct ao_cmds ao_pad_cmds[] = {
        { ao_pad_test,  "t\0Test pad continuity" },
        { ao_pad_manual,        "i <key> <n>\0Fire igniter. <key> is doit with D&I" },
 #if DEBUG
@@ -581,34 +593,34 @@ ao_pad_init(void)
        }
 #endif
 #if AO_PAD_NUM > 0
-       ao_enable_output(AO_PAD_0_PORT, AO_PAD_PIN_0, AO_PAD_0, 0);
+       ao_enable_output(AO_PAD_0_PORT, AO_PAD_PIN_0, 0);
 #endif
 #if AO_PAD_NUM > 1
-       ao_enable_output(AO_PAD_1_PORT, AO_PAD_PIN_1, AO_PAD_1, 0);
+       ao_enable_output(AO_PAD_1_PORT, AO_PAD_PIN_1, 0);
 #endif
 #if AO_PAD_NUM > 2
-       ao_enable_output(AO_PAD_2_PORT, AO_PAD_PIN_2, AO_PAD_2, 0);
+       ao_enable_output(AO_PAD_2_PORT, AO_PAD_PIN_2, 0);
 #endif
 #if AO_PAD_NUM > 3
-       ao_enable_output(AO_PAD_3_PORT, AO_PAD_PIN_3, AO_PAD_3, 0);
+       ao_enable_output(AO_PAD_3_PORT, AO_PAD_PIN_3, 0);
 #endif
 #if AO_PAD_NUM > 4
-       ao_enable_output(AO_PAD_4_PORT, AO_PAD_PIN_4, AO_PAD_4, 0);
+       ao_enable_output(AO_PAD_4_PORT, AO_PAD_PIN_4, 0);
 #endif
 #if AO_PAD_NUM > 5
-       ao_enable_output(AO_PAD_5_PORT, AO_PAD_PIN_5, AO_PAD_5, 0);
+       ao_enable_output(AO_PAD_5_PORT, AO_PAD_PIN_5, 0);
 #endif
 #if AO_PAD_NUM > 5
-       ao_enable_output(AO_PAD_6_PORT, AO_PAD_PIN_6, AO_PAD_6, 0);
+       ao_enable_output(AO_PAD_6_PORT, AO_PAD_PIN_6, 0);
 #endif
 #if AO_PAD_NUM > 7
-       ao_enable_output(AO_PAD_7_PORT, AO_PAD_PIN_7, AO_PAD_7, 0);
+       ao_enable_output(AO_PAD_7_PORT, AO_PAD_PIN_7, 0);
 #endif
 #ifdef AO_STROBE
-       ao_enable_output(AO_STROBE_PORT, AO_STROBE_PIN, AO_STROBE, 0);
+       ao_enable_output(AO_STROBE_PORT, AO_STROBE_PIN, 0);
 #endif
 #ifdef AO_SIREN
-       ao_enable_output(AO_SIREN_PORT, AO_SIREN_PIN, AO_SIREN, 0);
+       ao_enable_output(AO_SIREN_PORT, AO_SIREN_PIN, 0);
 #endif
        ao_cmd_register(&ao_pad_cmds[0]);
        ao_add_task(&ao_pad_task, ao_pad, "pad listener");