diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/drivers/ao_lco.c | 517 | ||||
| -rw-r--r-- | src/drivers/ao_lco.h | 116 | ||||
| -rw-r--r-- | src/drivers/ao_lco_bits.c | 468 | ||||
| -rw-r--r-- | src/telelco-v0.2-cc1200/Makefile | 1 | ||||
| -rw-r--r-- | src/telelco-v0.2/Makefile | 1 | ||||
| -rw-r--r-- | src/telelco-v0.3/Makefile | 1 | ||||
| -rw-r--r-- | src/telelco-v2.0/Makefile | 1 | ||||
| -rw-r--r-- | src/telelco-v2.0/ao_lco_v2.c | 475 | 
8 files changed, 679 insertions, 901 deletions
| diff --git a/src/drivers/ao_lco.c b/src/drivers/ao_lco.c index 91a0593f..6b270042 100644 --- a/src/drivers/ao_lco.c +++ b/src/drivers/ao_lco.c @@ -27,15 +27,6 @@  #include <ao_adc_single.h>  #endif -#define DEBUG	1 - -#if DEBUG -static uint8_t	ao_lco_debug; -#define PRINTD(...) do { if (!ao_lco_debug) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) -#else -#define PRINTD(...)  -#endif -  #define AO_LCO_PAD_DIGIT	0  #define AO_LCO_BOX_DIGIT_1	1  #define AO_LCO_BOX_DIGIT_10	2 @@ -46,28 +37,15 @@ static uint8_t	ao_lco_debug;  #define AO_LCO_VALID_LAST	1  #define AO_LCO_VALID_EVER	2 -static uint8_t	ao_lco_min_box, ao_lco_max_box; -static uint8_t	ao_lco_selected[AO_PAD_MAX_BOXES]; -static uint8_t	ao_lco_valid[AO_PAD_MAX_BOXES]; -static uint8_t	ao_lco_channels[AO_PAD_MAX_BOXES]; -static uint16_t	ao_lco_tick_offset[AO_PAD_MAX_BOXES]; -  /* UI values */ -static uint8_t	ao_lco_armed; -static uint8_t	ao_lco_firing;  static uint16_t	ao_lco_fire_tick;  static uint8_t	ao_lco_fire_down; -static uint8_t	ao_lco_drag_race; -static uint8_t	ao_lco_pad; -static int16_t	ao_lco_box;  #define AO_LCO_BOX_DRAG		0x1000 -static struct ao_pad_query	ao_pad_query; -  static uint8_t	ao_lco_display_mutex; -static void +void  ao_lco_set_pad(uint8_t pad)  {  	ao_mutex_get(&ao_lco_display_mutex); @@ -92,7 +70,7 @@ ao_lco_set_pad(uint8_t pad)  				 (0 << 5) |	\  				 (0 << 6)) -static void +void  ao_lco_set_box(uint16_t box)  {  	ao_mutex_get(&ao_lco_display_mutex); @@ -106,7 +84,7 @@ ao_lco_set_box(uint16_t box)  	ao_mutex_put(&ao_lco_display_mutex);  } -static void +void  ao_lco_set_voltage(uint16_t decivolts)  {  	uint8_t	tens, ones, tenths; @@ -121,7 +99,7 @@ ao_lco_set_voltage(uint16_t decivolts)  	ao_mutex_put(&ao_lco_display_mutex);  } -static void +void  ao_lco_set_display(void)  {  	if (ao_lco_pad == 0 && ao_lco_box != AO_LCO_BOX_DRAG) { @@ -135,13 +113,7 @@ ao_lco_set_display(void)  	}  } -#define MASK_SIZE(n)	(((n) + 7) >> 3) -#define MASK_ID(n)	((n) >> 3) -#define MASK_SHIFT(n)	((n) & 7) - -static uint8_t	ao_lco_box_mask[MASK_SIZE(AO_PAD_MAX_BOXES)]; - -static uint8_t +uint8_t  ao_lco_box_present(uint16_t box)  {  	if (box == AO_LCO_BOX_DRAG) @@ -149,117 +121,11 @@ ao_lco_box_present(uint16_t box)  	if (box >= AO_PAD_MAX_BOXES)  		return 0; -	return (ao_lco_box_mask[MASK_ID(box)] >> MASK_SHIFT(box)) & 1; -} - -static uint8_t -ao_lco_pad_present(uint8_t box, uint8_t pad) -{ -	/* voltage measurement is always valid */ -	if (pad == 0) -		return 1; -	if (!ao_lco_channels[box]) -		return 0; -	if (pad > AO_PAD_MAX_CHANNELS) -		return 0; -	return (ao_lco_channels[box] >> (pad - 1)) & 1; -} - -static uint8_t -ao_lco_pad_first(uint8_t box) -{ -	uint8_t	pad; - -	for (pad = 1; pad <= AO_PAD_MAX_CHANNELS; pad++) -		if (ao_lco_pad_present(box, pad)) -			return pad; -	return 0; +	return (ao_lco_box_mask[AO_LCO_MASK_ID(box)] >> AO_LCO_MASK_SHIFT(box)) & 1;  }  static struct ao_task	ao_lco_drag_task;  static uint8_t		ao_lco_drag_active; -static uint8_t		ao_lco_drag_beep_count; -static uint8_t		ao_lco_drag_beep_on; -static uint16_t		ao_lco_drag_beep_time; -static uint16_t		ao_lco_drag_warn_time; - -#define AO_LCO_DRAG_BEEP_TIME	AO_MS_TO_TICKS(50) -#define AO_LCO_DRAG_WARN_TIME	AO_SEC_TO_TICKS(5) - -static void -ao_lco_drag_beep_start(void) -{ -	ao_beep(AO_BEEP_HIGH); -	PRINTD("beep start\n"); -	ao_lco_drag_beep_on = 1; -	ao_lco_drag_beep_time = ao_time() + AO_LCO_DRAG_BEEP_TIME; -} - -static void -ao_lco_drag_beep_stop(void) -{ -	ao_beep(0); -	PRINTD("beep stop\n"); -	ao_lco_drag_beep_on = 0; -	if (ao_lco_drag_beep_count) { -		--ao_lco_drag_beep_count; -		if (ao_lco_drag_beep_count) -			ao_lco_drag_beep_time = ao_time() + AO_LCO_DRAG_BEEP_TIME; -	} -} - -static void -ao_lco_drag_beep(uint8_t beeps) -{ -	PRINTD("beep %d\n", beeps); -	if (!ao_lco_drag_beep_count) -		ao_lco_drag_beep_start(); -	ao_lco_drag_beep_count += beeps; -} - -static uint16_t -ao_lco_drag_beep_check(uint16_t now, uint16_t delay) -{ -	PRINTD("beep check count %d delta %d\n", -	       ao_lco_drag_beep_count, -	       (int16_t) (now - ao_lco_drag_beep_time)); -	if (ao_lco_drag_beep_count) { -		if ((int16_t) (now - ao_lco_drag_beep_time) >= 0) { -			if (ao_lco_drag_beep_on) -				ao_lco_drag_beep_stop(); -			else -				ao_lco_drag_beep_start(); -		} -	} - -	if (ao_lco_drag_beep_count) { -		if (delay > AO_LCO_DRAG_BEEP_TIME) -			delay = AO_LCO_DRAG_BEEP_TIME; -	} -	return delay; -} - -static void -ao_lco_drag_enable(void) -{ -	PRINTD("Drag enable\n"); -	ao_lco_drag_race = 1; -	memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -	ao_lco_drag_beep(5); -	ao_lco_set_display(); -	ao_lco_fire_down = 0; -} - -static void -ao_lco_drag_disable(void) -{ -	PRINTD("Drag disable\n"); -	ao_lco_drag_race = 0; -	memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -	ao_lco_drag_beep(2); -	ao_lco_set_display(); -	ao_lco_fire_down = 0; -}  static uint16_t  ao_lco_drag_button_check(uint16_t now, uint16_t delay) @@ -272,13 +138,17 @@ ao_lco_drag_button_check(uint16_t now, uint16_t delay)  	 */  	if (ao_lco_fire_down) {  		if (ao_lco_drag_race) { -			if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_STOP_TIME) +			if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_STOP_TIME) {  				ao_lco_drag_disable(); +				ao_lco_fire_down = 0; +			}  			else  				button_delay = ao_lco_fire_tick + AO_LCO_DRAG_RACE_STOP_TIME - now;  		} else { -			if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_START_TIME) +			if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_START_TIME) {  				ao_lco_drag_enable(); +				ao_lco_fire_down = 0; +			}  			else  				button_delay = ao_lco_fire_tick + AO_LCO_DRAG_RACE_START_TIME - now;  		} @@ -288,35 +158,20 @@ ao_lco_drag_button_check(uint16_t now, uint16_t delay)  	return delay;  } -static uint16_t -ao_lco_drag_warn_check(uint16_t now, uint16_t delay) -{ -	uint16_t	warn_delay = ~0; - -	if (ao_lco_drag_race) { -		if ((int16_t) (now - ao_lco_drag_warn_time) >= 0) { -			ao_lco_drag_beep(1); -			ao_lco_drag_warn_time = now + AO_LCO_DRAG_WARN_TIME; -		} -		warn_delay = ao_lco_drag_warn_time - now; -	} -	if (delay > warn_delay) -		delay = warn_delay; -	return delay; -} -  static void  ao_lco_drag_monitor(void)  {  	uint16_t	delay = ~0;  	uint16_t	now; +	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));  	for (;;) { -		PRINTD("Drag monitor active %d delay %d\n", ao_lco_drag_active, delay); +		PRINTD("Drag monitor count %d active %d delay %d\n", +		       ao_lco_drag_beep_count, ao_lco_drag_active, delay);  		if (delay == (uint16_t) ~0) -			ao_sleep(&ao_lco_drag_active); +			ao_sleep(&ao_lco_drag_beep_count);  		else -			ao_sleep_for(&ao_lco_drag_active, delay); +			ao_sleep_for(&ao_lco_drag_beep_count, delay);  		delay = ~0;  		if (!ao_lco_drag_active) @@ -336,13 +191,39 @@ ao_lco_drag_monitor(void)  }  static void +ao_lco_step_box(int8_t dir) +{ +	int16_t new_box = ao_lco_box; +	do { +		if (new_box == AO_LCO_BOX_DRAG) { +			if (dir < 0) +				new_box = ao_lco_max_box; +			else +				new_box = ao_lco_min_box; +		} else { +			new_box += dir; +			if (new_box > ao_lco_max_box) +				new_box = AO_LCO_BOX_DRAG; +			else if (new_box < ao_lco_min_box) +				new_box = AO_LCO_BOX_DRAG; +		} +		if (new_box == ao_lco_box) +			break; +	} while (!ao_lco_box_present(new_box)); +	if (ao_lco_box != new_box) { +		ao_lco_box = new_box; +		ao_lco_pad = 1; +		if (ao_lco_box != AO_LCO_BOX_DRAG) +			ao_lco_channels[ao_lco_box] = 0; +		ao_lco_set_display(); +	} +} + +static void  ao_lco_input(void)  {  	static struct ao_event	event; -	int8_t		dir, new_pad; -	int16_t		new_box; -	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));  	for (;;) {  		ao_event_get(&event);  		PRINTD("event type %d unit %d value %d\n", @@ -351,106 +232,38 @@ ao_lco_input(void)  		case AO_EVENT_QUADRATURE:  			switch (event.unit) {  			case AO_QUADRATURE_PAD: -				if (!ao_lco_armed) { -					dir = (int8_t) event.value; -					new_pad = ao_lco_pad; -					do { -						new_pad += dir; -						if (new_pad > AO_PAD_MAX_CHANNELS) -							new_pad = 0; -						if (new_pad < 0) -							new_pad = AO_PAD_MAX_CHANNELS; -						if (new_pad == ao_lco_pad) -							break; -					} while (!ao_lco_pad_present(ao_lco_box, new_pad)); -					if (new_pad != ao_lco_pad) { -						ao_lco_pad = new_pad; -						ao_lco_set_display(); -					} -				} +				if (!ao_lco_armed) +					ao_lco_step_pad((int8_t) event.value);  				break;  			case AO_QUADRATURE_BOX: -				if (!ao_lco_armed) { -					dir = (int8_t) event.value; -					new_box = ao_lco_box; -					do { -						if (new_box == AO_LCO_BOX_DRAG) { -							if (dir < 0) -								new_box = ao_lco_max_box; -							else -								new_box = ao_lco_min_box; -						} else { -							new_box += dir; -							if (new_box > ao_lco_max_box) -								new_box = AO_LCO_BOX_DRAG; -							else if (new_box < ao_lco_min_box) -								new_box = AO_LCO_BOX_DRAG; -						} -						if (new_box == ao_lco_box) -							break; -					} while (!ao_lco_box_present(new_box)); -					if (ao_lco_box != new_box) { -						ao_lco_box = new_box; -						ao_lco_pad = 1; -						if (ao_lco_box != AO_LCO_BOX_DRAG) -							ao_lco_channels[ao_lco_box] = 0; -						ao_lco_set_display(); -					} -				} +				if (!ao_lco_armed) +					ao_lco_step_box((int8_t) event.value);  				break;  			}  			break;  		case AO_EVENT_BUTTON:  			switch (event.unit) {  			case AO_BUTTON_ARM: -				ao_lco_armed = event.value; -				PRINTD("Armed %d\n", ao_lco_armed); -				if (ao_lco_armed) { -					if (ao_lco_drag_race) { -						uint8_t	box; - -						for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) { -							if (ao_lco_selected[box]) { -								ao_wakeup(&ao_lco_armed); -								break; -							} -						} -					} else { -						memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -						if (ao_lco_pad != 0 && ao_lco_box != AO_LCO_BOX_DRAG) -							ao_lco_selected[ao_lco_box] = (1 << (ao_lco_pad - 1)); -						else -							ao_lco_armed = 0; -					} -				} -				ao_wakeup(&ao_lco_armed); +				ao_lco_set_armed(event.value);  				break;  			case AO_BUTTON_FIRE:  				if (ao_lco_armed) {  					ao_lco_fire_down = 0; -					ao_lco_firing = event.value; -					PRINTD("Firing %d\n", ao_lco_firing); -					ao_wakeup(&ao_lco_armed); +					ao_lco_set_firing(event.value);  				} else {  					if (event.value) {  						if (ao_lco_box == AO_LCO_BOX_DRAG) {  							ao_lco_fire_down = 1;  							ao_lco_fire_tick = ao_time();  							ao_lco_drag_active = 1; +							ao_wakeup(&ao_lco_drag_beep_count); +						} else { +							ao_lco_toggle_drag();  						} -						if (ao_lco_drag_race) { -							if (ao_lco_pad != 0 && ao_lco_box != AO_LCO_BOX_DRAG) { -								ao_lco_selected[ao_lco_box] ^= (1 << (ao_lco_pad - 1)); -								PRINTD("Toggle box %d pad %d (pads now %x) to drag race\n", -								       ao_lco_pad, ao_lco_box, ao_lco_selected[ao_lco_box]); -								ao_lco_drag_beep(ao_lco_pad); -							} -						} -						ao_wakeup(&ao_lco_drag_active);  					} else {  						ao_lco_fire_down = 0;  						if (ao_lco_drag_active) -							ao_wakeup(&ao_lco_drag_active); +							ao_wakeup(&ao_lco_drag_beep_count);  					}  				}  				break; @@ -460,189 +273,6 @@ ao_lco_input(void)  	}  } -static AO_LED_TYPE	continuity_led[AO_LED_CONTINUITY_NUM] = { -#ifdef AO_LED_CONTINUITY_0 -	AO_LED_CONTINUITY_0, -#endif -#ifdef AO_LED_CONTINUITY_1 -	AO_LED_CONTINUITY_1, -#endif -#ifdef AO_LED_CONTINUITY_2 -	AO_LED_CONTINUITY_2, -#endif -#ifdef AO_LED_CONTINUITY_3 -	AO_LED_CONTINUITY_3, -#endif -#ifdef AO_LED_CONTINUITY_4 -	AO_LED_CONTINUITY_4, -#endif -#ifdef AO_LED_CONTINUITY_5 -	AO_LED_CONTINUITY_5, -#endif -#ifdef AO_LED_CONTINUITY_6 -	AO_LED_CONTINUITY_6, -#endif -#ifdef AO_LED_CONTINUITY_7 -	AO_LED_CONTINUITY_7, -#endif -}; - -static uint8_t -ao_lco_get_channels(uint8_t box, struct ao_pad_query *query) -{ -	int8_t			r; - -	r = ao_lco_query(box, query, &ao_lco_tick_offset[box]); -	if (r == AO_RADIO_CMAC_OK) { -		ao_lco_channels[box] = query->channels; -		ao_lco_valid[box] = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER; -	} else -		ao_lco_valid[box] &= ~AO_LCO_VALID_LAST; -	PRINTD("ao_lco_get_channels(%d) rssi %d valid %d ret %d offset %d\n", box, ao_radio_cmac_rssi, ao_lco_valid[box], r, ao_lco_tick_offset[box]); -	ao_wakeup(&ao_pad_query); -	return ao_lco_valid[box]; -} - -static void -ao_lco_update(void) -{ -	if (ao_lco_box != AO_LCO_BOX_DRAG) { -		uint8_t	previous_valid = ao_lco_valid[ao_lco_box]; - -		if (ao_lco_get_channels(ao_lco_box, &ao_pad_query) & AO_LCO_VALID_LAST) { -			if (!(previous_valid & AO_LCO_VALID_EVER)) { -				if (ao_lco_pad != 0) -					ao_lco_pad = ao_lco_pad_first(ao_lco_box); -				ao_lco_set_display(); -			} -			if (ao_lco_pad == 0) -				ao_lco_set_display(); -		} -	} -} - -static void -ao_lco_box_reset_present(void) -{ -	ao_lco_min_box = 0xff; -	ao_lco_max_box = 0x00; -	memset(ao_lco_box_mask, 0, sizeof (ao_lco_box_mask)); -} - -static void -ao_lco_box_set_present(uint8_t box) -{ -	if (box < ao_lco_min_box) -		ao_lco_min_box = box; -	if (box > ao_lco_max_box) -		ao_lco_max_box = box; -	if (box >= AO_PAD_MAX_BOXES) -		return; -	ao_lco_box_mask[MASK_ID(box)] |= 1 << MASK_SHIFT(box); -} - -static void -ao_lco_search(void) -{ -	int8_t		r; -	int8_t		try; -	uint8_t		box; -	uint8_t		boxes = 0; - -	ao_lco_box_reset_present(); -	ao_lco_set_pad(0); -	for (box = 0; box < AO_PAD_MAX_BOXES; box++) { -		if ((box % 10) == 0) -			ao_lco_set_box(box); -		for (try = 0; try < 3; try++) { -			ao_lco_tick_offset[box] = 0; -			r = ao_lco_query(box, &ao_pad_query, &ao_lco_tick_offset[box]); -			PRINTD("box %d result %d offset %d\n", box, r, ao_lco_tick_offset[box]); -			if (r == AO_RADIO_CMAC_OK) { -				++boxes; -				ao_lco_box_set_present(box); -				ao_lco_set_pad(boxes % 10); -				ao_delay(AO_MS_TO_TICKS(30)); -				break; -			} -		} -	} -	if (ao_lco_min_box <= ao_lco_max_box) -		ao_lco_box = ao_lco_min_box; -	else -		ao_lco_min_box = ao_lco_max_box = ao_lco_box = 0; -	memset(ao_lco_valid, 0, sizeof (ao_lco_valid)); -	memset(ao_lco_channels, 0, sizeof (ao_lco_channels)); -	ao_lco_pad = 1; -	ao_lco_set_display(); -} - -static void -ao_lco_igniter_status(void) -{ -	uint8_t		c; -	uint8_t		t = 0; - -	for (;;) { -		ao_sleep(&ao_pad_query); -		PRINTD("RSSI %d VALID %d\n", ao_radio_cmac_rssi, ao_lco_box == AO_LCO_BOX_DRAG ? -1 : ao_lco_valid[ao_lco_box]); -		if (ao_lco_box == AO_LCO_BOX_DRAG) { -			ao_led_off(AO_LED_RED|AO_LED_GREEN|AO_LED_AMBER); -			for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) -				ao_led_off(continuity_led[c]); -		} else { -			if (!(ao_lco_valid[ao_lco_box] & AO_LCO_VALID_LAST)) { -				ao_led_on(AO_LED_RED); -				ao_led_off(AO_LED_GREEN|AO_LED_AMBER); -				continue; -			} -			if (ao_radio_cmac_rssi < -90) { -				ao_led_on(AO_LED_AMBER); -				ao_led_off(AO_LED_RED|AO_LED_GREEN); -			} else { -				ao_led_on(AO_LED_GREEN); -				ao_led_off(AO_LED_RED|AO_LED_AMBER); -			} -			if (ao_pad_query.arm_status) -				ao_led_on(AO_LED_REMOTE_ARM); -			else -				ao_led_off(AO_LED_REMOTE_ARM); - -			for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) { -				uint8_t	status; - -				if (ao_lco_drag_race) { -					if (ao_lco_selected[ao_lco_box] & (1 << c) && t) -						ao_led_on(continuity_led[c]); -					else -						ao_led_off(continuity_led[c]); -				} else { -					if (ao_pad_query.channels & (1 << c)) -						status = ao_pad_query.igniter_status[c]; -					else -						status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN; -					if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) -						ao_led_on(continuity_led[c]); -					else -						ao_led_off(continuity_led[c]); -				} -			} -			t = 1-t; -		} -	} -} - -static void -ao_lco_arm_warn(void) -{ -	for (;;) { -		while (!ao_lco_armed) -			ao_sleep(&ao_lco_armed); -		ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); -		ao_delay(AO_MS_TO_TICKS(200)); -	} -} -  /*   * Light up everything for a second at power on to let the user   * visually inspect the system for correct operation @@ -680,11 +310,8 @@ static struct ao_task ao_lco_arm_warn_task;  static struct ao_task ao_lco_igniter_status_task;  static void -ao_lco_monitor(void) +ao_lco_main(void)  { -	uint16_t		delay; -	uint8_t			box; -  	ao_lco_display_test();  #if HAS_ADC_SINGLE  	ao_lco_batt_voltage(); @@ -694,33 +321,7 @@ ao_lco_monitor(void)  	ao_add_task(&ao_lco_arm_warn_task, ao_lco_arm_warn, "lco arm warn");  	ao_add_task(&ao_lco_igniter_status_task, ao_lco_igniter_status, "lco igniter status");  	ao_add_task(&ao_lco_drag_task, ao_lco_drag_monitor, "drag race"); -	for (;;) { -		PRINTD("monitor armed %d firing %d\n", -		       ao_lco_armed, ao_lco_firing); - -		if (ao_lco_armed && ao_lco_firing) { -			ao_lco_ignite(AO_PAD_FIRE); -		} else { -			ao_lco_update(); -			if (ao_lco_armed) { -				for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) { -					if (ao_lco_selected[box]) { -						PRINTD("Arming box %d pads %x\n", -						       box, ao_lco_selected[box]); -						if (ao_lco_valid[box] & AO_LCO_VALID_EVER) { -							ao_lco_arm(box, ao_lco_selected[box], ao_lco_tick_offset[box]); -							ao_delay(AO_MS_TO_TICKS(10)); -						} -					} -				} -			} -		} -		if (ao_lco_armed && ao_lco_firing) -			delay = AO_MS_TO_TICKS(100); -		else -			delay = AO_SEC_TO_TICKS(1); -		ao_sleep_for(&ao_lco_armed, delay); -	} +	ao_lco_monitor();  }  #if DEBUG @@ -742,7 +343,7 @@ __code struct ao_cmds ao_lco_cmds[] = {  void  ao_lco_init(void)  { -	ao_add_task(&ao_lco_monitor_task, ao_lco_monitor, "lco monitor"); +	ao_add_task(&ao_lco_monitor_task, ao_lco_main, "lco monitor");  #if DEBUG  	ao_cmd_register(&ao_lco_cmds[0]);  #endif diff --git a/src/drivers/ao_lco.h b/src/drivers/ao_lco.h index 5721eed5..d5aace0d 100644 --- a/src/drivers/ao_lco.h +++ b/src/drivers/ao_lco.h @@ -19,7 +19,123 @@  #ifndef _AO_LCO_H_  #define _AO_LCO_H_ +#include <ao_lco_func.h> + +#define DEBUG	1 + +#if DEBUG +extern uint8_t	ao_lco_debug; +#define PRINTD(...) do { if (!ao_lco_debug) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) +#else +#define PRINTD(...)  +#endif + +extern uint8_t	ao_lco_drag_race;	/* TRUE when drag race mode enabled */ +extern uint8_t	ao_lco_pad;		/* Currently selected pad */ +extern int16_t	ao_lco_box;		/* Currently selected box */ + +extern uint8_t	ao_lco_armed; +extern uint8_t	ao_lco_firing; + +extern struct ao_pad_query	ao_pad_query;	/* Last received QUERY from pad */ + +#define AO_LCO_VALID_LAST	1 +#define AO_LCO_VALID_EVER	2 + +#define AO_LCO_PAD_VOLTAGE	0		/* Pad number to show box voltage */ + +extern uint8_t	ao_lco_min_box, ao_lco_max_box; +extern uint8_t	ao_lco_selected[AO_PAD_MAX_BOXES]; +extern uint8_t	ao_lco_valid[AO_PAD_MAX_BOXES]; +extern uint8_t	ao_lco_channels[AO_PAD_MAX_BOXES]; +extern uint16_t	ao_lco_tick_offset[AO_PAD_MAX_BOXES]; + +#define AO_LCO_MASK_SIZE(n)	(((n) + 7) >> 3) +#define AO_LCO_MASK_ID(n)	((n) >> 3) +#define AO_LCO_MASK_SHIFT(n)	((n) & 7) + +extern uint8_t	ao_lco_box_mask[AO_LCO_MASK_SIZE(AO_PAD_MAX_BOXES)]; + +/* + * Shared functions + */ + +void +ao_lco_igniter_status(void); + +void +ao_lco_update(void); + +uint8_t +ao_lco_pad_present(uint8_t box, uint8_t pad); + +uint8_t +ao_lco_pad_first(uint8_t box); + +void +ao_lco_step_pad(int8_t dir); + +void +ao_lco_set_armed(uint8_t armed); + +void +ao_lco_set_firing(uint8_t firing); + +void +ao_lco_toggle_drag(void); + +void +ao_lco_search(void); + +void +ao_lco_monitor(void); + +extern uint8_t			ao_lco_drag_beep_count; + +/* enable drag race mode */ +void +ao_lco_drag_enable(void); + +/* disable drag race mode */ +void +ao_lco_drag_disable(void); + +/* Handle drag beeps, return new delay */ +uint16_t +ao_lco_drag_beep_check(uint16_t now, uint16_t delay); + +/* Check if it's time to beep during drag race. Return new delay */ +uint16_t +ao_lco_drag_warn_check(uint16_t now, uint16_t delay); + +/* Request 'beeps' additional drag race beeps */ +void +ao_lco_drag_add_beeps(uint8_t beeps); + +/* task function for beeping while arm is active */ +void +ao_lco_arm_warn(void); + +/* + * Provided by the hw-specific driver code + */ + +void +ao_lco_set_pad(uint8_t pad); + +void +ao_lco_set_box(uint16_t box); + +void +ao_lco_set_voltage(uint16_t decivolts); + +void +ao_lco_set_display(void); +  void  ao_lco_init(void); +uint8_t +ao_lco_box_present(uint16_t box); +  #endif /* _AO_LCO_H_ */ diff --git a/src/drivers/ao_lco_bits.c b/src/drivers/ao_lco_bits.c new file mode 100644 index 00000000..b2124d1b --- /dev/null +++ b/src/drivers/ao_lco_bits.c @@ -0,0 +1,468 @@ +/* + * Copyright © 2018 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, 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_lco.h> +#include <ao_radio_cmac.h> + +uint8_t		ao_lco_debug; + +uint8_t		ao_lco_pad; +int16_t		ao_lco_box; +uint8_t		ao_lco_drag_race; + +uint8_t		ao_lco_armed;	/* arm active */ +uint8_t		ao_lco_firing;	/* fire active */ + +uint8_t		ao_lco_min_box, ao_lco_max_box; +uint8_t		ao_lco_selected[AO_PAD_MAX_BOXES]; +uint8_t		ao_lco_valid[AO_PAD_MAX_BOXES]; +uint8_t		ao_lco_channels[AO_PAD_MAX_BOXES]; +uint16_t	ao_lco_tick_offset[AO_PAD_MAX_BOXES]; + +struct ao_pad_query	ao_pad_query; + +static AO_LED_TYPE	continuity_led[AO_LED_CONTINUITY_NUM] = { +#ifdef AO_LED_CONTINUITY_0 +	AO_LED_CONTINUITY_0, +#endif +#ifdef AO_LED_CONTINUITY_1 +	AO_LED_CONTINUITY_1, +#endif +#ifdef AO_LED_CONTINUITY_2 +	AO_LED_CONTINUITY_2, +#endif +#ifdef AO_LED_CONTINUITY_3 +	AO_LED_CONTINUITY_3, +#endif +#ifdef AO_LED_CONTINUITY_4 +	AO_LED_CONTINUITY_4, +#endif +#ifdef AO_LED_CONTINUITY_5 +	AO_LED_CONTINUITY_5, +#endif +#ifdef AO_LED_CONTINUITY_6 +	AO_LED_CONTINUITY_6, +#endif +#ifdef AO_LED_CONTINUITY_7 +	AO_LED_CONTINUITY_7, +#endif +}; + +/* Set LEDs to match remote box status */ +void +ao_lco_igniter_status(void) +{ +	uint8_t		c; +	uint8_t		t = 0; + +	for (;;) { +		if (ao_lco_drag_race) +			ao_sleep_for(&ao_pad_query, AO_MS_TO_TICKS(50)); +		else +			ao_sleep(&ao_pad_query); +		PRINTD("RSSI %d VALID %d\n", ao_radio_cmac_rssi, ao_lco_valid[ao_lco_box]); +		if (!(ao_lco_valid[ao_lco_box] & AO_LCO_VALID_LAST)) { +			ao_led_on(AO_LED_RED); +			ao_led_off(AO_LED_GREEN|AO_LED_AMBER); +			continue; +		} +		if (ao_radio_cmac_rssi < -90) { +			ao_led_on(AO_LED_AMBER); +			ao_led_off(AO_LED_RED|AO_LED_GREEN); +		} else { +			ao_led_on(AO_LED_GREEN); +			ao_led_off(AO_LED_RED|AO_LED_AMBER); +		} +		if (ao_pad_query.arm_status) +			ao_led_on(AO_LED_REMOTE_ARM); +		else +			ao_led_off(AO_LED_REMOTE_ARM); + +		for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) { +			uint8_t	status; + +			if (ao_pad_query.channels & (1 << c)) +				status = ao_pad_query.igniter_status[c]; +			else +				status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN; + +			if (ao_lco_drag_race && (ao_lco_selected[ao_lco_box] & (1 << c))) { +				uint8_t	on = 0; +				if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) { +					if (t) +						on = 1; +				} else { +					if (t == 1) +						on = 1; +				} +				if (on) +					ao_led_on(continuity_led[c]); +				else +					ao_led_off(continuity_led[c]); +			} else { +				if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) +					ao_led_on(continuity_led[c]); +				else +					ao_led_off(continuity_led[c]); +			} +		} +		t = (t + 1) & 3; +	} +} + +uint8_t +ao_lco_pad_present(uint8_t box, uint8_t pad) +{ +	/* voltage measurement is always valid */ +	if (pad == AO_LCO_PAD_VOLTAGE) +		return 1; +	if (!ao_lco_channels[box]) +		return 0; +	if (pad > AO_PAD_MAX_CHANNELS) +		return 0; +	return (ao_lco_channels[box] >> (pad - 1)) & 1; +} + +uint8_t +ao_lco_pad_first(uint8_t box) +{ +	uint8_t	pad; + +	for (pad = 1; pad <= AO_PAD_MAX_CHANNELS; pad++) +		if (ao_lco_pad_present(box, pad)) +			return pad; +	return 0; +} + +static uint8_t +ao_lco_get_channels(uint8_t box, struct ao_pad_query *query) +{ +	int8_t			r; + +	r = ao_lco_query(box, query, &ao_lco_tick_offset[box]); +	if (r == AO_RADIO_CMAC_OK) { +		ao_lco_channels[box] = query->channels; +		ao_lco_valid[box] = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER; +	} else +		ao_lco_valid[box] &= ~AO_LCO_VALID_LAST; +	PRINTD("ao_lco_get_channels(%d) rssi %d valid %d ret %d offset %d\n", box, ao_radio_cmac_rssi, ao_lco_valid[box], r, ao_lco_tick_offset[box]); +	ao_wakeup(&ao_pad_query); +	return ao_lco_valid[box]; +} + +void +ao_lco_update(void) +{ +	uint8_t	previous_valid = ao_lco_valid[ao_lco_box]; + +	if (ao_lco_get_channels(ao_lco_box, &ao_pad_query) & AO_LCO_VALID_LAST) { +		if (!(previous_valid & AO_LCO_VALID_EVER)) { +			if (ao_lco_pad != AO_LCO_PAD_VOLTAGE) +				ao_lco_pad = ao_lco_pad_first(ao_lco_box); +			ao_lco_set_display(); +		} +		if (ao_lco_pad == AO_LCO_PAD_VOLTAGE) +			ao_lco_set_display(); +	} +} + +uint8_t	ao_lco_box_mask[AO_LCO_MASK_SIZE(AO_PAD_MAX_BOXES)]; + +static void +ao_lco_box_reset_present(void) +{ +	ao_lco_min_box = 0xff; +	ao_lco_max_box = 0x00; +	memset(ao_lco_box_mask, 0, sizeof (ao_lco_box_mask)); +} + +static void +ao_lco_box_set_present(uint8_t box) +{ +	if (box < ao_lco_min_box) +		ao_lco_min_box = box; +	if (box > ao_lco_max_box) +		ao_lco_max_box = box; +	if (box >= AO_PAD_MAX_BOXES) +		return; +	ao_lco_box_mask[AO_LCO_MASK_ID(box)] |= 1 << AO_LCO_MASK_SHIFT(box); +} + +void +ao_lco_step_pad(int8_t dir) +{ +	int8_t	new_pad; + +	new_pad = ao_lco_pad; +	do { +		new_pad += dir; +		if (new_pad > AO_PAD_MAX_CHANNELS) +			new_pad = AO_LCO_PAD_VOLTAGE; +		if (new_pad < 0) +			new_pad = AO_PAD_MAX_CHANNELS; +		if (new_pad == ao_lco_pad) +			break; +	} while (!ao_lco_pad_present(ao_lco_box, new_pad)); +	if (new_pad != ao_lco_pad) { +		ao_lco_pad = new_pad; +		ao_lco_set_display(); +	} +} + +void +ao_lco_set_armed(uint8_t armed) +{ +	ao_lco_armed = armed; +	PRINTD("Armed %d\n", ao_lco_armed); +	if (ao_lco_armed) { +		if (ao_lco_drag_race) { +			uint8_t	box; + +			for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) +				if (ao_lco_selected[box]) +					break; +			if (box > ao_lco_max_box) +				ao_lco_armed = 0; +		} else { +			memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); +			if (ao_lco_pad != 0) +				ao_lco_selected[ao_lco_box] = (1 << (ao_lco_pad - 1)); +			else +				ao_lco_armed = 0; +		} +	} +	ao_wakeup(&ao_lco_armed); +} + +void +ao_lco_set_firing(uint8_t firing) +{ +	ao_lco_firing = firing; +	PRINTD("Firing %d\n", ao_lco_firing); +	ao_wakeup(&ao_lco_armed); +} + +void +ao_lco_toggle_drag(void) +{ +	if (ao_lco_drag_race && ao_lco_pad != AO_LCO_PAD_VOLTAGE) { +		ao_lco_selected[ao_lco_box] ^= (1 << (ao_lco_pad - 1)); +		PRINTD("Toggle box %d pad %d (pads now %x) to drag race\n", +		       ao_lco_pad, ao_lco_box, ao_lco_selected[ao_lco_box]); +		ao_lco_drag_add_beeps(ao_lco_pad); +	} +} + +void +ao_lco_search(void) +{ +	int8_t		r; +	int8_t		try; +	uint8_t		box; +	uint8_t		boxes = 0; + +	ao_lco_box_reset_present(); +	ao_lco_set_pad(0); +	for (box = 0; box < AO_PAD_MAX_BOXES; box++) { +		if ((box % 10) == 0) +			ao_lco_set_box(box); +		for (try = 0; try < 3; try++) { +			ao_lco_tick_offset[box] = 0; +			r = ao_lco_query(box, &ao_pad_query, &ao_lco_tick_offset[box]); +			PRINTD("box %d result %d offset %d\n", box, r, ao_lco_tick_offset[box]); +			if (r == AO_RADIO_CMAC_OK) { +				++boxes; +				ao_lco_box_set_present(box); +				ao_lco_set_pad(boxes % 10); +				ao_delay(AO_MS_TO_TICKS(30)); +				break; +			} +		} +	} +	if (ao_lco_min_box <= ao_lco_max_box) +		ao_lco_box = ao_lco_min_box; +	else +		ao_lco_min_box = ao_lco_max_box = ao_lco_box = 0; +	memset(ao_lco_valid, 0, sizeof (ao_lco_valid)); +	memset(ao_lco_channels, 0, sizeof (ao_lco_channels)); +	ao_lco_pad = 1; +	ao_lco_set_display(); +} + +void +ao_lco_monitor(void) +{ +	uint16_t		delay; +	uint8_t			box; + +	for (;;) { +		PRINTD("monitor armed %d firing %d\n", +		       ao_lco_armed, ao_lco_firing); + +		if (ao_lco_armed && ao_lco_firing) { +			ao_lco_ignite(AO_PAD_FIRE); +		} else { +			ao_lco_update(); +			if (ao_lco_armed) { +				for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) { +					if (ao_lco_selected[box]) { +						PRINTD("Arming box %d pads %x\n", +						       box, ao_lco_selected[box]); +						if (ao_lco_valid[box] & AO_LCO_VALID_EVER) { +							ao_lco_arm(box, ao_lco_selected[box], ao_lco_tick_offset[box]); +							ao_delay(AO_MS_TO_TICKS(10)); +						} +					} +				} +			} +		} +		if (ao_lco_armed && ao_lco_firing) +			delay = AO_MS_TO_TICKS(100); +		else +			delay = AO_SEC_TO_TICKS(1); +		ao_sleep_for(&ao_lco_armed, delay); +	} +} + +uint8_t			ao_lco_drag_beep_count; +static uint8_t		ao_lco_drag_beep_on; +static uint16_t		ao_lco_drag_beep_time; +static uint16_t		ao_lco_drag_warn_time; + +#define AO_LCO_DRAG_BEEP_TIME	AO_MS_TO_TICKS(50) +#define AO_LCO_DRAG_WARN_TIME	AO_SEC_TO_TICKS(5) + +/* Request 'beeps' additional drag race beeps */ +void +ao_lco_drag_add_beeps(uint8_t beeps) +{ +	PRINTD("beep %d\n", beeps); +	if (ao_lco_drag_beep_count == 0) +		ao_lco_drag_beep_time = ao_time(); +	ao_lco_drag_beep_count += beeps; +	ao_wakeup(&ao_lco_drag_beep_count); +} + +/* Check whether it's time to change the beeper status, then either + * turn it on or off as necessary and bump the remaining beep counts + */ + +uint16_t +ao_lco_drag_beep_check(uint16_t now, uint16_t delay) +{ +	PRINTD("beep check count %d delta %d\n", +	       ao_lco_drag_beep_count, +	       (int16_t) (now - ao_lco_drag_beep_time)); +	if (ao_lco_drag_beep_count) { +		if ((int16_t) (now - ao_lco_drag_beep_time) >= 0) { +			if (ao_lco_drag_beep_on) { +				ao_beep(0); +				PRINTD("beep stop\n"); +				ao_lco_drag_beep_on = 0; +				if (ao_lco_drag_beep_count) { +					--ao_lco_drag_beep_count; +					if (ao_lco_drag_beep_count) +						ao_lco_drag_beep_time = now + AO_LCO_DRAG_BEEP_TIME; +				} +			} else { +				ao_beep(AO_BEEP_HIGH); +				PRINTD("beep start\n"); +				ao_lco_drag_beep_on = 1; +				ao_lco_drag_beep_time = now + AO_LCO_DRAG_BEEP_TIME; +			} +		} +	} + +	if (ao_lco_drag_beep_count) { +		uint16_t beep_delay = 0; + +		if (ao_lco_drag_beep_time > now) +			beep_delay = ao_lco_drag_beep_time - now; + +		if (delay > beep_delay) +			delay = beep_delay; +	} +	return delay; +} + +void +ao_lco_drag_enable(void) +{ +	if (!ao_lco_drag_race) { +		PRINTD("Drag enable\n"); +		ao_lco_drag_race = 1; +		memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); +#ifdef AO_LED_DRAG +		ao_led_on(AO_LED_DRAG); +#endif +		ao_lco_drag_add_beeps(5); +		ao_lco_set_display(); +	} +} + +void +ao_lco_drag_disable(void) +{ +	if (ao_lco_drag_race) { +		PRINTD("Drag disable\n"); +		ao_lco_drag_race = 0; +#ifdef AO_LED_DRAG +		ao_led_off(AO_LED_DRAG); +#endif +		memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); +		ao_lco_drag_add_beeps(2); +		ao_lco_set_display(); +	} +} + +/* add a beep if it's time to warn the user that drag race mode is + * active + */ + +uint16_t +ao_lco_drag_warn_check(uint16_t now, uint16_t delay) +{ +	if (ao_lco_drag_race) { +		uint16_t	warn_delay; + +		if ((int16_t) (now - ao_lco_drag_warn_time) >= 0) { +			ao_lco_drag_add_beeps(1); +			ao_lco_drag_warn_time = now + AO_LCO_DRAG_WARN_TIME; +		} +		warn_delay = ao_lco_drag_warn_time - now; +		if (delay > warn_delay) +			delay = warn_delay; +	} +	return delay; +} + +/* task function for beeping while arm is active */ +void +ao_lco_arm_warn(void) +{ +	for (;;) { +		while (!ao_lco_armed) { +#ifdef AO_LED_FIRE +			ao_led_off(AO_LED_FIRE); +#endif +			ao_sleep(&ao_lco_armed); +		} +#ifdef AO_LED_FIRE +		ao_led_on(AO_LED_FIRE); +#endif +		ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); +		ao_delay(AO_MS_TO_TICKS(200)); +	} +} diff --git a/src/telelco-v0.2-cc1200/Makefile b/src/telelco-v0.2-cc1200/Makefile index f29e2930..4ccf494c 100644 --- a/src/telelco-v0.2-cc1200/Makefile +++ b/src/telelco-v0.2-cc1200/Makefile @@ -67,6 +67,7 @@ ALTOS_SRC = \  	ao_button.c \  	ao_event.c \  	ao_lco.c \ +	ao_lco_bits.c \  	ao_lco_cmd.c \  	ao_lco_func.c \  	ao_radio_cmac_cmd.c diff --git a/src/telelco-v0.2/Makefile b/src/telelco-v0.2/Makefile index 8c1ced6c..8279cac1 100644 --- a/src/telelco-v0.2/Makefile +++ b/src/telelco-v0.2/Makefile @@ -64,6 +64,7 @@ ALTOS_SRC = \  	ao_button.c \  	ao_event.c \  	ao_lco.c \ +	ao_lco_bits.c \  	ao_lco_cmd.c \  	ao_lco_func.c \  	ao_radio_cmac_cmd.c diff --git a/src/telelco-v0.3/Makefile b/src/telelco-v0.3/Makefile index 0bb0f9dc..c2592bf8 100644 --- a/src/telelco-v0.3/Makefile +++ b/src/telelco-v0.3/Makefile @@ -65,6 +65,7 @@ ALTOS_SRC = \  	ao_button.c \  	ao_event.c \  	ao_lco.c \ +	ao_lco_bits.c \  	ao_lco_cmd.c \  	ao_lco_func.c \  	ao_radio_cmac_cmd.c diff --git a/src/telelco-v2.0/Makefile b/src/telelco-v2.0/Makefile index 4871993d..43295fd3 100644 --- a/src/telelco-v2.0/Makefile +++ b/src/telelco-v2.0/Makefile @@ -66,6 +66,7 @@ ALTOS_SRC = \  	ao_quadrature.c \  	ao_button.c \  	ao_event.c \ +	ao_lco_bits.c \  	ao_lco_v2.c \  	ao_lco_cmd.c \  	ao_lco_func.c \ diff --git a/src/telelco-v2.0/ao_lco_v2.c b/src/telelco-v2.0/ao_lco_v2.c index 21b2c54d..9fefde3b 100644 --- a/src/telelco-v2.0/ao_lco_v2.c +++ b/src/telelco-v2.0/ao_lco_v2.c @@ -21,19 +21,9 @@  #include <ao_event.h>  #include <ao_seven_segment.h>  #include <ao_quadrature.h> -#include <ao_lco_func.h>  #include <ao_radio_cmac.h>  #include <ao_adc_single.h> -#define DEBUG	1 - -#if DEBUG -static uint8_t	ao_lco_debug; -#define PRINTD(...) do { if (!ao_lco_debug) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) -#else -#define PRINTD(...)  -#endif -  #define AO_LCO_PAD_DIGIT	0  #define AO_LCO_BOX_DIGIT_1	1  #define AO_LCO_BOX_DIGIT_10	2 @@ -41,30 +31,14 @@ static uint8_t	ao_lco_debug;  #define AO_LCO_DRAG_RACE_START_TIME	AO_SEC_TO_TICKS(5)  #define AO_LCO_DRAG_RACE_STOP_TIME	AO_SEC_TO_TICKS(2) -#define AO_LCO_VALID_LAST	1 -#define AO_LCO_VALID_EVER	2 - -static uint8_t	ao_lco_min_box, ao_lco_max_box; -static uint8_t	ao_lco_selected[AO_PAD_MAX_BOXES]; -static uint8_t	ao_lco_valid[AO_PAD_MAX_BOXES]; -static uint8_t	ao_lco_channels[AO_PAD_MAX_BOXES]; -static uint16_t	ao_lco_tick_offset[AO_PAD_MAX_BOXES]; -  /* UI values */ -static uint8_t	ao_lco_armed; -static uint8_t	ao_lco_firing; -static uint8_t	ao_lco_drag_race; -static uint8_t	ao_lco_pad; -static int16_t	ao_lco_box;  static uint8_t	ao_lco_select_mode;  #define AO_LCO_SELECT_PAD	0  #define AO_LCO_SELECT_BOX	1 -static struct ao_pad_query	ao_pad_query; -  static uint8_t	ao_lco_display_mutex; -static void +void  ao_lco_set_pad(uint8_t pad)  {  	ao_mutex_get(&ao_lco_display_mutex); @@ -89,7 +63,7 @@ ao_lco_set_pad(uint8_t pad)  				 (0 << 5) |	\  				 (0 << 6)) -static void +void  ao_lco_set_box(uint16_t box)  {  	ao_mutex_get(&ao_lco_display_mutex); @@ -98,7 +72,7 @@ ao_lco_set_box(uint16_t box)  	ao_mutex_put(&ao_lco_display_mutex);  } -static void +void  ao_lco_set_voltage(uint16_t decivolts)  {  	uint8_t	tens, ones, tenths; @@ -114,7 +88,7 @@ ao_lco_set_voltage(uint16_t decivolts)  	ao_mutex_put(&ao_lco_display_mutex);  } -static void +void  ao_lco_set_display(void)  {  	if (ao_lco_pad == 0) { @@ -125,42 +99,12 @@ ao_lco_set_display(void)  	}  } -#define MASK_SIZE(n)	(((n) + 7) >> 3) -#define MASK_ID(n)	((n) >> 3) -#define MASK_SHIFT(n)	((n) & 7) - -static uint8_t	ao_lco_box_mask[MASK_SIZE(AO_PAD_MAX_BOXES)]; - -static uint8_t +uint8_t  ao_lco_box_present(uint16_t box)  {  	if (box >= AO_PAD_MAX_BOXES)  		return 0; -	return (ao_lco_box_mask[MASK_ID(box)] >> MASK_SHIFT(box)) & 1; -} - -static uint8_t -ao_lco_pad_present(uint8_t box, uint8_t pad) -{ -	/* voltage measurement is always valid */ -	if (pad == 0) -		return 1; -	if (!ao_lco_channels[box]) -		return 0; -	if (pad > AO_PAD_MAX_CHANNELS) -		return 0; -	return (ao_lco_channels[box] >> (pad - 1)) & 1; -} - -static uint8_t -ao_lco_pad_first(uint8_t box) -{ -	uint8_t	pad; - -	for (pad = 1; pad <= AO_PAD_MAX_CHANNELS; pad++) -		if (ao_lco_pad_present(box, pad)) -			return pad; -	return 0; +	return (ao_lco_box_mask[AO_LCO_MASK_ID(box)] >> AO_LCO_MASK_SHIFT(box)) & 1;  }  static void @@ -185,114 +129,29 @@ ao_lco_set_select(void)  	}  } -static struct ao_task	ao_lco_drag_task; -static uint8_t		ao_lco_drag_beep_count; -static uint8_t		ao_lco_drag_beep_on; -static uint16_t		ao_lco_drag_beep_time; -static uint16_t		ao_lco_drag_warn_time; - -#define AO_LCO_DRAG_BEEP_TIME	AO_MS_TO_TICKS(50) -#define AO_LCO_DRAG_WARN_TIME	AO_SEC_TO_TICKS(5) - -/* Request 'beeps' additional drag race beeps */ -static void -ao_lco_drag_add_beeps(uint8_t beeps) -{ -	PRINTD("beep %d\n", beeps); -	if (ao_lco_drag_beep_count == 0) -		ao_lco_drag_beep_time = ao_time(); -	ao_lco_drag_beep_count += beeps; -	ao_wakeup(&ao_lco_drag_beep_count); -} - -/* Check whether it's time to change the beeper status, then either - * turn it on or off as necessary and bump the remaining beep counts - */ - -static uint16_t -ao_lco_drag_beep_check(uint16_t now, uint16_t delay) -{ -	PRINTD("beep check count %d delta %d\n", -	       ao_lco_drag_beep_count, -	       (int16_t) (now - ao_lco_drag_beep_time)); -	if (ao_lco_drag_beep_count) { -		if ((int16_t) (now - ao_lco_drag_beep_time) >= 0) { -			if (ao_lco_drag_beep_on) { -				ao_beep(0); -				PRINTD("beep stop\n"); -				ao_lco_drag_beep_on = 0; -				if (ao_lco_drag_beep_count) { -					--ao_lco_drag_beep_count; -					if (ao_lco_drag_beep_count) -						ao_lco_drag_beep_time = now + AO_LCO_DRAG_BEEP_TIME; -				} -			} else { -				ao_beep(AO_BEEP_HIGH); -				PRINTD("beep start\n"); -				ao_lco_drag_beep_on = 1; -				ao_lco_drag_beep_time = now + AO_LCO_DRAG_BEEP_TIME; -			} -		} -	} - -	if (ao_lco_drag_beep_count) { -		uint16_t beep_delay = 0; - -		if (ao_lco_drag_beep_time > now) -			beep_delay = ao_lco_drag_beep_time - now; - -		if (delay > beep_delay) -			delay = beep_delay; -	} -	return delay; -} -  static void -ao_lco_drag_enable(void) +ao_lco_step_box(int8_t dir)  { -	if (!ao_lco_drag_race) { -		PRINTD("Drag enable\n"); -		ao_lco_drag_race = 1; -		memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -		ao_led_on(AO_LED_DRAG); -		ao_lco_drag_add_beeps(5); -		ao_lco_set_display(); -	} -} - -static void -ao_lco_drag_disable(void) -{ -	if (ao_lco_drag_race) { -		PRINTD("Drag disable\n"); -		ao_lco_drag_race = 0; -		ao_led_off(AO_LED_DRAG); -		memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -		ao_lco_drag_add_beeps(2); +	int16_t new_box = ao_lco_box; + +	do { +		new_box += dir; +		if (new_box > ao_lco_max_box) +			new_box = ao_lco_min_box; +		else if (new_box < ao_lco_min_box) +			new_box = ao_lco_max_box; +		if (new_box == ao_lco_box) +			break; +	} while (!ao_lco_box_present(new_box)); +	if (ao_lco_box != new_box) { +		ao_lco_box = new_box; +		ao_lco_pad = 1; +		ao_lco_channels[ao_lco_box] = 0;  		ao_lco_set_display();  	}  } -/* add a beep if it's time to warn the user that drag race mode is - * active - */ - -static uint16_t -ao_lco_drag_warn_check(uint16_t now, uint16_t delay) -{ -	if (ao_lco_drag_race) { -		uint16_t	warn_delay; - -		if ((int16_t) (now - ao_lco_drag_warn_time) >= 0) { -			ao_lco_drag_add_beeps(1); -			ao_lco_drag_warn_time = now + AO_LCO_DRAG_WARN_TIME; -		} -		warn_delay = ao_lco_drag_warn_time - now; -		if (delay > warn_delay) -			delay = warn_delay; -	} -	return delay; -} +static struct ao_task	ao_lco_drag_task;  static void  ao_lco_drag_monitor(void) @@ -300,6 +159,7 @@ ao_lco_drag_monitor(void)  	uint16_t	delay = ~0;  	uint16_t	now; +	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));  	for (;;) {  		PRINTD("Drag monitor count %d delay %d\n", ao_lco_drag_beep_count, delay);  		if (delay == (uint16_t) ~0) @@ -318,10 +178,7 @@ static void  ao_lco_input(void)  {  	static struct ao_event	event; -	int8_t		dir, new_pad; -	int16_t		new_box; -	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));  	for (;;) {  		ao_event_get(&event);  		PRINTD("event type %d unit %d value %d\n", @@ -333,40 +190,10 @@ ao_lco_input(void)  				if (!ao_lco_armed) {  					switch (ao_lco_select_mode) {  					case AO_LCO_SELECT_PAD: -						dir = (int8_t) event.value; -						new_pad = ao_lco_pad; -						do { -							new_pad += dir; -							if (new_pad > AO_PAD_MAX_CHANNELS) -								new_pad = 0; -							if (new_pad < 0) -								new_pad = AO_PAD_MAX_CHANNELS; -							if (new_pad == ao_lco_pad) -								break; -						} while (!ao_lco_pad_present(ao_lco_box, new_pad)); -						if (new_pad != ao_lco_pad) { -							ao_lco_pad = new_pad; -							ao_lco_set_display(); -						} +						ao_lco_step_pad((int8_t) event.value);  						break;  					case AO_LCO_SELECT_BOX: -						dir = (int8_t) event.value; -						new_box = ao_lco_box; -						do { -							new_box += dir; -							if (new_box > ao_lco_max_box) -								new_box = ao_lco_min_box; -							else if (new_box < ao_lco_min_box) -								new_box = ao_lco_max_box; -							if (new_box == ao_lco_box) -								break; -						} while (!ao_lco_box_present(new_box)); -						if (ao_lco_box != new_box) { -							ao_lco_box = new_box; -							ao_lco_pad = 1; -							ao_lco_channels[ao_lco_box] = 0; -							ao_lco_set_display(); -						} +						ao_lco_step_box((int8_t) event.value);  						break;  					default:  						break; @@ -378,34 +205,12 @@ ao_lco_input(void)  		case AO_EVENT_BUTTON:  			switch (event.unit) {  			case AO_BUTTON_ARM: -				ao_lco_armed = event.value; -				PRINTD("Armed %d\n", ao_lco_armed); -				if (ao_lco_armed) { -					if (ao_lco_drag_race) { -						uint8_t	box; - -						for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) -							if (ao_lco_selected[box]) -								break; -						if (box > ao_lco_max_box) -							ao_lco_armed = 0; -					} else { -						memset(ao_lco_selected, 0, sizeof (ao_lco_selected)); -						if (ao_lco_pad != 0) -							ao_lco_selected[ao_lco_box] = (1 << (ao_lco_pad - 1)); -						else -							ao_lco_armed = 0; -					} -				} +				ao_lco_set_armed(event.value);  				ao_lco_set_select(); -				ao_wakeup(&ao_lco_armed);  				break;  			case AO_BUTTON_FIRE: -				if (ao_lco_armed) { -					ao_lco_firing = event.value; -					PRINTD("Firing %d\n", ao_lco_firing); -					ao_wakeup(&ao_lco_armed); -				} +				if (ao_lco_armed) +					ao_lco_set_firing(event.value);  				break;  			case AO_BUTTON_DRAG_SELECT:  				if (event.value && ao_lco_drag_race) { @@ -437,193 +242,6 @@ ao_lco_input(void)  	}  } -static AO_LED_TYPE	continuity_led[AO_LED_CONTINUITY_NUM] = { -#ifdef AO_LED_CONTINUITY_0 -	AO_LED_CONTINUITY_0, -#endif -#ifdef AO_LED_CONTINUITY_1 -	AO_LED_CONTINUITY_1, -#endif -#ifdef AO_LED_CONTINUITY_2 -	AO_LED_CONTINUITY_2, -#endif -#ifdef AO_LED_CONTINUITY_3 -	AO_LED_CONTINUITY_3, -#endif -#ifdef AO_LED_CONTINUITY_4 -	AO_LED_CONTINUITY_4, -#endif -#ifdef AO_LED_CONTINUITY_5 -	AO_LED_CONTINUITY_5, -#endif -#ifdef AO_LED_CONTINUITY_6 -	AO_LED_CONTINUITY_6, -#endif -#ifdef AO_LED_CONTINUITY_7 -	AO_LED_CONTINUITY_7, -#endif -}; - -static uint8_t -ao_lco_get_channels(uint8_t box, struct ao_pad_query *query) -{ -	int8_t			r; - -	r = ao_lco_query(box, query, &ao_lco_tick_offset[box]); -	if (r == AO_RADIO_CMAC_OK) { -		ao_lco_channels[box] = query->channels; -		ao_lco_valid[box] = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER; -	} else -		ao_lco_valid[box] &= ~AO_LCO_VALID_LAST; -	PRINTD("ao_lco_get_channels(%d) rssi %d valid %d ret %d offset %d\n", box, ao_radio_cmac_rssi, ao_lco_valid[box], r, ao_lco_tick_offset[box]); -	ao_wakeup(&ao_pad_query); -	return ao_lco_valid[box]; -} - -static void -ao_lco_update(void) -{ -	uint8_t	previous_valid = ao_lco_valid[ao_lco_box]; - -	if (ao_lco_get_channels(ao_lco_box, &ao_pad_query) & AO_LCO_VALID_LAST) { -		if (!(previous_valid & AO_LCO_VALID_EVER)) { -			if (ao_lco_pad != 0) -				ao_lco_pad = ao_lco_pad_first(ao_lco_box); -			ao_lco_set_display(); -		} -		if (ao_lco_pad == 0) -			ao_lco_set_display(); -	} -} - -static void -ao_lco_box_reset_present(void) -{ -	ao_lco_min_box = 0xff; -	ao_lco_max_box = 0x00; -	memset(ao_lco_box_mask, 0, sizeof (ao_lco_box_mask)); -} - -static void -ao_lco_box_set_present(uint8_t box) -{ -	if (box < ao_lco_min_box) -		ao_lco_min_box = box; -	if (box > ao_lco_max_box) -		ao_lco_max_box = box; -	if (box >= AO_PAD_MAX_BOXES) -		return; -	ao_lco_box_mask[MASK_ID(box)] |= 1 << MASK_SHIFT(box); -} - -static void -ao_lco_search(void) -{ -	int8_t		r; -	int8_t		try; -	uint8_t		box; -	uint8_t		boxes = 0; - -	ao_lco_box_reset_present(); -	ao_lco_set_pad(0); -	for (box = 0; box < AO_PAD_MAX_BOXES; box++) { -		if ((box % 10) == 0) -			ao_lco_set_box(box); -		for (try = 0; try < 3; try++) { -			ao_lco_tick_offset[box] = 0; -			r = ao_lco_query(box, &ao_pad_query, &ao_lco_tick_offset[box]); -			PRINTD("box %d result %d offset %d\n", box, r, ao_lco_tick_offset[box]); -			if (r == AO_RADIO_CMAC_OK) { -				++boxes; -				ao_lco_box_set_present(box); -				ao_lco_set_pad(boxes % 10); -				ao_delay(AO_MS_TO_TICKS(30)); -				break; -			} -		} -	} -	if (ao_lco_min_box <= ao_lco_max_box) -		ao_lco_box = ao_lco_min_box; -	else -		ao_lco_min_box = ao_lco_max_box = ao_lco_box = 0; -	memset(ao_lco_valid, 0, sizeof (ao_lco_valid)); -	memset(ao_lco_channels, 0, sizeof (ao_lco_channels)); -	ao_lco_pad = 1; -	ao_lco_set_display(); -} - -static void -ao_lco_igniter_status(void) -{ -	uint8_t		c; -	uint8_t		t = 0; - -	for (;;) { -		ao_sleep(&ao_pad_query); -		PRINTD("RSSI %d VALID %d\n", ao_radio_cmac_rssi, ao_lco_valid[ao_lco_box]); -		if (!(ao_lco_valid[ao_lco_box] & AO_LCO_VALID_LAST)) { -			ao_led_on(AO_LED_RED); -			ao_led_off(AO_LED_GREEN|AO_LED_AMBER); -			continue; -		} -		if (ao_radio_cmac_rssi < -90) { -			ao_led_on(AO_LED_AMBER); -			ao_led_off(AO_LED_RED|AO_LED_GREEN); -		} else { -			ao_led_on(AO_LED_GREEN); -			ao_led_off(AO_LED_RED|AO_LED_AMBER); -		} -		if (ao_pad_query.arm_status) -			ao_led_on(AO_LED_REMOTE_ARM); -		else -			ao_led_off(AO_LED_REMOTE_ARM); - -		for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) { -			uint8_t	status; - -			if (ao_pad_query.channels & (1 << c)) -				status = ao_pad_query.igniter_status[c]; -			else -				status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN; - -			if (ao_lco_drag_race && (ao_lco_selected[ao_lco_box] & (1 << c))) { -				uint8_t	on = 0; -				if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) { -					if (t) -						on = 1; -				} else { -					if (t == 1) -						on = 1; -				} -				if (on) -					ao_led_on(continuity_led[c]); -				else -					ao_led_off(continuity_led[c]); -			} else { -				if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) -					ao_led_on(continuity_led[c]); -				else -					ao_led_off(continuity_led[c]); -			} -		} -		t = (t + 1) & 3; -	} -} - -static void -ao_lco_arm_warn(void) -{ -	for (;;) { -		while (!ao_lco_armed) { -			ao_led_off(AO_LED_FIRE); -			ao_sleep(&ao_lco_armed); -		} -		ao_led_on(AO_LED_FIRE); -		ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); -		ao_delay(AO_MS_TO_TICKS(200)); -	} -} -  /*   * Light up everything for a second at power on to let the user   * visually inspect the system for correct operation @@ -659,11 +277,8 @@ static struct ao_task ao_lco_arm_warn_task;  static struct ao_task ao_lco_igniter_status_task;  static void -ao_lco_monitor(void) +ao_lco_main(void)  { -	uint16_t		delay; -	uint8_t			box; -  	ao_lco_display_test();  	ao_lco_batt_voltage();  	ao_lco_search(); @@ -671,33 +286,7 @@ ao_lco_monitor(void)  	ao_add_task(&ao_lco_arm_warn_task, ao_lco_arm_warn, "lco arm warn");  	ao_add_task(&ao_lco_igniter_status_task, ao_lco_igniter_status, "lco igniter status");  	ao_add_task(&ao_lco_drag_task, ao_lco_drag_monitor, "drag race"); -	for (;;) { -		PRINTD("monitor armed %d firing %d\n", -		       ao_lco_armed, ao_lco_firing); - -		if (ao_lco_armed && ao_lco_firing) { -			ao_lco_ignite(AO_PAD_FIRE); -		} else { -			ao_lco_update(); -			if (ao_lco_armed) { -				for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) { -					if (ao_lco_selected[box]) { -						PRINTD("Arming box %d pads %x\n", -						       box, ao_lco_selected[box]); -						if (ao_lco_valid[box] & AO_LCO_VALID_EVER) { -							ao_lco_arm(box, ao_lco_selected[box], ao_lco_tick_offset[box]); -							ao_delay(AO_MS_TO_TICKS(10)); -						} -					} -				} -			} -		} -		if (ao_lco_armed && ao_lco_firing) -			delay = AO_MS_TO_TICKS(100); -		else -			delay = AO_SEC_TO_TICKS(1); -		ao_sleep_for(&ao_lco_armed, delay); -	} +	ao_lco_monitor();  }  #if DEBUG @@ -719,7 +308,7 @@ __code struct ao_cmds ao_lco_cmds[] = {  void  ao_lco_init(void)  { -	ao_add_task(&ao_lco_monitor_task, ao_lco_monitor, "lco monitor"); +	ao_add_task(&ao_lco_monitor_task, ao_lco_main, "lco monitor");  #if DEBUG  	ao_cmd_register(&ao_lco_cmds[0]);  #endif | 
