diff options
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | ao.h | 165 | ||||
| -rw-r--r-- | ao_adc.c | 6 | ||||
| -rw-r--r-- | ao_cmd.c | 12 | ||||
| -rw-r--r-- | ao_ee.c | 24 | ||||
| -rw-r--r-- | ao_flight.c | 160 | ||||
| -rw-r--r-- | ao_log.c | 189 | ||||
| -rw-r--r-- | ao_report.c | 81 | ||||
| -rw-r--r-- | ao_timer.c | 8 | 
9 files changed, 621 insertions, 27 deletions
| @@ -20,9 +20,12 @@ SRC = \  	ao_cmd.c \  	ao_dma.c \  	ao_ee.c \ +	ao_flight.c \  	ao_led.c \ +	ao_log.c \  	ao_mutex.c \  	ao_panic.c \ +	ao_report.c \  	ao_task.c \  	ao_timer.c \  	ao_usb.c \ @@ -29,7 +29,7 @@  /* Stack runs from above the allocated __data space to 0xfe, which avoids   * writing to 0xff as that triggers the stack overflow indicator   */ -#define AO_STACK_START	0x75 +#define AO_STACK_START	0x7f  #define AO_STACK_END	0xfe  #define AO_STACK_SIZE	(AO_STACK_END - AO_STACK_START + 1) @@ -78,6 +78,7 @@ ao_start_scheduler(void);  #define AO_PANIC_DMA		2	/* Attempt to start DMA while active */  #define AO_PANIC_MUTEX		3	/* Mis-using mutex API */  #define AO_PANIC_EE		4	/* Mis-using eeprom API */ +#define AO_PANIC_LOG		5	/* Failing to read/write log data */  /* Stop the operating system, beeping and blinking the reason */  void @@ -111,7 +112,7 @@ ao_timer_init(void);   * ao_adc.c   */ -#define ADC_RING	128 +#define AO_ADC_RING	128  /*   * One set of samples read from the A/D converter @@ -130,7 +131,7 @@ struct ao_adc {   * A/D data is stored in a ring, with the next sample to be written   * at ao_adc_head   */ -extern volatile __xdata struct ao_adc	ao_adc_ring[ADC_RING]; +extern volatile __xdata struct ao_adc	ao_adc_ring[AO_ADC_RING];  extern volatile __data uint8_t		ao_adc_head;  /* Trigger a conversion sequence (called from the timer interrupt) */ @@ -325,26 +326,174 @@ ao_mutex_put(__xdata uint8_t *ao_mutex);  #define AO_EE_CONFIG_BLOCK	((uint16_t) (AO_EE_DATA_SIZE / AO_EE_BLOCK_SIZE))  void -ao_ee_flush(void); +ao_ee_flush(void) __reentrant;  /* Write to the eeprom */  uint8_t -ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len); +ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant;  /* Read from the eeprom */  uint8_t -ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len); +ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant;  /* Write the config block (at the end of the eeprom) */  uint8_t -ao_ee_write_config(uint8_t *buf, uint16_t len); +ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant;  /* Read the config block (at the end of the eeprom) */  uint8_t -ao_ee_read_config(uint8_t *buf, uint16_t len); +ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant;  /* Initialize the EEPROM code */  void  ao_ee_init(void); +/* + * ao_log.c + */ + +/* + * The data log is recorded in the eeprom as a sequence + * of data packets. + * + * Each packet starts with a 4-byte header that has the + * packet type, the packet checksum and the tick count. Then + * they all contain 2 16 bit values which hold packet-specific + * data. + *  + * For each flight, the first packet + * is FLIGHT packet, indicating the serial number of the + * device and a unique number marking the number of flights + * recorded by this device. + * + * During flight, data from the accelerometer and barometer + * are recorded in SENSOR packets, using the raw 16-bit values + * read from the A/D converter. + * + * Also during flight, but at a lower rate, the deployment + * sensors are recorded in DEPLOY packets. The goal here is to + * detect failure in the deployment circuits. + * + * STATE packets hold state transitions as the flight computer + * transitions through different stages of the flight. + */ +#define AO_LOG_FLIGHT		'F' +#define AO_LOG_SENSOR		'A' +#define AO_LOG_TEMP_VOLT	'T' +#define AO_LOG_DEPLOY		'D' +#define AO_LOG_STATE		'S' + +#define AO_LOG_POS_NONE		(~0UL) + +struct ao_log_record { +	uint8_t			type; +	uint8_t			csum; +	uint16_t		tick; +	union { +		struct { +			uint16_t	serial; +			uint16_t	flight; +		} flight; +		struct { +			int16_t		accel; +			int16_t		pres; +		} sensor; +		struct { +			int16_t		temp; +			int16_t		v_batt; +		} temp_volt; +		struct { +			int16_t		drogue; +			int16_t		main; +		} deploy; +		struct { +			uint16_t	state; +			uint16_t	reason; +		} state; +		struct { +			uint16_t	d0; +			uint16_t	d1; +		} anon; +	} u; +}; + +/* Write a record to the eeprom log */ +void +ao_log_data(struct ao_log_record *log); + +/* Flush the log */ +void +ao_log_flush(void); + +/* Log dumping API: + * ao_log_dump_first() - get first log record + * ao_log_dump_next()  - get next log record + */ +extern __xdata struct ao_log_record ao_log_dump; + +/* Retrieve first log record for the current flight */ +uint8_t +ao_log_dump_first(void); + +/* return next log record for the current flight */ +uint8_t +ao_log_dump_next(void); + +/* Logging thread main routine */ +void +ao_log(void); + +/* Start logging to eeprom */ +void +ao_log_start(void); + +/* Initialize the logging system */ +void +ao_log_init(void); + +/* + * ao_flight.c + */ + +enum ao_flight_state { +	ao_flight_startup, +	ao_flight_idle, +	ao_flight_launchpad, +	ao_flight_boost, +	ao_flight_coast, +	ao_flight_apogee, +	ao_flight_drogue, +	ao_flight_main, +	ao_flight_landed, +	ao_flight_invalid +}; + +extern __xdata struct ao_adc	ao_flight_data; +extern __data enum flight_state	ao_flight_state; +extern __data uint16_t			ao_flight_state_tick; +extern __data int16_t			ao_flight_accel; +extern __data int16_t			ao_flight_pres; +extern __data int16_t			ao_ground_pres; +extern __data int16_t			ao_ground_accel; +extern __data int16_t			ao_min_pres; +extern __data uint16_t			ao_launch_time; + +/* Flight thread */ +void +ao_flight(void); + +/* Initialize flight thread */ +void +ao_flight_init(void); + +/* + * ao_report.c + */ + +void +ao_report_notify(void); + +void +ao_report_init(void); +  #endif /* _AO_H_ */ @@ -18,7 +18,7 @@  #include "ao.h" -volatile __xdata struct ao_adc	ao_adc_ring[ADC_RING]; +volatile __xdata struct ao_adc	ao_adc_ring[AO_ADC_RING];  volatile __data uint8_t		ao_adc_head;  void @@ -38,7 +38,7 @@ ao_adc_get(__xdata struct ao_adc *packet)  {  	uint8_t	i = ao_adc_head;  	if (i == 0) -		i = ADC_RING; +		i = AO_ADC_RING;  	i--;  	memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc));  } @@ -60,7 +60,7 @@ ao_adc_isr(void) interrupt 1  		/* record this conversion series */  		ao_adc_ring[ao_adc_head].tick = ao_time();  		ao_adc_head++; -		if (ao_adc_head == ADC_RING) +		if (ao_adc_head == AO_ADC_RING)  			ao_adc_head = 0;  		ao_wakeup(ao_adc_ring);  	} @@ -463,20 +463,18 @@ debug_output(void)  static void  dump_log(void)  { -#if 0  	uint8_t	more; -	for (more = log_first(); more; more = log_next()) { -		putchar(log_dump.type); +	for (more = ao_log_dump_first(); more; more = ao_log_dump_next()) { +		putchar(ao_log_dump.type);  		putchar(' '); -		put16(log_dump.tick); +		put16(ao_log_dump.tick);  		putchar(' '); -		put16(log_dump.u.anon.d0); +		put16(ao_log_dump.u.anon.d0);  		putchar(' '); -		put16(log_dump.u.anon.d1); +		put16(ao_log_dump.u.anon.d1);  		putchar('\n');  	} -#endif  }  static const uint8_t help_txt[] =  @@ -216,15 +216,15 @@ ao_ee_read_block(void)  	ao_ee_cs_high();  } -void -ao_ee_flush(void) +static void +ao_ee_flush_internal(void)  {  	if (ao_ee_block_dirty) {  		ao_ee_write_block();  		ao_ee_block_dirty = 0;  	}  } - +	  static void  ao_ee_fill(uint16_t block)  { @@ -236,7 +236,7 @@ ao_ee_fill(uint16_t block)  }  uint8_t -ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) +ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant  {  	uint16_t block;  	uint16_t this_len; @@ -262,7 +262,7 @@ ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len)  			if (this_len != 256)  				ao_ee_fill(block);  			else { -				ao_ee_flush(); +				ao_ee_flush_internal();  				ao_ee_block = block;  			}  			memcpy(ao_ee_data + this_off, buf, this_len); @@ -277,7 +277,7 @@ ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len)  }  uint8_t -ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) +ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant  {  	uint16_t block;  	uint16_t this_len; @@ -311,12 +311,20 @@ ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len)  	return 1;  } +void +ao_ee_flush(void) __reentrant +{ +	ao_mutex_get(&ao_ee_mutex); { +		ao_ee_flush_internal(); +	} ao_mutex_put(&ao_ee_mutex); +} +  /*   * Read/write the config block, which is in   * the last block of the ao_eeprom   */  uint8_t -ao_ee_write_config(uint8_t *buf, uint16_t len) +ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant  {  	if (len > AO_EE_BLOCK_SIZE)  		return 0; @@ -329,7 +337,7 @@ ao_ee_write_config(uint8_t *buf, uint16_t len)  }  uint8_t -ao_ee_read_config(uint8_t *buf, uint16_t len) +ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant  {  	if (len > AO_EE_BLOCK_SIZE)  		return 0; diff --git a/ao_flight.c b/ao_flight.c new file mode 100644 index 00000000..f31b4cd4 --- /dev/null +++ b/ao_flight.c @@ -0,0 +1,160 @@ +/* + * Copyright © 2009 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +/* Main flight thread. */ + +__xdata struct ao_adc	ao_flight_data; +__data enum flight_state	ao_flight_state; +__data uint16_t			ao_flight_state_tick; +__data int16_t			ao_flight_accel; +__data int16_t			ao_flight_pres; +__data int16_t			ao_ground_pres; +__data int16_t			ao_ground_accel; +__data int16_t			ao_min_pres; +__data uint16_t			ao_launch_time; + +/* Accelerometer calibration + * + * We're sampling the accelerometer through a resistor divider which + * consists of 5k and 10k resistors. This multiplies the values by 2/3. + * That goes into the cc1111 A/D converter, which is running at 11 bits + * of precision with the bits in the MSB of the 16 bit value. Only positive + * values are used, so values should range from 0-32752 for 0-3.3V. The + * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what + * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV, + * for a final computation of: + * + * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g + * + * Zero g was measured at 16000 (we would expect 16384) + */ + +#define ACCEL_G		265 +#define ACCEL_ZERO_G	16000 +#define ACCEL_NOSE_UP	(ACCEL_ZERO_G - ACCEL_G * 2 /3) +#define ACCEL_BOOST	(ACCEL_NOSE_UP - ACCEL_G * 2) + +/* + * Barometer calibration + * + * We directly sample the barometer. The specs say: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + *  + * If we want to detect launch with the barometer, we need + * a large enough bump to not be fooled by noise. At typical + * launch elevations (0-2000m), a 200Pa pressure change cooresponds + * to about a 20m elevation change. This is 5.4mV, or about 3LSB. + * As all of our calculations are done in 16 bits, we'll actually see a change + * of 16 times this though + * + * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa + */ + +#define BARO_kPa	268 +#define BARO_LAUNCH	(BARO_kPa / 5)	/* .2kPa */ +#define BARO_APOGEE	(BARO_kPa / 10)	/* .1kPa */ + +/* We also have a clock, which can be used to sanity check things in + * case of other failures + */ + +#define BOOST_TICKS_MAX	AO_SEC_TO_TICKS(10) + +void +ao_flight(void) +{ +	__data static uint8_t	nsamples = 0; +	 +	for (;;) { +		ao_sleep(&ao_adc_ring); +		ao_adc_get(&ao_flight_data); +		ao_flight_accel -= ao_flight_accel >> 4; +		ao_flight_accel += ao_flight_data.accel >> 4; +		ao_flight_pres -= ao_flight_pres >> 4; +		ao_flight_pres += ao_flight_data.pres >> 4; +		 +		switch (ao_flight_state) { +		case ao_flight_startup: +			if (nsamples < 100) { +				++nsamples; +				continue; +			} +			ao_ground_accel = ao_flight_accel; +			ao_ground_pres = ao_flight_pres; +			ao_min_pres = ao_flight_pres; +			if (ao_flight_accel < ACCEL_NOSE_UP) { +				ao_flight_state = ao_flight_launchpad; +				ao_flight_state_tick = ao_time(); +				ao_report_notify(); +			} else { +				ao_flight_state = ao_flight_idle; +				ao_flight_state_tick = ao_time(); +				ao_report_notify(); +			} +			break; +		case ao_flight_launchpad: +			if (ao_flight_accel < ACCEL_BOOST ||  +			    ao_flight_pres + BARO_LAUNCH < ao_ground_pres) +			{ +				ao_flight_state = ao_flight_boost; +				ao_flight_state_tick = ao_time(); +				ao_log_start(); +				ao_report_notify(); +				break; +			} +			break; +		case ao_flight_boost: +			if (ao_flight_accel > ACCEL_ZERO_G || +			    (int16_t) (ao_flight_data.tick - ao_launch_time) > BOOST_TICKS_MAX) +			{ +				ao_flight_state = ao_flight_coast; +				ao_flight_state_tick = ao_time(); +				ao_report_notify(); +				break; +			} +			break; +		case ao_flight_coast: +			if (ao_flight_pres < ao_min_pres) +				ao_min_pres = ao_flight_pres; +			if (ao_flight_pres - BARO_APOGEE > ao_min_pres) { +				ao_flight_state = ao_flight_apogee; +				ao_flight_state_tick = ao_time(); +				ao_report_notify(); +			} +			break; +		case ao_flight_apogee: +			break; +		} +	} +} + +static __xdata struct ao_task	flight_task; + +void +ao_flight_init(void) +{ +	ao_flight_state = ao_flight_startup; + +	ao_add_task(&flight_task, ao_flight); +} + diff --git a/ao_log.c b/ao_log.c new file mode 100644 index 00000000..112ea510 --- /dev/null +++ b/ao_log.c @@ -0,0 +1,189 @@ +/* + * Copyright © 2009 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +__data uint32_t		ao_log_current_pos; +__data uint32_t		ao_log_start_pos; +__xdata uint8_t		ao_log_running; +__xdata uint8_t		ao_log_mutex; + +static uint8_t +ao_log_csum(uint8_t *b) +{ +	uint8_t	sum = 0x5a; +	uint8_t	i; + +	for (i = 0; i < sizeof (struct ao_log_record); i++) +		sum += *b++; +	return -sum; +} + +void +ao_log_data(struct ao_log_record *log) +{ +	/* set checksum */ +	log->csum = 0; +	log->csum = ao_log_csum((uint8_t *) log); +	ao_mutex_get(&ao_log_mutex); { +		if (ao_log_running) { +			ao_ee_write(ao_log_current_pos, +				    (uint8_t *) log, +				    sizeof (struct ao_log_record)); +			ao_log_current_pos += sizeof (struct ao_log_record); +			if (ao_log_current_pos >= AO_EE_DATA_SIZE) +				ao_log_current_pos = 0; +			if (ao_log_current_pos == ao_log_start_pos) +				ao_log_running = 0; +		} +	} ao_mutex_put(&ao_log_mutex); +} + +void +ao_log_flush(void) +{ +	ao_ee_flush(); +} + +__xdata struct ao_log_record ao_log_dump; +static __data uint16_t ao_log_dump_flight; +static __data uint32_t ao_log_dump_pos; + +static uint8_t +ao_log_dump_check_data(void) +{ +	if (ao_log_csum((uint8_t *) &ao_log_dump) != 0) +		return 0; +	return 1; +} + +static uint8_t +ao_log_dump_scan(void) +{ +	if (!ao_ee_read(0, (uint8_t *) &ao_log_dump, sizeof (struct ao_log_record))) +		ao_panic(AO_PANIC_LOG); +	if (ao_log_dump_check_data() && ao_log_dump.type == AO_LOG_FLIGHT) { +		ao_log_dump_flight = ao_log_dump.u.flight.flight; +		return 1; +	} else { +		ao_log_dump_flight = 0; +		return 0; +	} +} + +uint8_t +ao_log_dump_first(void) +{ +	ao_log_dump_pos = 0; +	if (!ao_log_dump_scan()) +		return 0; +	return 1; +} + +uint8_t +ao_log_dump_next(void) +{ +	ao_log_dump_pos += sizeof (struct ao_log_record); +	if (ao_log_dump_pos >= AO_EE_DEVICE_SIZE) +		return 0; +	if (!ao_ee_read(ao_log_dump_pos, (uint8_t *) &ao_log_dump, +			sizeof (struct ao_log_record))) +		return 0; +	return ao_log_dump_check_data(); +} + +uint8_t	ao_log_adc_pos; +enum flight_state ao_log_state; + +void +ao_log(void) +{ +	static __xdata struct ao_log_record	log; +	 +	ao_log_dump_scan(); + +	while (!ao_log_running) +		ao_sleep(&ao_log_running); +	 +	log.type = AO_LOG_FLIGHT; +	log.tick = ao_flight_state_tick; +	log.u.flight.serial = 0; +	log.u.flight.flight = ao_log_dump_flight + 1; +	ao_log_data(&log); +	for (;;) { +		/* Write state change to EEPROM */ +		if (ao_flight_state != ao_log_state) { +			ao_log_state = ao_flight_state; +			log.type = AO_LOG_STATE; +			log.tick = ao_flight_state_tick; +			log.u.state.state = ao_log_state; +			log.u.state.reason = 0; +			ao_log_data(&log); +		} +		/* Write samples to EEPROM */ +		while (ao_log_adc_pos != ao_adc_head) { +			log.type = AO_LOG_SENSOR; +			log.tick = ao_adc_ring[ao_log_adc_pos].tick; +			log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel; +			log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres; +			ao_log_data(&log); +			if (ao_log_adc_pos == 0) { +				log.type = AO_LOG_TEMP_VOLT; +				log.tick = ao_adc_ring[ao_log_adc_pos].tick; +				log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp; +				log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt; +				ao_log_data(&log); +				log.type = AO_LOG_DEPLOY; +				log.tick = ao_adc_ring[ao_log_adc_pos].tick; +				log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d; +				log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m; +				ao_log_data(&log); +			} +			ao_log_adc_pos++; +			if (ao_log_adc_pos == AO_ADC_RING) +				ao_log_adc_pos = 0; +		} +		 +		/* Wait for a while */ +		ao_delay(AO_MS_TO_TICKS(100)); +	} +} + +void +ao_log_start(void) +{ +	/* start logging */ +	ao_log_running = 1; +	ao_wakeup(&ao_log_running); +} + +static __xdata struct ao_task ao_log_task; + +void +ao_log_init(void) +{ +	ao_log_running = 0; + +	/* For now, just log the flight starting at the begining of eeprom */ +	ao_log_start_pos = 0; +	ao_log_current_pos = ao_log_start_pos; +	ao_log_state = ao_flight_invalid; + +	/* Create a task to log events to eeprom */ +	ao_add_task(&ao_log_task, ao_log); +} diff --git a/ao_report.c b/ao_report.c new file mode 100644 index 00000000..1cc883be --- /dev/null +++ b/ao_report.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2009 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +static const char * __xdata flight_reports[] = { +	"...",		/* startup, 'S' */ +	"..",		/* idle 'I' */ +	".--.",		/* launchpad 'P' */ +	"-...",		/* boost 'B' */ +	"-.-.",		/* coast 'C' */ +	".-",		/* apogee 'A' */ +	"-..",		/* drogue 'D' */ +	"--",		/* main 'M' */ +	".-..",		/* landed 'L' */ +	".-.-.-",	/* invalid */ +}; + +#if 1 +#define signal(time)	ao_beep_for(AO_BEEP_MID, time) +#else +#define signal(time)	ao_led_for(AO_LED_RED, time) +#endif +#define pause(time)	ao_delay(time) + +static void +ao_report_state(void) +{ +	char *r = flight_reports[ao_flight_state]; +	char c; + +	if (!r) +		return; +	while (c = *r++) { +		if (c == '.') +			signal(AO_MS_TO_TICKS(200)); +		else +			signal(AO_MS_TO_TICKS(600)); +		pause(AO_MS_TO_TICKS(200)); +	} +} + +static __xdata ao_report_wait; + +void +ao_report_notify(void) +{ +	ao_wakeup(&ao_report_wait); +} + +void +ao_report(void) +{ +	for(;;) { +		ao_report_state(); +		ao_sleep(&ao_report_wait); +	} +} + +static __xdata struct ao_task ao_report_task; + +void +ao_report_init(void) +{ +	ao_add_task(&ao_report_task, ao_report); +} @@ -42,10 +42,16 @@ ao_delay(uint16_t ticks)  #define T1_CLOCK_DIVISOR	8	/* 24e6/8 = 3e6 */  #define T1_SAMPLE_TIME		30000	/* 3e6/30000 = 100 */ +__data uint8_t	ao_adc_interval = 1; +__data uint8_t	ao_adc_count; +  void ao_timer_isr(void) interrupt 9  {  	++ao_tick_count; -	ao_adc_poll(); +	if (++ao_adc_count >= ao_adc_interval) { +		ao_adc_count = 0; +		ao_adc_poll(); +	}  	ao_wakeup(DATA_TO_XDATA(&ao_tick_count));  } | 
