+ __pdata int16_t pyro;
+
+ ao_arch_critical(
+ while (sample == ao_data_head)
+ ao_sleep((void *) DATA_TO_XDATA(&ao_data_head));
+ );
+
+
+ packet = &ao_data_ring[sample];
+ sample = ao_data_ring_next(sample);
+
+ /* 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);
+
+ cur = 0;
+ if (pyro > query.battery * 7 / 8) {
+ query.arm_status = AO_PAD_ARM_STATUS_ARMED;
+ cur |= AO_LED_ARMED;
+ } 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 < AO_PAD_RSSI_MINIMUM)
+ cur |= AO_LED_AMBER;
+ else
+ cur |= AO_LED_GREEN;
+
+ for (c = 0; c < AO_PAD_NUM; 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;
+
+ /*
+ * Here's the resistor stack on each
+ * igniter channel. Note that
+ * AO_PAD_R_V_PYRO_IGNITER is optional
+ *
+ * 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 ---
+ *
+ */
+
+#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
+#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;