*
* 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
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
#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
#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
}
{
#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)
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)
{
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;
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;
* 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) {
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
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;
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;
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;
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;
+ }
+#if 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");
ao_pad_arm_time = ao_time();
ao_wakeup(&ao_pad_ignite);
break;
+ case AO_PAD_ENDSTATIC:
+#if HAS_LOG
+ ao_log_stop();
+#endif
+ break;
}
}
}
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;