diff options
| author | Keith Packard <keithp@keithp.com> | 2012-12-25 14:20:42 -0800 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2012-12-25 14:20:42 -0800 | 
| commit | 868ef0c9c4b208c02a87180b0eede329369bdc77 (patch) | |
| tree | 1f20d312d56bac34bad12f287629a2651bbbccf8 | |
| parent | 669cde8a87d88ceae89e369c1d38b88c9f8198cf (diff) | |
| parent | 57487e78b90465a21c87cf30deb0aeaba0887332 (diff) | |
Merge branch 'master' into micropeak-logging
75 files changed, 4154 insertions, 672 deletions
| diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 45a88783..99b8e39d 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -26,31 +26,56 @@ public class AltosConfigData implements Iterable<String> {  	/* Version information */  	public String	manufacturer;  	public String	product; -	public String	version; -	public int	log_format;  	public int	serial; +	public int	flight; +	public int	log_format; +	public String	version;  	/* Strings returned */  	public LinkedList<String>	lines;  	/* Config information */ -	public int	config_major; -	public int	config_minor; +	/* HAS_FLIGHT*/  	public int	main_deploy;  	public int	apogee_delay; -	public int	radio_channel; -	public int	radio_setting; +	public int	apogee_lockout; + +	/* HAS_RADIO */  	public int	radio_frequency;  	public String	callsign; -	public int	accel_cal_plus, accel_cal_minus; +	public int	radio_enable;  	public int	radio_calibration; +	/* Old HAS_RADIO values */ +	public int	radio_channel; +	public int	radio_setting; + +	/* HAS_ACCEL */ +	public int	accel_cal_plus, accel_cal_minus; +	public int	pad_orientation; + +	/* HAS_LOG */  	public int	flight_log_max; + +	/* HAS_IGNITE */  	public int	ignite_mode; -	public int	stored_flight; + +	/* HAS_AES */ +	public String	aes_key; + +	/* AO_PYRO_NUM */ +	public AltosPyro[]	pyros; +	public int		npyro; +	public int		pyro; + +	/* HAS_APRS */ +	public int		aprs_interval; + +	/* Storage info replies */  	public int	storage_size;  	public int	storage_erase_unit; -	public AltosPyro[]	pyros; +	/* Log listing replies */ +	public int	stored_flight;  	public static String get_string(String line, String label) throws  ParseException {  		if (line.startsWith(label)) { @@ -85,6 +110,9 @@ public class AltosConfigData implements Iterable<String> {  			if (stored_flight == 0)  				return 1;  			return 0; +		case AltosLib.AO_LOG_FORMAT_TELEMETRY: +		case AltosLib.AO_LOG_FORMAT_TELESCIENCE: +			return 1;  		default:  			if (flight_log_max <= 0)  				return 1; @@ -111,7 +139,7 @@ public class AltosConfigData implements Iterable<String> {  		return r;  	} -	 +  	public int compare_version(String other) {  		int[]	me = parse_version(version);  		int[]	them = parse_version(other); @@ -130,71 +158,343 @@ public class AltosConfigData implements Iterable<String> {  		return 0;  	} -	public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { -		link.printf("c s\nf\nl\nv\n"); +	public void reset() {  		lines = new LinkedList<String>(); -		radio_setting = 0; -		radio_frequency = 0; -		stored_flight = 0; -		serial = -1; + +		manufacturer = "unknown"; +		product = "unknown"; +		serial = 0; +		flight = 0; +		log_format = AltosLib.AO_LOG_FORMAT_UNKNOWN; +		version = "unknown"; + +		main_deploy = -1; +		apogee_delay = -1; +		apogee_lockout = -1; + +		radio_frequency = -1; +		callsign = null; +		radio_enable = -1; +		radio_calibration = -1; +		radio_channel = -1; +		radio_setting = -1; + +		accel_cal_plus = -1; +		accel_cal_minus = -1; +		pad_orientation = -1; + +		flight_log_max = -1; +		ignite_mode = -1; + +		aes_key = ""; + +		pyro = 0; +		npyro = 0;  		pyros = null; -		int npyro = 0; -		int pyro = 0; +		aprs_interval = -1; + +		storage_size = -1; +		storage_erase_unit = -1; +		stored_flight = -1; +	} + +	public void parse_line(String line) { +		lines.add(line); +		/* Version replies */ +		try { manufacturer = get_string(line, "manufacturer"); } catch (Exception e) {} +		try { product = get_string(line, "product"); } catch (Exception e) {} +		try { serial = get_int(line, "serial-number"); } catch (Exception e) {} +		try { flight = get_int(line, "current-flight"); } catch (Exception e) {} +		try { log_format = get_int(line, "log-format"); } catch (Exception e) {} +		try { version = get_string(line, "software-version"); } catch (Exception e) {} + +		/* Version also contains MS5607 info, which we ignore here */ + +		/* Config show replies */ + +		/* HAS_FLIGHT */ +		try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} +		try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} +		try { apogee_lockout = get_int(line, "Apogee lockout:"); } catch (Exception e) {} + +		/* HAS_RADIO */ +		try { +			radio_frequency = get_int(line, "Frequency:"); +			if (radio_frequency < 0) +				radio_frequency = 434550; +		} catch (Exception e) {} +		try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} +		try { radio_enable = get_int(line, "Radio enable:"); } catch (Exception e) {} +		try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} + +		/* Old HAS_RADIO values */ +		try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} +		try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} + +		/* HAS_ACCEL */ +		try { +			if (line.startsWith("Accel cal")) { +				String[] bits = line.split("\\s+"); +				if (bits.length >= 6) { +					accel_cal_plus = Integer.parseInt(bits[3]); +					accel_cal_minus = Integer.parseInt(bits[5]); +				} +			} +		} catch (Exception e) {} +		try { pad_orientation = get_int(line, "Pad orientation:"); } catch (Exception e) {} + +		/* HAS_LOG */ +		try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} + +		/* HAS_IGNITE */ +		try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} + +		/* HAS_AES */ +		try { aes_key = get_string(line, "AES key:"); } catch (Exception e) {} + +		/* AO_PYRO_NUM */ +		try { +			npyro = get_int(line, "Pyro-count:"); +			pyros = new AltosPyro[npyro]; +			pyro = 0; +		} catch (Exception e) {} +		if (npyro > 0) { +			try { +				AltosPyro p = new AltosPyro(pyro, line); +				if (pyro < npyro) +					pyros[pyro++] = p; +			} catch (Exception e) {} +		} + +		/* HAS_APRS */ +		try { aprs_interval = get_int(line, "APRS interval:"); } catch (Exception e) {} + +		/* Storage info replies */ +		try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} +		try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} + +		/* Log listing replies */ +		try { get_int(line, "flight"); stored_flight++; }  catch (Exception e) {} +	} + +	public AltosConfigData() { +		reset(); +	} + +	private void read_link(AltosLink link, String finished) throws InterruptedException, TimeoutException {  		for (;;) {  			String line = link.get_reply();  			if (line == null)  				throw new TimeoutException();  			if (line.contains("Syntax error"))  				continue; -			lines.add(line); -			if (pyro < npyro - 1) { -				if (pyros == null) -					pyros = new AltosPyro[npyro]; -				try { -					pyros[pyro] = new AltosPyro(pyro, line); -				} catch (ParseException e) { -				} -				++pyro; -				continue; -			} -			try { serial = get_int(line, "serial-number"); } catch (Exception e) {} -			try { log_format = get_int(line, "log-format"); } catch (Exception e) {} -			try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} -			try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} -			try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} -			try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} -			try { -				radio_frequency = get_int(line, "Frequency:"); -				if (radio_frequency < 0) -					radio_frequency = 434550; -			} catch (Exception e) {} -			try { -				if (line.startsWith("Accel cal")) { -					String[] bits = line.split("\\s+"); -					if (bits.length >= 6) { -						accel_cal_plus = Integer.parseInt(bits[3]); -						accel_cal_minus = Integer.parseInt(bits[5]); -					} -				} -			} catch (Exception e) {} -			try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} -			try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} -			try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} -			try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} -			try { version = get_string(line,"software-version"); } catch (Exception e) {} -			try { product = get_string(line,"product"); } catch (Exception e) {} -			try { manufacturer = get_string(line,"manufacturer"); } catch (Exception e) {} - -			try { get_int(line, "flight"); stored_flight++; }  catch (Exception e) {} -			try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} -			try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} -			try { npyro = get_int(line, "Pyro-count:"); pyro = 0; } catch (Exception e) {} +			this.parse_line(line);  			/* signals the end of the version info */ -			if (line.startsWith("software-version")) +			if (line.startsWith(finished))  				break;  		}  	} -}
\ No newline at end of file +	public boolean has_frequency() { +		return radio_frequency >= 0 || radio_setting >= 0 || radio_channel >= 0; +	} + +	public void set_frequency(double freq) { +		int	frequency = radio_frequency; +		int	setting = radio_setting; + +		if (frequency > 0) { +			radio_frequency = (int) Math.floor (freq * 1000 + 0.5); +			radio_channel = -1; +		} else if (setting > 0) { +			radio_setting =AltosConvert.radio_frequency_to_setting(freq, +										    radio_calibration); +			radio_channel = -1; +		} else { +			radio_channel = AltosConvert.radio_frequency_to_channel(freq); +		} +	} + +	public double frequency() { +		int	channel = radio_channel; +		int	setting = radio_setting; +		if (channel < 0) +			channel = 0; +		if (setting < 0) +			setting = 0; + +		return AltosConvert.radio_to_frequency(radio_frequency, +						       setting, +						       radio_calibration, +						       channel); +	} + +	public int log_limit() { +		if (storage_size > 0 && storage_erase_unit > 0) { +			int	log_limit = storage_size - storage_erase_unit; +			if (log_limit > 0) +				return log_limit / 1024; +		} +		return 1024; +	} + +	public void get_values(AltosConfigValues source) { + +		/* HAS_FLIGHT */ +		if (main_deploy >= 0) +			main_deploy = source.main_deploy(); +		if (apogee_delay >= 0) +			apogee_delay = source.apogee_delay(); +		if (apogee_lockout >= 0) +			apogee_lockout = source.apogee_lockout(); + +		/* HAS_RADIO */ +		if (has_frequency()) +			set_frequency(source.radio_frequency()); +		if (radio_enable >= 0) +			radio_enable = source.radio_enable(); +		if (callsign != null) +			callsign = source.callsign(); +		if (radio_calibration >= 0) +			radio_calibration = source.radio_calibration(); + +		/* HAS_ACCEL */ +		if (pad_orientation >= 0) +			pad_orientation = source.pad_orientation(); + +		/* HAS_LOG */ +		if (flight_log_max >= 0) +			flight_log_max = source.flight_log_max(); + +		/* HAS_IGNITE */ +		if (ignite_mode >= 0) +			ignite_mode = source.ignite_mode(); + +		/* AO_PYRO_NUM */ +		if (npyro > 0) +			pyros = source.pyros(); + +		if (aprs_interval >= 0) +			aprs_interval = source.aprs_interval(); +	} + +	public void set_values(AltosConfigValues dest) { +		dest.set_serial(serial); +		dest.set_product(product); +		dest.set_version(version); +		dest.set_main_deploy(main_deploy); +		dest.set_apogee_delay(apogee_delay); +		dest.set_apogee_lockout(apogee_lockout); +		dest.set_radio_calibration(radio_calibration); +		dest.set_radio_frequency(frequency()); +		boolean max_enabled = true; +		switch (log_format) { +		case AltosLib.AO_LOG_FORMAT_TINY: +			max_enabled = false; +			break; +		default: +			if (stored_flight >= 0) +				max_enabled = false; +			break; +		} +		dest.set_flight_log_max_enabled(max_enabled); +		dest.set_radio_enable(radio_enable); +		dest.set_flight_log_max_limit(log_limit()); +		dest.set_flight_log_max(flight_log_max); +		dest.set_ignite_mode(ignite_mode); +		dest.set_pad_orientation(pad_orientation); +		dest.set_callsign(callsign); +		if (npyro > 0) +			dest.set_pyros(pyros); +		else +			dest.set_pyros(null); +		dest.set_aprs_interval(aprs_interval); +	} + +	public void save(AltosLink link, boolean remote) throws InterruptedException, TimeoutException { + +		/* HAS_FLIGHT */ +		if (main_deploy >= 0) +			link.printf("c m %d\n", main_deploy); +		if (apogee_delay >= 0) +			link.printf("c d %d\n", apogee_delay); +		if (apogee_lockout >= 0) +			link.printf("c L %d\n", apogee_lockout); + +		/* Don't mess with radio calibration when remote */ +		if (radio_calibration > 0 && !remote) +			link.printf("c f %d\n", radio_calibration); + +		/* HAS_RADIO */ +		if (has_frequency()) { +			boolean has_frequency = radio_frequency >= 0; +			boolean has_setting = radio_setting > 0; +			double frequency = frequency(); +			link.set_radio_frequency(frequency, +							has_frequency, +							has_setting, +							radio_calibration); +			/* When remote, reset the dongle frequency at the same time */ +			if (remote) { +				link.stop_remote(); +				link.set_radio_frequency(frequency); +				link.start_remote(); +			} +		} + +		if (callsign != null) +			link.printf("c c %s\n", callsign); +		if (radio_enable >= 0) +			link.printf("c e %d\n", radio_enable); + +		/* HAS_ACCEL */ +		/* UI doesn't support accel cal */ +		if (pad_orientation >= 0) +			link.printf("c o %d\n", pad_orientation); + +		/* HAS_LOG */ +		if (flight_log_max != 0) +			link.printf("c l %d\n", flight_log_max); + +		/* HAS_IGNITE */ +		if (ignite_mode >= 0) +			link.printf("c i %d\n", ignite_mode); + +		/* HAS_AES */ +		/* UI doesn't support AES key config */ + +		/* AO_PYRO_NUM */ +		if (pyros.length > 0) { +			for (int p = 0; p < pyros.length; p++) { +				link.printf("c P %s\n", +						   pyros[p].toString()); +			} +		} + +		/* HAS_APRS */ +		if (aprs_interval >= 0) +			link.printf("c A %d\n", aprs_interval); + +		link.printf("c w\n"); +		link.flush_output(); +	} + +	public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { +		reset(); +		link.printf("c s\nf\nv\n"); +		read_link(link, "software-version"); +		System.out.printf("Log format %d\n", log_format); +		switch (log_format) { +		case AltosLib.AO_LOG_FORMAT_FULL: +		case AltosLib.AO_LOG_FORMAT_TINY: +		case AltosLib.AO_LOG_FORMAT_MEGAMETRUM: +			link.printf("l\n"); +			read_link(link, "done"); +		default: +			break; +		} +	} + +} diff --git a/altoslib/AltosConfigValues.java b/altoslib/AltosConfigValues.java new file mode 100644 index 00000000..40d5217e --- /dev/null +++ b/altoslib/AltosConfigValues.java @@ -0,0 +1,79 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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. + */ + +package org.altusmetrum.AltosLib; + +public interface AltosConfigValues { +	/* set and get all of the dialog values */ +	public abstract void set_product(String product); + +	public abstract void set_version(String version); + +	public abstract void set_serial(int serial); + +	public abstract void set_main_deploy(int new_main_deploy); + +	public abstract int main_deploy(); + +	public abstract void set_apogee_delay(int new_apogee_delay); + +	public abstract int apogee_delay(); + +	public abstract void set_apogee_lockout(int new_apogee_lockout); + +	public abstract int apogee_lockout(); + +	public abstract void set_radio_frequency(double new_radio_frequency); + +	public abstract double radio_frequency(); + +	public abstract void set_radio_calibration(int new_radio_calibration); + +	public abstract int radio_calibration(); + +	public abstract void set_radio_enable(int new_radio_enable); + +	public abstract int radio_enable(); + +	public abstract void set_callsign(String new_callsign); + +	public abstract String callsign(); + +	public abstract void set_flight_log_max(int new_flight_log_max); + +	public abstract void set_flight_log_max_enabled(boolean enable); + +	public abstract int flight_log_max(); + +	public abstract void set_flight_log_max_limit(int flight_log_max_limit); + +	public abstract void set_ignite_mode(int new_ignite_mode); + +	public abstract int ignite_mode(); + +	public abstract void set_pad_orientation(int new_pad_orientation); + +	public abstract int pad_orientation(); + +	public abstract void set_pyros(AltosPyro[] new_pyros); + +	public abstract AltosPyro[] pyros(); + +	public abstract int aprs_interval(); + +	public abstract void set_aprs_interval(int new_aprs_interval); +} diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 6d510563..1b722026 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -284,8 +284,8 @@ public abstract class AltosLink implements Runnable {  		frequency = in_frequency;  		config_data();  		set_radio_frequency(frequency, -				    config_data.radio_frequency != 0, -				    config_data.radio_setting != 0, +				    config_data.radio_frequency > 0, +				    config_data.radio_setting > 0,  				    config_data.radio_calibration);  	} @@ -339,10 +339,10 @@ public abstract class AltosLink implements Runnable {  	public String name;  	public void start_remote() throws TimeoutException, InterruptedException { -		if (debug) -			System.out.printf("start remote %7.3f\n", frequency);  		if (frequency == 0.0)  			frequency = AltosPreferences.frequency(serial); +		if (debug) +			System.out.printf("start remote %7.3f\n", frequency);  		set_radio_frequency(frequency);  		set_callsign(AltosPreferences.callsign());  		printf("p\nE 0\n"); diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java index 148a9f92..318fea4d 100644 --- a/altoslib/AltosMs5607.java +++ b/altoslib/AltosMs5607.java @@ -82,6 +82,43 @@ public class AltosMs5607 {  		return pa;  	} +	public boolean parse_line(String line) { +		String[] items = line.split("\\s+"); +		if (line.startsWith("Pressure:")) { +			if (items.length >= 2) +				raw_pres = Integer.parseInt(items[1]); +		} else if (line.startsWith("Temperature:")) { +			if (items.length >= 2) +				raw_temp = Integer.parseInt(items[1]); +		} else if (line.startsWith("ms5607 reserved:")) { +			if (items.length >= 3) +				reserved = Integer.parseInt(items[2]); +		} else if (line.startsWith("ms5607 sens:")) { +			if (items.length >= 3) +				sens = Integer.parseInt(items[2]); +		} else if (line.startsWith("ms5607 off:")) { +			if (items.length >= 3) +				off = Integer.parseInt(items[2]); +		} else if (line.startsWith("ms5607 tcs:")) { +			if (items.length >= 3) +				tcs = Integer.parseInt(items[2]); +		} else if (line.startsWith("ms5607 tco:")) { +			if (items.length >= 3) +				tco = Integer.parseInt(items[2]); +		} else if (line.startsWith("ms5607 tref:")) { +			if (items.length >= 3) +				tref = Integer.parseInt(items[2]); +		} else if (line.startsWith("ms5607 tempsens:")) { +			if (items.length >= 3) +				tempsens = Integer.parseInt(items[2]); +		} else if (line.startsWith("ms5607 crc:")) { +			if (items.length >= 3) +				crc = Integer.parseInt(items[2]); +		} else if (line.startsWith("Altitude")) +			return false; +		return true; +	} +  	public AltosMs5607() {  		raw_pres = AltosRecord.MISSING;  		raw_temp = AltosRecord.MISSING; diff --git a/altoslib/AltosMs5607Query.java b/altoslib/AltosMs5607Query.java index 3c746795..1aaec334 100644 --- a/altoslib/AltosMs5607Query.java +++ b/altoslib/AltosMs5607Query.java @@ -27,38 +27,7 @@ class AltosMs5607Query extends AltosMs5607 {  			if (line == null) {  				throw new TimeoutException();  			} -			String[] items = line.split("\\s+"); -			if (line.startsWith("Pressure:")) { -				if (items.length >= 2) -					raw_pres = Integer.parseInt(items[1]); -			} else if (line.startsWith("Temperature:")) { -				if (items.length >= 2) -					raw_temp = Integer.parseInt(items[1]); -			} else if (line.startsWith("ms5607 reserved:")) { -				if (items.length >= 3) -					reserved = Integer.parseInt(items[2]); -			} else if (line.startsWith("ms5607 sens:")) { -				if (items.length >= 3) -					sens = Integer.parseInt(items[2]); -			} else if (line.startsWith("ms5607 off:")) { -				if (items.length >= 3) -					off = Integer.parseInt(items[2]); -			} else if (line.startsWith("ms5607 tcs:")) { -				if (items.length >= 3) -					tcs = Integer.parseInt(items[2]); -			} else if (line.startsWith("ms5607 tco:")) { -				if (items.length >= 3) -					tco = Integer.parseInt(items[2]); -			} else if (line.startsWith("ms5607 tref:")) { -				if (items.length >= 3) -					tref = Integer.parseInt(items[2]); -			} else if (line.startsWith("ms5607 tempsens:")) { -				if (items.length >= 3) -					tempsens = Integer.parseInt(items[2]); -			} else if (line.startsWith("ms5607 crc:")) { -				if (items.length >= 3) -					crc = Integer.parseInt(items[2]); -			} else if (line.startsWith("Altitude")) +			if (!parse_line(line))  				break;  		}  		convert(); diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index f28dd1c6..218c598a 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -92,6 +92,9 @@ public class AltosState {  	public void init (AltosRecord cur, AltosState prev_state) {  		data = cur; +		/* Discard previous state if it was for a different board */ +		if (prev_state != null && prev_state.data.serial != data.serial) +			prev_state = null;  		ground_altitude = data.ground_altitude();  		altitude = data.altitude(); diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 2579a650..0086bc65 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -12,6 +12,7 @@ AltosLibdir = $(datadir)/java  AltosLib_JAVA = \  	$(SRC)/AltosLib.java \  	$(SRC)/AltosConfigData.java \ +	$(SRC)/AltosConfigValues.java \  	$(SRC)/AltosConvert.java \  	$(SRC)/AltosCRCException.java \  	$(SRC)/AltosEepromChunk.java \ diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 4b0edec0..e1ffebb4 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -58,64 +58,12 @@ public class AltosConfig implements ActionListener {  	AltosDevice	device;  	AltosSerial	serial_line;  	boolean		remote; -	AltosConfigData	remote_config_data; -	double		remote_frequency; -	int_ref		serial; -	int_ref		log_format; -	int_ref		main_deploy; -	int_ref		apogee_delay; -	int_ref		apogee_lockout; -	int_ref		radio_channel; -	int_ref		radio_calibration; -	int_ref		flight_log_max; -	int_ref		ignite_mode; -	int_ref		pad_orientation; -	int_ref		radio_setting; -	int_ref		radio_frequency; -	int_ref		storage_size; -	int_ref		storage_erase_unit; -	int_ref		stored_flight; -	int_ref		radio_enable; -	string_ref	version; -	string_ref	product; -	string_ref	callsign; -	int_ref		npyro; -	AltosPyro[]	pyros; + +	AltosConfigData	data;  	AltosConfigUI	config_ui;  	boolean		serial_started;  	boolean		made_visible; -	boolean get_int(String line, String label, int_ref x) { -		if (line.startsWith(label)) { -			try { -				String tail = line.substring(label.length()).trim(); -				String[] tokens = tail.split("\\s+"); -				if (tokens.length > 0) { -					int	i = Integer.parseInt(tokens[0]); -					x.set(i); -					return true; -				} -			} catch (NumberFormatException ne) { -			} -		} -		return false; -	} - -	boolean get_string(String line, String label, string_ref s) { -		if (line.startsWith(label)) { -			String	quoted = line.substring(label.length()).trim(); - -			if (quoted.startsWith("\"")) -				quoted = quoted.substring(1); -			if (quoted.endsWith("\"")) -				quoted = quoted.substring(0,quoted.length()-1); -			s.set(quoted); -			return true; -		} else { -			return false; -		} -	} -  	void start_serial() throws InterruptedException, TimeoutException {  		serial_started = true;  		if (remote) @@ -130,43 +78,8 @@ public class AltosConfig implements ActionListener {  			serial_line.stop_remote();  	} -	int log_limit() { -		if (storage_size.get() > 0 && storage_erase_unit.get() > 0) { -			int	log_limit = storage_size.get() - storage_erase_unit.get(); -			if (log_limit > 0) -				return log_limit / 1024; -		} -		return 1024; -	} -  	void update_ui() { -		config_ui.set_serial(serial.get()); -		config_ui.set_product(product.get()); -		config_ui.set_version(version.get()); -		config_ui.set_main_deploy(main_deploy.get()); -		config_ui.set_apogee_delay(apogee_delay.get()); -		config_ui.set_apogee_lockout(apogee_lockout.get()); -		config_ui.set_radio_calibration(radio_calibration.get()); -		config_ui.set_radio_frequency(frequency()); -		boolean max_enabled = true; -		switch (log_format.get()) { -		case Altos.AO_LOG_FORMAT_TINY: -			max_enabled = false; -			break; -		default: -			if (stored_flight.get() >= 0) -				max_enabled = false; -			break; -		} -		config_ui.set_flight_log_max_enabled(max_enabled); -		config_ui.set_radio_enable(radio_enable.get()); -		config_ui.set_flight_log_max_limit(log_limit()); -		config_ui.set_flight_log_max(flight_log_max.get()); -		config_ui.set_ignite_mode(ignite_mode.get()); -		config_ui.set_pad_orientation(pad_orientation.get()); -		config_ui.set_callsign(callsign.get()); -		config_ui.set_pyros(pyros); -		config_ui.set_has_pyro(npyro.get() > 0); +		data.set_values(config_ui);  		config_ui.set_clean();  		if (!made_visible) {  			made_visible = true; @@ -176,52 +89,6 @@ public class AltosConfig implements ActionListener {  	int	pyro; -	void process_line(String line) { -		if (line == null) { -			abort(); -			return; -		} -		if (line.equals("all finished")) { -			if (serial_line != null) -				update_ui(); -			return; -		} -		if (pyro < npyro.get()) { -			if (pyros == null) -				pyros = new AltosPyro[npyro.get()]; - -			try { -				pyros[pyro] = new AltosPyro(pyro, line); -			} catch (ParseException e) { -				System.out.printf ("pyro parse failed %s\n", line); -			} -			++pyro; -			return; -		} -		get_int(line, "serial-number", serial); -		get_int(line, "log-format", log_format); -		get_int(line, "Main deploy:", main_deploy); -		get_int(line, "Apogee delay:", apogee_delay); -		get_int(line, "Apogee lockout:", apogee_lockout); -		get_int(line, "Radio channel:", radio_channel); -		get_int(line, "Radio cal:", radio_calibration); -		get_int(line, "Max flight log:", flight_log_max); -		get_int(line, "Ignite mode:", ignite_mode); -		get_int(line, "Pad orientation:", pad_orientation); -		get_int(line, "Radio setting:", radio_setting); -		if (get_int(line, "Frequency:", radio_frequency)) -			if (radio_frequency.get() < 0) -				radio_frequency.set(434550); -		get_int(line, "Radio enable:", radio_enable); -		get_int(line, "Storage size:", storage_size); -		get_int(line, "Storage erase unit:", storage_erase_unit); -		get_int(line, "flight", stored_flight); -		get_string(line, "Callsign:", callsign); -		get_string(line,"software-version", version); -		get_string(line,"product", product); -		get_int(line, "Pyro-count:", npyro); -	} -  	final static int	serial_mode_read = 0;  	final static int	serial_mode_save = 1;  	final static int	serial_mode_reboot = 2; @@ -230,63 +97,33 @@ public class AltosConfig implements ActionListener {  		AltosConfig	config;  		int		serial_mode; -		void process_line(String line) { -			config.process_line(line); -		} -		void callback(String in_line) { -			final String line = in_line; +		void callback(String in_cmd) { +			final String cmd = in_cmd;  			Runnable r = new Runnable() {  					public void run() { -						process_line(line); +						if (cmd.equals("abort")) { +							abort(); +						} else if (cmd.equals("all finished")) { +							if (serial_line != null) +								update_ui(); +						}  					}  				};  			SwingUtilities.invokeLater(r);  		} -		void reset_data() { -			serial.set(0); -			log_format.set(Altos.AO_LOG_FORMAT_UNKNOWN); -			main_deploy.set(250); -			apogee_delay.set(0); -			apogee_lockout.set(0); -			radio_channel.set(0); -			radio_setting.set(0); -			radio_frequency.set(0); -			radio_calibration.set(1186611); -			radio_enable.set(-1); -			flight_log_max.set(0); -			ignite_mode.set(-1); -			pad_orientation.set(-1); -			storage_size.set(-1); -			storage_erase_unit.set(-1); -			stored_flight.set(-1); -			callsign.set("N0CALL"); -			version.set("unknown"); -			product.set("unknown"); -			pyro = 0; -			npyro.set(0); -		} -  		void get_data() { +			data = null;  			try { -				config.start_serial(); -				reset_data(); - -				config.serial_line.printf("c s\nf\nl\nv\n"); -				for (;;) { -					try { -						String line = config.serial_line.get_reply(5000); -						if (line == null) -							stop_serial(); -						callback(line); -						if (line.startsWith("software-version")) -							break; -					} catch (Exception e) { -						break; -					} -				} +				start_serial(); +				data = new AltosConfigData(config.serial_line);  			} catch (InterruptedException ie) {  			} catch (TimeoutException te) { +				try { +					stop_serial(); +					callback("abort"); +				} catch (InterruptedException ie) { +				}  			} finally {  				try {  					stop_serial(); @@ -298,41 +135,11 @@ public class AltosConfig implements ActionListener {  		void save_data() {  			try { -				double frequency = frequency(); -				boolean has_frequency = radio_frequency.get() > 0; -				boolean has_setting = radio_setting.get() > 0;  				start_serial(); -				serial_line.printf("c m %d\n", main_deploy.get()); -				serial_line.printf("c d %d\n", apogee_delay.get()); -				serial_line.printf("c L %d\n", apogee_lockout.get()); -				if (!remote) -					serial_line.printf("c f %d\n", radio_calibration.get()); -				serial_line.set_radio_frequency(frequency, -								has_frequency, -								has_setting, -								radio_calibration.get()); -				if (remote) { -					serial_line.stop_remote(); -					serial_line.set_radio_frequency(frequency); -					AltosUIPreferences.set_frequency(device.getSerial(), frequency); -					serial_line.start_remote(); -				} -				serial_line.printf("c c %s\n", callsign.get()); -				if (flight_log_max.get() != 0) -					serial_line.printf("c l %d\n", flight_log_max.get()); -				if (radio_enable.get() >= 0) -					serial_line.printf("c e %d\n", radio_enable.get()); -				if (ignite_mode.get() >= 0) -					serial_line.printf("c i %d\n", ignite_mode.get()); -				if (pad_orientation.get() >= 0) -					serial_line.printf("c o %d\n", pad_orientation.get()); -				if (pyros.length > 0) { -					for (int p = 0; p < pyros.length; p++) { -						serial_line.printf("c P %s\n", -								   pyros[p].toString()); -					} -				} -				serial_line.printf("c w\n"); +				data.save(serial_line, remote); +				if (remote) +					AltosUIPreferences.set_frequency(device.getSerial(), +									 data.frequency());  			} catch (InterruptedException ie) {  			} catch (TimeoutException te) {  			} finally { @@ -413,57 +220,29 @@ public class AltosConfig implements ActionListener {  	}  	double frequency() { -		return AltosConvert.radio_to_frequency(radio_frequency.get(), -						       radio_setting.get(), -						       radio_calibration.get(), -						       radio_channel.get()); -	} - -	void set_frequency(double freq) { -		int	frequency = radio_frequency.get(); -		int	setting = radio_setting.get(); - -		if (frequency > 0) { -			radio_frequency.set((int) Math.floor (freq * 1000 + 0.5)); -			radio_channel.set(0); -		} else if (setting > 0) { -			radio_setting.set(AltosConvert.radio_frequency_to_setting(freq, -										  radio_calibration.get())); -			radio_channel.set(0); -		} else { -			radio_channel.set(AltosConvert.radio_frequency_to_channel(freq)); -		} +		return AltosConvert.radio_to_frequency(data.radio_frequency, +						       data.radio_setting, +						       data.radio_calibration, +						       data.radio_channel);  	}  	void save_data() {  		/* bounds check stuff */ -		if (config_ui.flight_log_max() > log_limit()) { +		if (config_ui.flight_log_max() > data.log_limit()) {  			JOptionPane.showMessageDialog(owner,  						      String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",  								    config_ui.flight_log_max(), -								    log_limit()), +								    data.log_limit()),  						      "Maximum Flight Log Too Large",  						      JOptionPane.ERROR_MESSAGE);  			return;  		} -		main_deploy.set(config_ui.main_deploy()); -		apogee_delay.set(config_ui.apogee_delay()); -		apogee_lockout.set(config_ui.apogee_lockout()); -		radio_calibration.set(config_ui.radio_calibration()); -		set_frequency(config_ui.radio_frequency()); -		flight_log_max.set(config_ui.flight_log_max()); -		if (radio_enable.get() >= 0) -			radio_enable.set(config_ui.radio_enable()); -		if (ignite_mode.get() >= 0) -			ignite_mode.set(config_ui.ignite_mode()); -		if (pad_orientation.get() >= 0) -			pad_orientation.set(config_ui.pad_orientation()); -		callsign.set(config_ui.callsign()); -		if (npyro.get() > 0) { -			pyros = config_ui.pyros(); -		} +		/* Pull data out of the UI and stuff back into our local data record */ + +		data.get_values(config_ui); +  		run_serial_thread(serial_mode_save);  	} @@ -491,27 +270,6 @@ public class AltosConfig implements ActionListener {  	public AltosConfig(JFrame given_owner) {  		owner = given_owner; -		serial = new int_ref(0); -		log_format = new int_ref(Altos.AO_LOG_FORMAT_UNKNOWN); -		main_deploy = new int_ref(250); -		apogee_delay = new int_ref(0); -		apogee_lockout = new int_ref(0); -		radio_channel = new int_ref(0); -		radio_setting = new int_ref(0); -		radio_frequency = new int_ref(0); -		radio_calibration = new int_ref(1186611); -		radio_enable = new int_ref(-1); -		flight_log_max = new int_ref(0); -		ignite_mode = new int_ref(-1); -		pad_orientation = new int_ref(-1); -		storage_size = new int_ref(-1); -		storage_erase_unit = new int_ref(-1); -		stored_flight = new int_ref(-1); -		callsign = new string_ref("N0CALL"); -		version = new string_ref("unknown"); -		product = new string_ref("unknown"); -		npyro = new int_ref(0); -  		device = AltosDeviceDialog.show(owner, Altos.product_any);  		if (device != null) {  			try { diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index feac053b..95780e2b 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -25,7 +25,7 @@ import org.altusmetrum.AltosLib.*;  public class AltosConfigUI  	extends AltosDialog -	implements ActionListener, ItemListener, DocumentListener +	implements ActionListener, ItemListener, DocumentListener, AltosConfigValues  {  	Container	pane; @@ -39,6 +39,7 @@ public class AltosConfigUI  	JLabel		radio_calibration_label;  	JLabel		radio_frequency_label;  	JLabel		radio_enable_label; +	JLabel		aprs_interval_label;  	JLabel		flight_log_max_label;  	JLabel		ignite_mode_label;  	JLabel		pad_orientation_label; @@ -56,6 +57,7 @@ public class AltosConfigUI  	AltosFreqList	radio_frequency_value;  	JTextField	radio_calibration_value;  	JRadioButton	radio_enable_value; +	JComboBox	aprs_interval_value;  	JComboBox	flight_log_max_value;  	JComboBox	ignite_mode_value;  	JComboBox	pad_orientation_value; @@ -97,6 +99,13 @@ public class AltosConfigUI  		"Redundant Main",  	}; +	static String[] aprs_interval_values = { +		"Disabled", +		"2", +		"5", +		"10" +	}; +  	static String[] pad_orientation_values = {  		"Antenna Up",  		"Antenna Down", @@ -141,6 +150,13 @@ public class AltosConfigUI  			radio_enable_value.setToolTipText("Firmware version does not support disabling radio");  	} +	void set_aprs_interval_tool_tip() { +		if (aprs_interval_value.isEnabled()) +			aprs_interval_value.setToolTipText("Enable APRS and set the interval between APRS reports"); +		else +			aprs_interval_value.setToolTipText("Hardware doesn't support APRS"); +	} +  	void set_flight_log_max_tool_tip() {  		if (flight_log_max_value.isEnabled())  			flight_log_max_value.setToolTipText("Size reserved for each flight log (in kB)"); @@ -393,7 +409,7 @@ public class AltosConfigUI  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = il;  		c.ipady = 5; -		radio_enable_label = new JLabel("Telemetry/RDF Enable:"); +		radio_enable_label = new JLabel("Telemetry/RDF/APRS Enable:");  		pane.add(radio_enable_label, c);  		c = new GridBagConstraints(); @@ -410,6 +426,32 @@ public class AltosConfigUI  		set_radio_enable_tool_tip();  		row++; +		/* APRS interval */ +		c = new GridBagConstraints(); +		c.gridx = 0; c.gridy = row; +		c.gridwidth = 4; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		c.ipady = 5; +		aprs_interval_label = new JLabel("APRS Interval(s):"); +		pane.add(aprs_interval_label, c); + +		c = new GridBagConstraints(); +		c.gridx = 4; c.gridy = row; +		c.gridwidth = 4; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = ir; +		c.ipady = 5; +		aprs_interval_value = new JComboBox(aprs_interval_values); +		aprs_interval_value.setEditable(true); +		aprs_interval_value.addItemListener(this); +		pane.add(aprs_interval_value, c); +		set_aprs_interval_tool_tip(); +		row++; +  		/* Callsign */  		c = new GridBagConstraints();  		c.gridx = 0; c.gridy = row; @@ -684,6 +726,7 @@ public class AltosConfigUI  	public void set_apogee_delay(int new_apogee_delay) {  		apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay)); +		apogee_delay_value.setEnabled(new_apogee_delay >= 0);  	}  	public int apogee_delay() { @@ -692,6 +735,7 @@ public class AltosConfigUI  	public void set_apogee_lockout(int new_apogee_lockout) {  		apogee_lockout_value.setSelectedItem(Integer.toString(new_apogee_lockout)); +		apogee_lockout_value.setEnabled(new_apogee_lockout >= 0);  	}  	public int apogee_lockout() { @@ -829,13 +873,10 @@ public class AltosConfigUI  			return -1;  	} -	public void set_has_pyro(boolean has_pyro) { -		pyro.setEnabled(has_pyro); -	} -  	public void set_pyros(AltosPyro[] new_pyros) {  		pyros = new_pyros; -		if (pyro_ui != null) +		pyro.setEnabled(pyros != null); +		if (pyros != null && pyro_ui != null)  			pyro_ui.set_pyros(pyros);  	} @@ -844,4 +885,24 @@ public class AltosConfigUI  			pyros = pyro_ui.get_pyros();  		return pyros;  	} + +	public void set_aprs_interval(int new_aprs_interval) { +		String	s; + +		if (new_aprs_interval <= 0) +			s = "Disabled"; +		else +			s = Integer.toString(new_aprs_interval); +		aprs_interval_value.setSelectedItem(s); +		aprs_interval_value.setEnabled(new_aprs_interval >= 0); +		set_aprs_interval_tool_tip(); +	} + +	public int aprs_interval() { +		String	s = aprs_interval_value.getSelectedItem().toString(); + +		if (s.equals("Disabled")) +			return 0; +		return Integer.parseInt(s); +	}  } diff --git a/altosui/AltosGraphTime.java b/altosui/AltosGraphTime.java index 75e536c5..62d516b2 100644 --- a/altosui/AltosGraphTime.java +++ b/altosui/AltosGraphTime.java @@ -68,11 +68,13 @@ class AltosGraphTime extends AltosGraph {      abstract static class TimeSeries implements Element {          protected XYSeries series;          private String axisName; +	private String axisUnits;          private Color color; -        public TimeSeries(String axisName, String label, Color color) { +        public TimeSeries(String axisName, String axisUnits, String label, Color color) {              this.series = new XYSeries(label); -            this.axisName = axisName; +            this.axisName = String.format("%s (%s)", axisName, axisUnits); +	    this.axisUnits = axisUnits;              this.color = color;          } @@ -85,8 +87,14 @@ class AltosGraphTime extends AltosGraph {              XYSeriesCollection dataset = new XYSeriesCollection();              dataset.addSeries(this.series); -            XYItemRenderer renderer = new StandardXYItemRenderer(); +            XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);              renderer.setSeriesPaint(0, color); +	    StandardXYToolTipGenerator	tool_tip; + +	    tool_tip = new StandardXYToolTipGenerator(String.format("{1}s: {2}%s ({0})", axisUnits), +						      new java.text.DecimalFormat("0.00"), +						      new java.text.DecimalFormat("0.00")); +	    renderer.setBaseToolTipGenerator(tool_tip);              int dataNum = g.getDataNum(this);              int axisNum = g.getAxisNum(this); @@ -192,10 +200,8 @@ class AltosGraphTime extends AltosGraph {      public JFreeChart createChart() {          NumberAxis xAxis = new NumberAxis("Time (s)");          xAxis.setAutoRangeIncludesZero(false); -        XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);          XYPlot plot = new XYPlot();          plot.setDomainAxis(xAxis); -        plot.setRenderer(renderer);          plot.setOrientation(PlotOrientation.VERTICAL);          if (serial != null && flight != null) { @@ -205,7 +211,6 @@ class AltosGraphTime extends AltosGraph {              title = callsign + " - " + title;          } -        renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());          JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,                                  plot, true);          ChartUtilities.applyCurrentTheme(chart); diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index f59f70ba..b7c2e92e 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -29,7 +29,7 @@ public class AltosGraphUI extends AltosFrame      static private class OverallGraphs {          AltosGraphTime.Element height =  -		new AltosGraphTime.TimeSeries(String.format("Height (%s)", AltosConvert.height.show_units()), "Height (AGL)", red) { +		new AltosGraphTime.TimeSeries("Height", AltosConvert.height.show_units(), "Height (AGL)", red) {                  public void gotTimeData(double time, AltosDataPoint d) {  			double	height = d.height();  			if (height != AltosRecord.MISSING) @@ -38,7 +38,7 @@ public class AltosGraphUI extends AltosFrame              };          AltosGraphTime.Element speed = -		new AltosGraphTime.TimeSeries(String.format("Speed (%s)", AltosConvert.speed.show_units()), "Vertical Speed", green) {  +		new AltosGraphTime.TimeSeries("Speed", AltosConvert.speed.show_units(), "Vertical Speed", green) {                   public void gotTimeData(double time, AltosDataPoint d) {  		    double	speed = d.speed();  		    if (speed != AltosRecord.MISSING) @@ -47,8 +47,8 @@ public class AltosGraphUI extends AltosFrame              };          AltosGraphTime.Element acceleration = -		new AltosGraphTime.TimeSeries(String.format("Acceleration (%s)", -							    AltosConvert.accel.show_units()), +		new AltosGraphTime.TimeSeries("Acceleration", +					      AltosConvert.accel.show_units(),  					      "Axial Acceleration", blue)              {                  public void gotTimeData(double time, AltosDataPoint d) { @@ -59,8 +59,8 @@ public class AltosGraphUI extends AltosFrame              };          AltosGraphTime.Element temperature = -            new AltosGraphTime.TimeSeries("Temperature (\u00B0C)",  -                    "Board temperature", red)  +	    new AltosGraphTime.TimeSeries("Temperature", "\u00B0C",  +					  "Board temperature", red)               {                  public void gotTimeData(double time, AltosDataPoint d) {  		    double temp = d.temperature(); @@ -70,7 +70,7 @@ public class AltosGraphUI extends AltosFrame              };          AltosGraphTime.Element drogue_voltage = -            new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", yellow)  +            new AltosGraphTime.TimeSeries("Voltage", "(V)", "Drogue Continuity", yellow)               {                  public void gotTimeData(double time, AltosDataPoint d) {  		    double v = d.drogue_voltage(); @@ -80,7 +80,7 @@ public class AltosGraphUI extends AltosFrame              };          AltosGraphTime.Element main_voltage = -            new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", magenta)  +            new AltosGraphTime.TimeSeries("Voltage", "(V)", "Main Continuity", magenta)               {                  public void gotTimeData(double time, AltosDataPoint d) {  		    double v = d.main_voltage(); diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index 257fdaec..871b8205 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -1 +1 @@ -SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load ao-telem ao-stmload ao-send-telem +SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load ao-telem ao-stmload ao-send-telem ao-sky-flash diff --git a/ao-tools/ao-sky-flash/Makefile.am b/ao-tools/ao-sky-flash/Makefile.am new file mode 100644 index 00000000..f6c5089a --- /dev/null +++ b/ao-tools/ao-sky-flash/Makefile.am @@ -0,0 +1,18 @@ +bin_PROGRAMS=ao-sky-flash + +AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) +AO_SKY_FLASH_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a + +ao_sky_flash_DEPENDENCIES = $(AO_SKY_FLASH_LIBS) + +ao_sky_flash_LDADD=$(AO_SKY_FLASH_LIBS) $(LIBUSB_LIBS) + +ao_sky_flash_SOURCES = \ +	sky_bin.c \ +	sky_debug.c \ +	sky_flash.c \ +	sky_flash.h \ +	sky_serial.c \ +	sky_srec.c + +man_MANS = ao-sky-flash.1 diff --git a/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin b/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.binBinary files differ new file mode 100644 index 00000000..c698add2 --- /dev/null +++ b/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin diff --git a/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin b/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.binBinary files differ new file mode 100644 index 00000000..9e256897 --- /dev/null +++ b/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin diff --git a/ao-tools/ao-sky-flash/ao-sky-flash.1 b/ao-tools/ao-sky-flash/ao-sky-flash.1 new file mode 100644 index 00000000..d61c9c9d --- /dev/null +++ b/ao-tools/ao-sky-flash/ao-sky-flash.1 @@ -0,0 +1,85 @@ +.\" +.\" 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. +.\" +.\" +.TH AO-SKY-FLASH 1 "ao-sky-flash" "" +.SH NAME +ao-sky-flash \- flash GPS firmware program to a SkyTraq GPS chip +.SH SYNOPSIS +.B "ao-sky-flash" +[\-T \fItty-device\fP] +[\--tty \fItty-device\fP] +[\-D \fIaltos-device\fP] +[\--device \fIaltos-device\fP] +[\--loader \fIboot-loader\fP] +[\--firmware \fIgps-firmware\fP] +[\--query] +[\--quiet] +[\--raw] +.SH DESCRIPTION +.I ao-sky-flash +loads the specified GPS firmware file into the target GPS chip flash +memory using the specified boot loader. +.SH OPTIONS +.TP +\-T tty-device | --tty tty-device +This selects which tty device the debugger uses to communicate with +the target device. +.TP +\-D AltOS-device | --device AltOS-device +Search for a connected device. This requires an argument of one of the +following forms: +.IP +TeleMetrum:2 +.br +TeleMetrum +.br +2 +.IP +Leaving out the product name will cause the tool to select a suitable +product, leaving out the serial number will cause the tool to match +one of the available devices. +.TP +\--loader boot-loader +This specifies the desired boot loader to use for reflashing the +device. You should use srec_115200.bin unless you have a good reason +not to. This should be in S record format. +.TP +\--firmware gps-firmware +This specifies the new GPS firmware image to load onto the target GPS +chip. No checking is done on this device at all; flash garbage and the +GPS chip will probably fail to boot. +.TP +\--query +Instead of loading new firmware, query the current version of firmware +running on the target device. +.TP +\--quiet +Normally, ao-spy-flash is quite chatty. This shuts it up, except for +error messages. +.TP +\--raw +The expected target for reflashing is an Altus Metrum product with the +GPS chip connected to the CPU on that board and not directly to the +USB serial port. This option says that the target GPS chip is directly +connected, which changes how things are initialized a bit. +.SH USAGE +.I ao-sky-flash +loads the specified bootloader into device RAM and then uses that to +load new firmware to flash. +.SH AUTHOR +Keith Packard diff --git a/ao-tools/ao-sky-flash/sky_bin.c b/ao-tools/ao-sky-flash/sky_bin.c new file mode 100644 index 00000000..04cfec35 --- /dev/null +++ b/ao-tools/ao-sky-flash/sky_bin.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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 "sky_flash.h" +#include <stdio.h> +#include <string.h> + +#define FLASHBYTES	8192 + +int +skytraq_send_bin(int fd, const char *filename) +{ +	FILE		*file; +	char		buf[FLASHBYTES]; +	int		count; +	unsigned char	cksum; +	int		c; +	long		size; +	long		pos; +	char		message[1024]; +	int		ret; +	 +	file = fopen(filename, "r"); +	if (!file) { +		perror(filename); +		return -1; +	} + +	/* Compute checksum, figure out how long the file */ +	cksum = 0; +	while ((c = getc(file)) != EOF) +		cksum += (unsigned char) c; +	size = ftell(file); +	rewind(file); + +	sprintf(message, "BINSIZE = %d Checksum = %d Loopnumber = %d ", size, cksum, 1); + +	ret = skytraq_cmd_wait(fd, message, strlen(message) + 1, "OK", 20000); +	if (ret < 0) +		printf ("waitstatus failed %d\n", ret); + +	pos = 0; +	for (;;) { +		count = fread(buf, 1, sizeof (buf), file); +		if (count < 0) { +			perror("fread"); +			fclose(file); +			return -1; +		} +		if (count == 0) +			break; +		skytraq_dbg_printf (0, "%7d of %7d ", pos + count, size); +		pos += count; +		ret = skytraq_cmd_wait(fd, buf, count, "OK", 20000); +		if (ret < 0) +			return ret; +	} +	return skytraq_waitstatus(fd, "END", 30000); +} diff --git a/ao-tools/ao-sky-flash/sky_debug.c b/ao-tools/ao-sky-flash/sky_debug.c new file mode 100644 index 00000000..32571f0e --- /dev/null +++ b/ao-tools/ao-sky-flash/sky_debug.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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 <stdint.h> +#include <unistd.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/time.h> +#include "sky_flash.h" + +static int	dbg_input; +static int	dbg_newline = 1; + +int +skytraq_millis(void) +{ +	struct timeval	tv; +	gettimeofday(&tv, NULL); +	return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +static void +skytraq_dbg_time(void) +{ +	int	delta = skytraq_millis() - skytraq_open_time; + +	if (!skytraq_verbose) +		return; +	printf ("%4d.%03d ", delta / 1000, delta % 1000); +} + +void +skytraq_dbg_newline(void) +{ +	if (!skytraq_verbose) +		return; +	if (!dbg_newline) { +		putchar('\n'); +		dbg_newline = 1; +	} +} + +static void +skytraq_dbg_set(int input) +{ +	if (!skytraq_verbose) +		return; +	if (input != dbg_input) { +		skytraq_dbg_newline(); +		if (input) +			putchar('\t'); +		dbg_input = input; +	} +} + +void +skytraq_dbg_char(int input, char c) +{ +	if (!skytraq_verbose) +		return; +	skytraq_dbg_set(input); +	if (dbg_newline) +		skytraq_dbg_time(); +	if (c < ' '  || c > '~') +		printf ("\\%02x", (unsigned char) c); +	else +		putchar(c); +	dbg_newline = 0; +	if (c == '\n') +		dbg_input = 2; +	fflush(stdout); +} + +void +skytraq_dbg_buf(int input, const char *buf, int len) +{ +	if (!skytraq_verbose) +		return; +	while (len--) +		skytraq_dbg_char(input, *buf++); +} + +void +skytraq_dbg_printf(int input, const char *fmt, ...) +{ +	va_list ap; + +	if (!skytraq_verbose) +		return; +	skytraq_dbg_set(input); +	if (dbg_newline) +		skytraq_dbg_time(); +	va_start (ap, fmt); +	vprintf(fmt, ap); +	va_end(ap); +	dbg_newline = 0; +} diff --git a/ao-tools/ao-sky-flash/sky_flash.c b/ao-tools/ao-sky-flash/sky_flash.c new file mode 100644 index 00000000..55cb2cb6 --- /dev/null +++ b/ao-tools/ao-sky-flash/sky_flash.c @@ -0,0 +1,259 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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 "sky_flash.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <getopt.h> +#include "cc.h" + +static const struct option options[] = { +	{ .name = "tty", .has_arg = 1, .val = 'T' }, +	{ .name = "device", .has_arg = 1, .val = 'D' }, +	{ .name = "loader", .has_arg = 1, .val = 'l' }, +	{ .name = "firmware", .has_arg = 1, .val = 'f' }, +	{ .name = "query", .has_arg = 0, .val = 'q' }, +	{ .name = "raw", .has_arg = 0, .val = 'r' }, +	{ .name = "quiet", .has_arg = 0, .val = 'Q' }, +	{ 0, 0, 0, 0}, +}; + +static uint8_t	query_version[] = { +	0xa0, 0xa1, 0x00, 0x02, 0x02, 0x01, 0x03, 0x0d, 0x0a +}; + +static void +usage(char *program) +{ +	fprintf(stderr, +		"usage: %s [--tty <tty-name>]\n" +		"          [--device <device-name>]\n" +		"          [--loader <srec bootloader file>]\n" +		"          [--firmware <binary firmware file>]\n" +		"          [--query]\n" +		"          [--quiet]\n" +		"          [--raw]\n", program); +	exit(1); +} + +int +skytraq_expect(int fd, uint8_t want, int timeout) { +	int	c; + +	c = skytraq_waitchar(fd, timeout); +	if (c < 0) +		return -1; +	if (c == want) +		return 1; +	return 0; +} + +int +skytraq_wait_reply(int fd, uint8_t reply, uint8_t *buf, uint8_t reply_len) { + +	for(;;) { +		uint8_t	a, b; +		uint8_t	cksum_computed, cksum_read; +		int	len; +		switch (skytraq_expect(fd, 0xa0, 10000)) { +		case -1: +			return -1; +		case 0: +			continue; +		case 1: +			break; +		} +		switch (skytraq_expect(fd, 0xa1, 1000)) { +		case -1: +			return -1; +		case 0: +			continue; +		} +		a = skytraq_waitchar(fd, 1000); +		b = skytraq_waitchar(fd, 1000); +		switch (skytraq_expect(fd, reply, 1000)) { +		case -1: +			return -1; +		case 0: +			continue; +		} +		len = (a << 16) | b; +		if (len != reply_len) +			continue; +		*buf++ = reply; +		len--; +		cksum_computed = reply; +		while (len--) { +			a = skytraq_waitchar(fd, 1000); +			if (a < 0) +				return a; +			cksum_computed ^= a; +			*buf++ = a; +		} +		switch (skytraq_expect(fd, cksum_computed, 1000)) { +		case -1: +			return -1; +		case 0: +			continue; +		} +		switch (skytraq_expect(fd, 0x0d, 1000)) { +		case -1: +			return -1; +		case 0: +			continue; +		} +		switch (skytraq_expect(fd, 0x0a, 1000)) { +		case -1: +			return -1; +		case 0: +			continue; +		} +		break; +	} +	return 0; +} + +int +main(int argc, char **argv) +{ +	int	fd; +	char	buf[512]; +	int	ret; +	FILE	*input; +	long	size; +	unsigned char	cksum; +	int	c; +	char	message[1024]; +	char	*tty = NULL; +	char	*device = NULL; +	char	*loader = "srec_115200.bin"; +	char	*file = NULL; +	int	query = 0; +	int	raw = 0; + +	while ((c = getopt_long(argc, argv, "T:D:l:f:qQr", options, NULL)) != -1) { +		switch (c) { +		case 'T': +			tty = optarg; +			break; +		case 'D': +			device = optarg; +			break; +		case 'l': +			loader = optarg; +			break; +		case 'f': +			file = optarg; +			break; +		case 'q': +			query = 1; +			break; +		case 'Q': +			skytraq_verbose = 0; +			break; +		case 'r': +			raw = 1; +			break; +		default: +			usage(argv[0]); +			break; +		} +	} + +	if (!tty) +		tty = cc_usbdevs_find_by_arg(device, "TeleMetrum"); +	if (!tty) +		tty = getenv("ALTOS_TTY"); +	if (!tty) +		tty="/dev/ttyACM0"; +	fd = skytraq_open(tty); +	if (fd < 0) +		exit(1); + +	if (raw) { +		/* Set the baud rate to 115200 */ +		skytraq_setcomm(fd, 115200); +		sleep(1); +		skytraq_setspeed(fd, 115200); +	} else { +		/* Connect TM to the device */ +		skytraq_write(fd, "U\n", 2); +	} + +	/* Wait for the device to stabilize after baud rate changes */ +	for (c = 0; c < 6; c++) { +		skytraq_flush(fd); +		sleep(1); +	} + +	if (query) { +		uint8_t	query_reply[14]; + +		uint8_t		software_type; +		uint32_t	kernel_version; +		uint32_t	odm_version; +		uint32_t	revision; + +		skytraq_write(fd, query_version, 9); +		if (skytraq_wait_reply(fd, 0x80, query_reply, sizeof (query_reply)) != 0) { +			fprintf(stderr, "query reply failed\n"); +			exit(1); +		} + +#define i8(o)	query_reply[(o)-1] +#define i32(o)	((i8(o) << 24) | (i8(o+1) << 16) | (i8(o+2) << 8) | (i8(o+3))) +		software_type = i8(2); +		kernel_version = i32(3); +		odm_version = i32(7); +		revision = i32(11); +		skytraq_dbg_printf(0, "\n"); +		printf ("Software Type %d. Kernel Version %d.%d.%d. ODM Version %d.%d.%d. Revision %d.%d.%d.\n", +			software_type, +			kernel_version >> 16 & 0xff, +			kernel_version >> 8 & 0xff, +			kernel_version >> 0 & 0xff, +			odm_version >> 16 & 0xff, +			odm_version >> 8 & 0xff, +			odm_version >> 0 & 0xff, +			revision >> 16 & 0xff, +			revision >> 8 & 0xff, +			revision >> 0 & 0xff); +		exit(0); +	} + +	if (!file) +		usage(argv[0]); + +	ret = skytraq_send_srec(fd, "srec_115200.bin"); +	skytraq_dbg_printf (0, "srec ret %d\n", ret); +	if (ret < 0) +		exit(1); + +	sleep(2); + +//	ret = skytraq_send_bin(fd, "STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin"); +	ret = skytraq_send_bin(fd, "STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin"); + +	printf ("bin ret %d\n", ret); +	if (ret < 0) +		exit(1); + +	return 0; +} diff --git a/ao-tools/ao-sky-flash/sky_flash.h b/ao-tools/ao-sky-flash/sky_flash.h new file mode 100644 index 00000000..77f4c742 --- /dev/null +++ b/ao-tools/ao-sky-flash/sky_flash.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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. + */ + +/* sky_serial.c */ + +extern int	skytraq_open_time; +extern int	skytraq_verbose; + +int +skytraq_open(const char *path); + +int +skytraq_setspeed(int fd, int baud); + +int +skytraq_setcomm(int fd, int baudrate); + +int +skytraq_write(int fd, const char *data, int len); + +int +skytraq_waitchar(int fd, int timeout); + +int +skytraq_waitstatus(int fd, const char *status, int timeout); + +void +skytraq_flush(int fd); + +int +skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout); + +int +skytraq_cmd_nowait(int fd, const char *message, int len); + +/* sky_debug.c */ + +void +skytraq_dbg_printf(int input, const char *fmt, ...); + +void +skytraq_dbg_buf(int input, const char *buf, int len); + +void +skytraq_dbg_char(int input, char c); + +/* sky_srec.c */ +int +skytraq_send_srec(int fd, const char *file); + +/* sky_bin.c */ +int +skytraq_send_bin(int fd, const char *filename); diff --git a/ao-tools/ao-sky-flash/sky_serial.c b/ao-tools/ao-sky-flash/sky_serial.c new file mode 100644 index 00000000..7230bf8c --- /dev/null +++ b/ao-tools/ao-sky-flash/sky_serial.c @@ -0,0 +1,257 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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. + */ + +#define _BSD_SOURCE +#include <termios.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <poll.h> +#include "sky_flash.h" +#include <stdio.h> +#include <sys/time.h> +#include <stdint.h> +#include <unistd.h> +#include <stdarg.h> + +int	skytraq_verbose = 1; + +int +skytraq_setspeed(int fd, int baud) +{ +	int	b; +	int	ret; +	struct termios	term; + +	switch (baud) { +	case 9600: +		b = B9600; +		break; +	case 38400: +		b = B38400; +		break; +	case 115200: +		b = B115200; +		break; +	default: +		fprintf (stderr, "Invalid baudrate %d\n", baud); +		return -1; +	} +	ret = tcgetattr(fd, &term); +	cfmakeraw(&term); +#ifdef USE_POLL +	term.c_cc[VMIN] = 1; +	term.c_cc[VTIME] = 0; +#else +	term.c_cc[VMIN] = 0; +	term.c_cc[VTIME] = 1; +#endif + +	cfsetspeed(&term, b); + +	ret = tcsetattr(fd, TCSAFLUSH, &term); +	return ret; +} + +int	skytraq_open_time; + +int +skytraq_open(const char *path) +{ +	int		fd; +	int		ret; + +	fd = open(path, O_RDWR | O_NOCTTY); +	if (fd < 0) { +		perror (path); +		return -1; +	} + +	ret = skytraq_setspeed(fd, 9600); +	if (ret < 0) { +		close (fd); +		return -1; +	} +	skytraq_open_time = skytraq_millis(); +	return fd; +} + + +#define BAUD		57600 +#define BPS		(BAUD/10 * 9/10) +#define US_PER_CHAR	(1000000 / BPS) + +int +skytraq_write(int fd, const char *data, int len) +{ +	const char *d = data; +	int		r; +	int		us; + +	skytraq_dbg_printf (0, "%4d: ", len); +	if (len < 70) +		skytraq_dbg_buf(0, data, len); +	while (len) { +		int	this_time = len; +		if (this_time > 128) +			this_time = 128; +		skytraq_dbg_printf(0, "."); +		fflush(stdout); +		r = write(fd, data, this_time); +		if (r <= 0) +			return r; +		us = r * US_PER_CHAR; +		usleep(r * US_PER_CHAR); +		data += r; +		len -= r; +	} +	skytraq_dbg_newline(); +	return 1; +} + +int +skytraq_setcomm(int fd, int baudrate) +{ +	uint8_t	msg[11]; +	int	i; +	uint8_t	cksum; + +	int target_baudrate; +	switch(baudrate) +	{ +	case 4800: +		target_baudrate=0; +		break; +	case 9600: +		target_baudrate=1; +		break; +	case 19200: +		target_baudrate=2; +		break; +	case 38400: +		target_baudrate=3; +		break; +	case 57600: +		target_baudrate=4; +		break; +	case 115200: +		target_baudrate=5; +		break; +	case 230400: +		target_baudrate=6; +		break; +	} +	msg[0] = 0xa0;	/* header */ +	msg[1] = 0xa1; +	msg[2] = 0x00;	/* length */ +	msg[3] = 0x04; +	msg[4] = 0x05;	/* configure serial port */ +	msg[5] = 0x00;	/* COM 1 */ +	msg[6] = target_baudrate; +	msg[7] = 0x00;	/* update to SRAM only */ + +	cksum = 0; +	for (i = 4; i < 8; i++) +		cksum ^= msg[i]; +	msg[8] = cksum; +	msg[9] = 0x0d; +	msg[10] = 0x0a; +	return skytraq_write(fd, msg, 11); +} + +int +skytraq_waitchar(int fd, int timeout) +{ +	struct pollfd	fds[1]; +	int		ret; +	unsigned char	c; + +	for (;;) { +		fds[0].fd = fd; +		fds[0].events = POLLIN; +		ret = poll(fds, 1, timeout); +		if (ret >= 1) { +			if (fds[0].revents & POLLIN) { +				ret = read(fd, &c, 1); +				if (ret == 1) { +					skytraq_dbg_char(1, c); +					return c; +				} +			} +		} else if (ret == 0) +			return -2; +		else { +			perror("poll"); +			return -1; +		} +	} +} + +int +skytraq_waitstatus(int fd, const char *status, int timeout) +{ +	const char	*s; +	int		c; + +	for (;;) { +		c = skytraq_waitchar(fd, timeout); +		if (c < 0) { +			skytraq_dbg_newline(); +			return c; +		} +		if ((char) c == *status) { +			s = status + 1; +			for (;;) { +				c = skytraq_waitchar(fd, timeout); +				if (c < 0) { +					skytraq_dbg_newline(); +					return c; +				} +				if ((char) c != *s) +					break; +				if (!*s) { +					skytraq_dbg_newline(); +					return 0; +				} +				s++; +			} +		} +	} +} + +void +skytraq_flush(int fd) +{ +	while (skytraq_waitchar(fd, 1) >= 0) +		; +} + +int +skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout) +{ +	skytraq_flush(fd); +	skytraq_write(fd, message, len); +	return skytraq_waitstatus(fd, status, timeout); +} + +int +skytraq_cmd_nowait(int fd, const char *message, int len) +{ +	skytraq_flush(fd); +	return skytraq_write(fd, message, len); +} diff --git a/ao-tools/ao-sky-flash/sky_srec.c b/ao-tools/ao-sky-flash/sky_srec.c new file mode 100644 index 00000000..6d00f58c --- /dev/null +++ b/ao-tools/ao-sky-flash/sky_srec.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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 "sky_flash.h" +#include <stdio.h> +#include <string.h> + +static const char loader_start[] = "$LOADER DOWNLOAD"; + +int +skytraq_send_srec(int fd, const char *filename) +{ +	FILE	*file; +	int	ret; +	char	line[1024]; + +	file = fopen(filename, "r"); +	if (!file) { +		perror(filename); +		return -1; +	} + +	ret = skytraq_cmd_wait(fd, loader_start, strlen(loader_start) + 1, "OK", 1000); +	if (ret) +		return ret; + +	for (;;) { +		char	*s; +		int	len; + +		s = fgets(line, sizeof(line), file); +		if (!s) +			break; +		len = strlen(s); +		if (len < 3)		/* Terminated with \r\n */ +			break; +		s[len-2] = '\n';	/* Smash \r */ +		s[len-1] = '\0';	/* Smash \n */ +		skytraq_cmd_nowait(fd, s, len); +	} +	fclose(file); + +	ret = skytraq_waitstatus(fd, "END", 10000); +	skytraq_dbg_newline(); +	return ret; +} diff --git a/ao-tools/ao-sky-flash/srec_115200.bin b/ao-tools/ao-sky-flash/srec_115200.bin new file mode 100644 index 00000000..8ea8e7cd --- /dev/null +++ b/ao-tools/ao-sky-flash/srec_115200.bin @@ -0,0 +1,346 @@ +S0130000666C6173683131353230302E73726563DA
 +S31550000000033FFFF7821063209DE380011920000013
 +S31550000010D2030000173FFFF79612E3E4AC07BFF890
 +S31550000020D225800BD005800B133FFFC0900A0009E4
 +S3155000003090122977D0230000E00320901B0800136C
 +S31550000040C0232090D20320149E136018D225800B13
 +S31550000050D005800B1300180090120009900A3FF04B
 +S31550000060D0232014D20300001100003FD225800B6C
 +S31550000070D405800B901223FF940A800813043E0087
 +S3155000008094128009D4230000D003C0009A13601C38
 +S31550000090D025800BD205800B11004000902A4008D5
 +S315500000A0D023C000D403400011000040D425800B5B
 +S315500000B0D205800BA00C204092124008A13C20068D
 +S315500000C011140005E02A2180D2234000B8102000E8
 +S315500000D0400004C890102005130004004000017031
 +S315500000E090102001213FFFF84000036F90058010CB
 +S315500000F0A014200A92058010B6102000B4102000DB
 +S31550000100A6102000AE10200096102000D00A400005
 +S3155000011080A2202002800006920260019602E00131
 +S3155000012080A2E06324BFFFFBD00A40009810200055
 +S3155000013080A3000B1680000F113FFFF89012200A83
 +S31550000140940580089810000B912CE0029002001341
 +S31550000150D20A8000912A200190020009A6023FD0BF
 +S3155000016098833FFF12BFFFF99402A0019810000B2D
 +S315500001709205800C113FFFF894024008961020001B
 +S315500001809002800BD20A201680A2602002800007BF
 +S3155000019080A2E0009602E00180A2E06304BFFFFA6D
 +S315500001A09002800B80A2E0000480000F113FFFF800
 +S315500001B09205800C9012201698024008900DE0FF90
 +S315500001C0932A2002D40B000092024008932A600121
 +S315500001D094028009AE02BFD09682FFFF12BFFFF88D
 +S315500001E098032001133FFFF794126384921263869B
 +S315500001F090078009400001A89207800A80A220003B
 +S3155000020002800122153FFFF79012A386D21780086D
 +S3155000021080A2601C0280010E9012A384113FFFF74A
 +S31550000220961223849012238692102037D237800854
 +S31550000230941020B5D437800B900F2001213FFFF743
 +S31550000240AB2A201392142386110001E1D41780099A
 +S3155000025090122154A2142384A4054008D617801165
 +S3155000026090100012400002289210202080A22000F8
 +S31550000270028000CA11140005B0100010B21000110F
 +S31550000280A0102000113FFFEA80A420000280000445
 +S315500002909212225511000015921221AA912A60102D
 +S315500002A0A8162386A3322010D617801990048010E2
 +S315500002B0D417801492102002400001DA98100011D1
 +S315500002C080A22000028000B511140005D0148010C1
 +S315500002D080A44008128000B0A004200280A420030D
 +S315500002E004BFFFEA113FFFEA213FFFF79214238430
 +S315500002F0D617800990100012D417801440000202BD
 +S3155000030092102020170001DF9012E3F8D20200006D
 +S31550000310941423E4D225800AA01423E0C02580102B
 +S31550000320D005800A80A23FFF228000BB9012E3FCDA
 +S31550000330113FFFF7A2122384A0122386110001C198
 +S31550000340D417801090122154D61780119210202065
 +S31550000350400001ED90054008110001E9D4178010C6
 +S3155000036090122154D617801192102020400001E699
 +S3155000037090054008110001F1D417801090122154B5
 +S31550000380D617801192102020400001DF90054008BA
 +S31550000390133FFFF8D00D800980A220421280000B37
 +S315500003A0A410001392058009D00A600180A220494A
 +S315500003B03280000721140005D00A600280A2204E28
 +S315500003C022800008D417801021140005400002F640
 +S315500003D09014202890142028400002F39E03FCF02D
 +S315500003E090102000D6178011400001C792100013BC
 +S315500003F080A2200022800069111400051114000506
 +S31550000400400002E990122030400000BE010000007A
 +S3155000041011000007A81223FFB010001480A4801406
 +S31550000420148000031300000892100012113FFFF8C9
 +S315500004304000036F90058008A2922000028000734E
 +S31550000440A010200080A40011B40680111A8000214B
 +S31550000450A4248011333FFFF71100003FAA1223FF57
 +S31550000460BA1663849810001092102000A00420023F
 +S31550000470173FFFF89005800CD40A000B932A6008AA
 +S315500004809803200180A3001006BFFFFB9212400A7A
 +S31550000490912A60109932201080A300150280000A1C
 +S315500004A090166386D417800892102002D617801DA6
 +S315500004B04000015C9010001B80A220000280003793
 +S315500004C01114000580A400110ABFFFE7B606E0022A
 +S315500004D0900E801880A0000892603FFF80A0001206
 +S315500004E090603FFF809240080280000680A68013ED
 +S315500004F011140005400002AC9012203080A68013E3
 +S3155000050012BFFFC880A480149410200080A28013CC
 +S315500005101680000996102000D21280009132600891
 +S315500005209002C0089402A00280A2801306BFFFFB6F
 +S3155000053096020009920AE0FF900DE0FF80A2400863
 +S31550000540028000041114000510BFFFA49012203839
 +S31550000550153FFFF79012A3E0D205800880A26001F4
 +S31550000560128000109212A3849012A386D41780088A
 +S3155000057098102A01D6178009110001DF901223FC2A
 +S31550000580400001289210200280A22000128000060E
 +S31550000590211400051114000510BFFF909012202061
 +S315500005A02114000540000280901420404000027E35
 +S315500005B090142040901020F013080013D0302000E3
 +S315500005C092126020D012400015200000900A3FFE83
 +S315500005D0D03240009612A04C90102010D022C0006D
 +S315500005E0D802C0009412A0B813080004D822800084
 +S315500005F092126014D0024000900A3FFED022400072
 +S3155000060010800000010000001114000510BFFF7398
 +S3155000061090122048D20200001102807FD225800A13
 +S31550000620901223FFD0258010D205800AD005801065
 +S3155000063080A2400832BFFF40113FFFF790102001C3
 +S31550000640D025801010BFFF3C113FFFF7D61780080A
 +S31550000650921AE0B980A0000994603FFF901AE0DA40
 +S3155000066080A0000892603FFF8092800902BFFEED95
 +S31550000670113FFFF780A2E0DA22BFFEF0B81020014A
 +S3155000068010BFFEEF900F20012114000540000246D6
 +S315500006909014205030BFFFFE01000000941020F04F
 +S315500006A019080013D430200098132020170800048E
 +S315500006B0D41300008212E01417200000940ABFFEE3
 +S315500006C09A12E0B8D4330000900A20FF9612E04CFC
 +S315500006D0D222C00080A22001128000070100000033
 +S315500006E0D202C000D2234000D0004000900A3FFE04
 +S315500006F0D02040000100000081C3E0080100000046
 +S315500007001308000492126014D00240009012200187
 +S31550000710D02240000100000081C3E0080100000023
 +S315500007209C03BF90D233A066D213A06696100008E1
 +S31550000730920A6080D012000080A0000994402000E8
 +S31550000740900A208080A000089240200080A2400A93
 +S315500007500280000D01000000D012C000808A2020C7
 +S315500007601280000901000000D012C000900A2080BB
 +S3155000077080A000089240200080A2400A12BFFFF7D6
 +S3155000078001000000D012C000900A208080A000080E
 +S3155000079090402000901A000A901A20010100000093
 +S315500007A081C3E0089C23BF909DE3BF90B20E60FFCB
 +S315500007B0A0100018C027BFF480A660BA14800006A7
 +S315500007C080A660DA80A660B916800006153FFFEA5B
 +S315500007D080A660B512800027B0102000153FFFEAB2
 +S315500007E096102AAA9412A2AA13000015D432C00059
 +S315500007F09212615598102554113FFFE0D2330000F4
 +S3155000080090122080D032C000D432C000D2330000C3
 +S315500008101100000C2300003F90122030130000C33B
 +S31550000820D0340000A412613FB21463FF921463FFE8
 +S315500008307FFFFFBC90100010B0100008D007BFF427
 +S3155000084090022001D027BFF4D214000080A64009A0
 +S315500008500280000880A620011280000601000000D8
 +S31550000860D007BFF480A2001208BFFFF2921463FFB4
 +S31550000870D007BFF4130000C39212613F80A2400814
 +S3155000088094403FFFB00E000A0100000081C7E00807
 +S3155000089081E80000153FFFEA98102AAA9412A2AAEE
 +S315500008A0D4330000170000159612E155153FFFE4AA
 +S315500008B0D63025549412A090D4330000D61022007E
 +S315500008C09A100008960AE0FFD6320000901030F0D9
 +S315500008D0D0330000D613400098100009901AE03724
 +S315500008E080A0000894603FFF901AE01C80A000088A
 +S315500008F092603FFF8092800912800007821020008C
 +S3155000090080A2E0C20280000480A2E0201280004251
 +S3155000091090102000113FFFEA94102AAA901222AAA2
 +S31550000920D03280001300001592126155113FFFE43A
 +S31550000930D230255490122090D0328000D21022020C
 +S31550000940901030F0920A60FFD2330000D03280000F
 +S31550000950D013400080A220370280002A80A2202097
 +S31550000960D41300000280001D912AA0109002BF47A8
 +S31550000970912A201091322010952AA01080A2200290
 +S315500009809532A01092602000901AA0B580A0000861
 +S31550000990920A600190603FFF809240083280000BBF
 +S315500009A08210200180A2A0B90280000A80A2A0BABB
 +S315500009B00280000880A2A0EF0280000680A2A0DA82
 +S315500009C02280000282102001108000139010000136
 +S315500009D010BFFFFE821020019132201080A220EE1F
 +S315500009E012BFFFE49002BF479010201CD033400046
 +S315500009F0921020B9D233000010BFFFDD941020B9F9
 +S31550000A00D413000080A2A03402BFFFF880A2202099
 +S31550000A1030BFFFD50100000081C3E008010000008F
 +S31550000A209DE3BF88B72EE010C037BFF4B736E0104D
 +S31550000A30A0100018C027BFEC80A6E0BA14800006AC
 +S31550000A4080A6E0DA80A6E0B916800006113FFFEADC
 +S31550000A5080A6E0B512800023B0102000113FFFEAB7
 +S31550000A6094102AAA901222AAD032800013000015A0
 +S31550000A7092126155113FFFE8D2302554901220A0B2
 +S31550000A80D0328000F837BFF2D017BFF2130000C340
 +S31550000A90D0340000B612613FD217BFF27FFFFF215C
 +S31550000AA090100010B0100008D007BFEC9002200143
 +S31550000AB0D027BFECD2140000D017BFF280A2000995
 +S31550000AC00280000880A62001128000060100000066
 +S31550000AD0D007BFEC80A2001B08BFFFF0010000004A
 +S31550000AE0D007BFEC130000C39212613F80A24008AA
 +S31550000AF094403FFFB00E000A0100000081C7E00895
 +S31550000B0081E800009DE3BF9811140005D4022150DE
 +S31550000B10A210200080A4400AA410001B9A102000A6
 +S31550000B20A0102000A610200116800012961020005A
 +S31550000B30912EA010B5322010932EE0109810000A76
 +S31550000B40111400059332601094122060D002A00C4C
 +S31550000B5080A2001A22800048D002A0109602E0011E
 +S31550000B6080A2C00C06BFFFFA9402A05011140005D3
 +S31550000B70D202215080A2C009028000449010200168
 +S31550000B8080A6200008800016912AE0029002000BF1
 +S31550000B9013140005B4126060992A20049E10200197
 +S31550000BA0912C200290020010912A200290030008F6
 +S31550000BB09002001AD4022004A2046001D202200836
 +S31550000BC080A4400A932BC0099A034009A0643FFFB2
 +S31550000BD080A6000D18BFFFF4912C200280A660005D
 +S31550000BE00480001F932AE0029202400BB60CA0FF2D
 +S31550000BF011140005A4122060B52A60049210001B3F
 +S31550000C007FFFFEEA90100018932C200292024010AB
 +S31550000C10932A6002920680099402401280A2200014
 +S31550000C2002800013A2046001D202A0089010200195
 +S31550000C30912A000980A64008B00600080680000ADE
 +S31550000C40B2264008D002A00480A44008A0643FFF0A
 +S31550000C5080A6600014BFFFEB9210001B1080000BA3
 +S31550000C6090100013108000099010200110BFFFFC57
 +S31550000C70A610200080A2000932BFFFBA9602E001FA
 +S31550000C8010BFFFBC1114000581C7E00891E80008A9
 +S31550000C9013140005D40A61801708000013000013CE
 +S31550000CA09212630C952AA00294028009D202C00ABD
 +S31550000CB0941000089132601F80A22001028000002B
 +S31550000CC09132601D808A20012280000490102001FC
 +S31550000CD0C022800030800002D022800081C3E0080C
 +S31550000CE09010000911140005D20A21801508000041
 +S31550000CF0110000139012230C932A600292024008AE
 +S31550000D00D20280099132601F80A220010280000029
 +S31550000D100100000081C3E008901000099DE3BF90D8
 +S31550000D2011140005E00A2180B00E20FF11140005B1
 +S31550000D3090122154B12E2002E2020018A12C20025A
 +S31550000D40110000139012230CA00400087FFFFFD15E
 +S31550000D509007BFF4D207BFF411060000932A601E15
 +S31550000D60921240112308000092124008D2244010DB
 +S31550000D707FFFFFC89007BFF4D207BFF411070000EA
 +S31550000D80932A601E92124008D22440107FFFFFC162
 +S31550000D909007BFF4D207BFF411030000932A601ED8
 +S31550000DA092124008D22440107FFFFFBA9007BFF43A
 +S31550000DB0D207BFF41104000090122003932A601E3C
 +S31550000DC092124008D22440107FFFFFB29007BFF422
 +S31550000DD0D207BFF411050000932A601E92124008F4
 +S31550000DE0D22440107FFFFFC0010000000100000028
 +S31550000DF081C7E00881E800009DE3BF90111400050B
 +S31550000E00E00A218025080000110000139012230CDF
 +S31550000E10A12C2002A00400087FFFFF9E9007BFF47C
 +S31550000E20D207BFF411050000932A601E92124008A3
 +S31550000E30D22480107FFFFF979007BFF4A2100008BE
 +S31550000E40D007BFF427040000912A201E90120013E9
 +S31550000E50D02480107FFFFF8F9007BFF4D207BFF4D6
 +S31550000E6011040004932A601E92124008D224801066
 +S31550000E707FFFFF889007BFF4D007BFF4A20C60FF36
 +S31550000E80912A201E9012001190120013D024801027
 +S31550000E907FFFFF95010000000100000081C7E008B8
 +S31550000EA081E800009DE3BF9011140005D20A21800D
 +S31550000EB02708000011000013932A60029012230C99
 +S31550000EC09202400893326002AC100009AB2A6002CD
 +S31550000ED0AE1000097FFFFF6F9007BFF4D007BFF435
 +S31550000EE023030000912A201E90120011D024C01511
 +S31550000EF07FFFFF7D0100000091322016A08A200F4F
 +S31550000F0032800011A2102000A4100011A32DA002BF
 +S31550000F107FFFFF609007BFF4D207BFF4932A601E8D
 +S31550000F2092124012D224C0117FFFFF6F01000000C1
 +S31550000F3091322016A08A200F02BFFFF60100000052
 +S31550000F40A210200080A440101ABFFFE3A52DE00296
 +S31550000F50290100007FFFFF4F9007BFF4D007BFF471
 +S31550000F60A2046001912A201E90120014D024C012AF
 +S31550000F707FFFFF5D01000000D02E0000808A20FF19
 +S31550000F8002800006B006200180A440100ABFFFF27E
 +S31550000F900100000030BFFFD00100000081C7E0080B
 +S31550000FA081E800009DE3BF9011140005D20A21800C
 +S31550000FB025080000D40E000011000013932A600289
 +S31550000FC09012230C80A2A000028000849202400856
 +S31550000FD0AD2A60109135A012A72A2002AA10000847
 +S31550000FE0A81000137FFFFF2B9007BFF4D007BFF464
 +S31550000FF021030000912A201E90120010D024801345
 +S315500010007FFFFF3901000000900A200680A22006CB
 +S315500010100280001001000000A2100010A12D6002F5
 +S315500010207FFFFF1C9007BFF4D207BFF4932A601EC0
 +S3155000103092124011D22480107FFFFF2B0100000036
 +S31550001040900A200680A2200612BFFFF6010000007B
 +S315500010507FFFFF109007BFF4D007BFF4D20E0000F9
 +S31550001060912A201E90120009D02480147FFFFF1E63
 +S31550001070B0062001D00E000080A2200012BFFFDA79
 +S31550001080010000009135A010D404800880A2A00071
 +S315500010900680004C010000009132A01D808A20017C
 +S315500010A00280004690102001C027BFF4D007BFF43D
 +S315500010B013030000912A201E901200099335A010A8
 +S315500010C0D0248009D404800980A2A0000680003470
 +S315500010D0900AA00680A22006028000169135A01222
 +S315500010E09A1000089E102001972A2002190300002A
 +S315500010F09132A01D808A2001128000039210200098
 +S315500011009210000F912A601E9012000CD024800B72
 +S31550001110D404800B80A2A0000680001A900AA00674
 +S3155000112080A2200612BFFFF49132A01DD227BFF431
 +S315500011309132A01D808A200102800010901020015B
 +S31550001140C027BFF4D007BFF49335A010912A201EB4
 +S31550001150D0248009D404800980A2A00016800021E2
 +S3155000116090100009D404800880A2A00006BFFFFE9C
 +S31550001170010000003080001B10BFFFF3D027BFF4E2
 +S31550001180912B6002D404800880A2A00006BFFFFE07
 +S315500011900100000010BFFFE3900AA006901000095E
 +S315500011A0D404800880A2A00006BFFFFE0100000004
 +S315500011B010BFFFC9900AA00610BFFFBDD027BFF4CD
 +S315500011C0D404800880A2A00006BFFFFE01000000E4
 +S315500011D010BFFFB39132A01D10BFFFABAD2A6010F8
 +S315500011E00100000081C7E00881E800009DE3BF9838
 +S315500011F035140005F60EA180921000183500001324
 +S31550001200B416A30CB72EE002B606C01A992EE010FB
 +S31550001210B53320129B2EA002A210001AA610001958
 +S315500012203B080000961020009410000DA410001AE0
 +S31550001230F807400D80A7200006800064B137201DB6
 +S31550001240B00E200180A00018B0603FFFB12E201EC6
 +S3155000125033030000B0160019F027400AF807400A79
 +S3155000126080A7200006800052B1372016B48E200F7A
 +S315500012701280001A82102000B3332012310003D09E
 +S31550001280901000199E162240B32E600237030000BC
 +S3155000129080A0400F8200600118800053B0102000DB
 +S315500012A0B137201DB00E200180A00018B0603FFF5E
 +S315500012B0B12E201EB016001BF0274019F807401912
 +S315500012C080A7200006800033B1372016B48E200F39
 +S315500012D002BFFFF180A0400F8210200080A0401A6C
 +S315500012E01ABFFFD4B1332012B72E20029010001827
 +S315500012F09E10001BA0100018F807401B80A7200066
 +S315500013000680001DB137201DB00E200180A00018A8
 +S31550001310B0603FFFB12E201E33010000B0160019F9
 +S31550001320F027400FF807400F80A720000680000CDA
 +S31550001330B12C20029602E001F82A400080A2C01388
 +S3155000134002800029B010000B8200600180A0401A74
 +S315500013500ABFFFEA9202600130BFFFB6F807401895
 +S3155000136080A7200006BFFFFE0100000010BFFFF35C
 +S315500013709602E001B12A2002F807401880A7200003
 +S3155000138006BFFFFE0100000010BFFFE0B137201D71
 +S31550001390B12A2002F807401880A7200006BFFFFE9A
 +S315500013A00100000010BFFFCAB1372016B12CA002B1
 +S315500013B0F807401880A7200006BFFFFE0100000076
 +S315500013C010BFFFABB1372016B12C6002F80740189A
 +S315500013D080A7200006BFFFFE0100000010BFFF9946
 +S315500013E0B137201D0100000081C7E00881E80000E8
 +S315500013F09DE3BF987FFFFE81B00E20FF7FFFFE4822
 +S3155000140081E800000100000000000000000000001C
 +S315500014100000000000000000000000000000000076
 +S315500014204572726F723400004572726F72330000EB
 +S315500014304F4B0000000000004572726F7232000080
 +S31550001440454E4400000000004572726F7235000030
 +S315500014504572726F723100000000000000000000FB
 +S3155000146000000000000000010000000E00000037E0
 +S31550001470000000B500004000000000030000000D11
 +S3155000148000000037000000B5000080000000000496
 +S315500014900000000F00000037000000B500010000FA
 +S315500014A00000000B0000001000000037000000B5DF
 +S315500014B00000000000000007000000100000001CA3
 +S315500014C0000000B900007000000000080000000F86
 +S315500014D00000001C000000B9000078000000000A5F
 +S315500014E00000000D0000001C000000B900007C0048
 +S315500014F00000000B0000000E0000001C000000B9A8
 +S31550001500000000000000000F000000100000001C4A
 +S31550001510000000DA00007000000000100000000F0C
 +S315500015200000001C000000DA0000700000000012ED
 +S315500015300000000D0000001C000000DA00007000E2
 +S31550001540000000130000000E0000001C000000DA2E
 +S3155000155000000003000001AA000000D50000006A48
 +S3155000156000000035000000230000001100000008B4
 +S3115000157000000000000000000000000019
 +S70550000000AA
 diff --git a/ao-tools/ao-sky-flash/srec_9600.bin b/ao-tools/ao-sky-flash/srec_9600.bin new file mode 100644 index 00000000..9a29ab1b --- /dev/null +++ b/ao-tools/ao-sky-flash/srec_9600.bin @@ -0,0 +1,346 @@ +S0190000666C6173685F3139646F74355F393630302E737265638A
 +S31550000000033FFFF7821063209DE380011920000013
 +S31550000010D2030000173FFFF79612E3E4AC07BFF890
 +S31550000020D225800BD005800B133FFFC0900A0009E4
 +S3155000003090122977D0230000E00320901B0800136C
 +S31550000040C0232090D20320149E136018D225800B13
 +S31550000050D005800B1300180090120009900A3FF04B
 +S31550000060D0232014D20300001100003FD225800B6C
 +S31550000070D405800B901223FF940A800813043E0087
 +S3155000008094128009D4230000D003C0009A13601C38
 +S31550000090D025800BD205800B11004000902A4008D5
 +S315500000A0D023C000D403400011000040D425800B5B
 +S315500000B0D205800BA00C204092124008A13C20068D
 +S315500000C011140005E02A2180D2234000B8102000E8
 +S315500000D0400004C890102001130004004000017035
 +S315500000E090102001213FFFF84000036F90058010CB
 +S315500000F0A014200A92058010B6102000B4102000DB
 +S31550000100A6102000AE10200096102000D00A400005
 +S3155000011080A2202002800006920260019602E00131
 +S3155000012080A2E06324BFFFFBD00A40009810200055
 +S3155000013080A3000B1680000F113FFFF89012200A83
 +S31550000140940580089810000B912CE0029002001341
 +S31550000150D20A8000912A200190020009A6023FD0BF
 +S3155000016098833FFF12BFFFF99402A0019810000B2D
 +S315500001709205800C113FFFF894024008961020001B
 +S315500001809002800BD20A201680A2602002800007BF
 +S3155000019080A2E0009602E00180A2E06304BFFFFA6D
 +S315500001A09002800B80A2E0000480000F113FFFF800
 +S315500001B09205800C9012201698024008900DE0FF90
 +S315500001C0932A2002D40B000092024008932A600121
 +S315500001D094028009AE02BFD09682FFFF12BFFFF88D
 +S315500001E098032001133FFFF794126384921263869B
 +S315500001F090078009400001A89207800A80A220003B
 +S3155000020002800122153FFFF79012A386D21780086D
 +S3155000021080A2601C0280010E9012A384113FFFF74A
 +S31550000220961223849012238692102037D237800854
 +S31550000230941020B5D437800B900F2001213FFFF743
 +S31550000240AB2A201392142386110001E1D41780099A
 +S3155000025090122154A2142384A4054008D617801165
 +S3155000026090100012400002289210202080A22000F8
 +S31550000270028000CA11140005B0100010B21000110F
 +S31550000280A0102000113FFFEA80A420000280000445
 +S315500002909212225511000015921221AA912A60102D
 +S315500002A0A8162386A3322010D617801990048010E2
 +S315500002B0D417801492102002400001DA98100011D1
 +S315500002C080A22000028000B511140005D0148010C1
 +S315500002D080A44008128000B0A004200280A420030D
 +S315500002E004BFFFEA113FFFEA213FFFF79214238430
 +S315500002F0D617800990100012D417801440000202BD
 +S3155000030092102020170001DF9012E3F8D20200006D
 +S31550000310941423E4D225800AA01423E0C02580102B
 +S31550000320D005800A80A23FFF228000BB9012E3FCDA
 +S31550000330113FFFF7A2122384A0122386110001C198
 +S31550000340D417801090122154D61780119210202065
 +S31550000350400001ED90054008110001E9D4178010C6
 +S3155000036090122154D617801192102020400001E699
 +S3155000037090054008110001F1D417801090122154B5
 +S31550000380D617801192102020400001DF90054008BA
 +S31550000390133FFFF8D00D800980A220421280000B37
 +S315500003A0A410001392058009D00A600180A220494A
 +S315500003B03280000721140005D00A600280A2204E28
 +S315500003C022800008D417801021140005400002F640
 +S315500003D09014202890142028400002F39E03FCF02D
 +S315500003E090102000D6178011400001C792100013BC
 +S315500003F080A2200022800069111400051114000506
 +S31550000400400002E990122030400000BE010000007A
 +S3155000041011000007A81223FFB010001480A4801406
 +S31550000420148000031300000892100012113FFFF8C9
 +S315500004304000036F90058008A2922000028000734E
 +S31550000440A010200080A40011B40680111A8000214B
 +S31550000450A4248011333FFFF71100003FAA1223FF57
 +S31550000460BA1663849810001092102000A00420023F
 +S31550000470173FFFF89005800CD40A000B932A6008AA
 +S315500004809803200180A3001006BFFFFB9212400A7A
 +S31550000490912A60109932201080A300150280000A1C
 +S315500004A090166386D417800892102002D617801DA6
 +S315500004B04000015C9010001B80A220000280003793
 +S315500004C01114000580A400110ABFFFE7B606E0022A
 +S315500004D0900E801880A0000892603FFF80A0001206
 +S315500004E090603FFF809240080280000680A68013ED
 +S315500004F011140005400002AC9012203080A68013E3
 +S3155000050012BFFFC880A480149410200080A28013CC
 +S315500005101680000996102000D21280009132600891
 +S315500005209002C0089402A00280A2801306BFFFFB6F
 +S3155000053096020009920AE0FF900DE0FF80A2400863
 +S31550000540028000041114000510BFFFA49012203839
 +S31550000550153FFFF79012A3E0D205800880A26001F4
 +S31550000560128000109212A3849012A386D41780088A
 +S3155000057098102A01D6178009110001DF901223FC2A
 +S31550000580400001289210200280A22000128000060E
 +S31550000590211400051114000510BFFF909012202061
 +S315500005A02114000540000280901420404000027E35
 +S315500005B090142040901020F013080013D0302000E3
 +S315500005C092126020D012400015200000900A3FFE83
 +S315500005D0D03240009612A04C90102010D022C0006D
 +S315500005E0D802C0009412A0B813080004D822800084
 +S315500005F092126014D0024000900A3FFED022400072
 +S3155000060010800000010000001114000510BFFF7398
 +S3155000061090122048D20200001102807FD225800A13
 +S31550000620901223FFD0258010D205800AD005801065
 +S3155000063080A2400832BFFF40113FFFF790102001C3
 +S31550000640D025801010BFFF3C113FFFF7D61780080A
 +S31550000650921AE0B980A0000994603FFF901AE0DA40
 +S3155000066080A0000892603FFF8092800902BFFEED95
 +S31550000670113FFFF780A2E0DA22BFFEF0B81020014A
 +S3155000068010BFFEEF900F20012114000540000246D6
 +S315500006909014205030BFFFFE01000000941020F04F
 +S315500006A019080013D430200098132020170800048E
 +S315500006B0D41300008212E01417200000940ABFFEE3
 +S315500006C09A12E0B8D4330000900A20FF9612E04CFC
 +S315500006D0D222C00080A22001128000070100000033
 +S315500006E0D202C000D2234000D0004000900A3FFE04
 +S315500006F0D02040000100000081C3E0080100000046
 +S315500007001308000492126014D00240009012200187
 +S31550000710D02240000100000081C3E0080100000023
 +S315500007209C03BF90D233A066D213A06696100008E1
 +S31550000730920A6080D012000080A0000994402000E8
 +S31550000740900A208080A000089240200080A2400A93
 +S315500007500280000D01000000D012C000808A2020C7
 +S315500007601280000901000000D012C000900A2080BB
 +S3155000077080A000089240200080A2400A12BFFFF7D6
 +S3155000078001000000D012C000900A208080A000080E
 +S3155000079090402000901A000A901A20010100000093
 +S315500007A081C3E0089C23BF909DE3BF90B20E60FFCB
 +S315500007B0A0100018C027BFF480A660BA14800006A7
 +S315500007C080A660DA80A660B916800006153FFFEA5B
 +S315500007D080A660B512800027B0102000153FFFEAB2
 +S315500007E096102AAA9412A2AA13000015D432C00059
 +S315500007F09212615598102554113FFFE0D2330000F4
 +S3155000080090122080D032C000D432C000D2330000C3
 +S315500008101100000C2300003F90122030130000C33B
 +S31550000820D0340000A412613FB21463FF921463FFE8
 +S315500008307FFFFFBC90100010B0100008D007BFF427
 +S3155000084090022001D027BFF4D214000080A64009A0
 +S315500008500280000880A620011280000601000000D8
 +S31550000860D007BFF480A2001208BFFFF2921463FFB4
 +S31550000870D007BFF4130000C39212613F80A2400814
 +S3155000088094403FFFB00E000A0100000081C7E00807
 +S3155000089081E80000153FFFEA98102AAA9412A2AAEE
 +S315500008A0D4330000170000159612E155153FFFE4AA
 +S315500008B0D63025549412A090D4330000D61022007E
 +S315500008C09A100008960AE0FFD6320000901030F0D9
 +S315500008D0D0330000D613400098100009901AE03724
 +S315500008E080A0000894603FFF901AE01C80A000088A
 +S315500008F092603FFF8092800912800007821020008C
 +S3155000090080A2E0C20280000480A2E0201280004251
 +S3155000091090102000113FFFEA94102AAA901222AAA2
 +S31550000920D03280001300001592126155113FFFE43A
 +S31550000930D230255490122090D0328000D21022020C
 +S31550000940901030F0920A60FFD2330000D03280000F
 +S31550000950D013400080A220370280002A80A2202097
 +S31550000960D41300000280001D912AA0109002BF47A8
 +S31550000970912A201091322010952AA01080A2200290
 +S315500009809532A01092602000901AA0B580A0000861
 +S31550000990920A600190603FFF809240083280000BBF
 +S315500009A08210200180A2A0B90280000A80A2A0BABB
 +S315500009B00280000880A2A0EF0280000680A2A0DA82
 +S315500009C02280000282102001108000139010000136
 +S315500009D010BFFFFE821020019132201080A220EE1F
 +S315500009E012BFFFE49002BF479010201CD033400046
 +S315500009F0921020B9D233000010BFFFDD941020B9F9
 +S31550000A00D413000080A2A03402BFFFF880A2202099
 +S31550000A1030BFFFD50100000081C3E008010000008F
 +S31550000A209DE3BF88B72EE010C037BFF4B736E0104D
 +S31550000A30A0100018C027BFEC80A6E0BA14800006AC
 +S31550000A4080A6E0DA80A6E0B916800006113FFFEADC
 +S31550000A5080A6E0B512800023B0102000113FFFEAB7
 +S31550000A6094102AAA901222AAD032800013000015A0
 +S31550000A7092126155113FFFE8D2302554901220A0B2
 +S31550000A80D0328000F837BFF2D017BFF2130000C340
 +S31550000A90D0340000B612613FD217BFF27FFFFF215C
 +S31550000AA090100010B0100008D007BFEC9002200143
 +S31550000AB0D027BFECD2140000D017BFF280A2000995
 +S31550000AC00280000880A62001128000060100000066
 +S31550000AD0D007BFEC80A2001B08BFFFF0010000004A
 +S31550000AE0D007BFEC130000C39212613F80A24008AA
 +S31550000AF094403FFFB00E000A0100000081C7E00895
 +S31550000B0081E800009DE3BF9811140005D4022150DE
 +S31550000B10A210200080A4400AA410001B9A102000A6
 +S31550000B20A0102000A610200116800012961020005A
 +S31550000B30912EA010B5322010932EE0109810000A76
 +S31550000B40111400059332601094122060D002A00C4C
 +S31550000B5080A2001A22800048D002A0109602E0011E
 +S31550000B6080A2C00C06BFFFFA9402A05011140005D3
 +S31550000B70D202215080A2C009028000449010200168
 +S31550000B8080A6200008800016912AE0029002000BF1
 +S31550000B9013140005B4126060992A20049E10200197
 +S31550000BA0912C200290020010912A200290030008F6
 +S31550000BB09002001AD4022004A2046001D202200836
 +S31550000BC080A4400A932BC0099A034009A0643FFFB2
 +S31550000BD080A6000D18BFFFF4912C200280A660005D
 +S31550000BE00480001F932AE0029202400BB60CA0FF2D
 +S31550000BF011140005A4122060B52A60049210001B3F
 +S31550000C007FFFFEEA90100018932C200292024010AB
 +S31550000C10932A6002920680099402401280A2200014
 +S31550000C2002800013A2046001D202A0089010200195
 +S31550000C30912A000980A64008B00600080680000ADE
 +S31550000C40B2264008D002A00480A44008A0643FFF0A
 +S31550000C5080A6600014BFFFEB9210001B1080000BA3
 +S31550000C6090100013108000099010200110BFFFFC57
 +S31550000C70A610200080A2000932BFFFBA9602E001FA
 +S31550000C8010BFFFBC1114000581C7E00891E80008A9
 +S31550000C9013140005D40A61801708000013000013CE
 +S31550000CA09212630C952AA00294028009D202C00ABD
 +S31550000CB0941000089132601F80A22001028000002B
 +S31550000CC09132601D808A20012280000490102001FC
 +S31550000CD0C022800030800002D022800081C3E0080C
 +S31550000CE09010000911140005D20A21801508000041
 +S31550000CF0110000139012230C932A600292024008AE
 +S31550000D00D20280099132601F80A220010280000029
 +S31550000D100100000081C3E008901000099DE3BF90D8
 +S31550000D2011140005E00A2180B00E20FF11140005B1
 +S31550000D3090122154B12E2002E2020018A12C20025A
 +S31550000D40110000139012230CA00400087FFFFFD15E
 +S31550000D509007BFF4D207BFF411060000932A601E15
 +S31550000D60921240112308000092124008D2244010DB
 +S31550000D707FFFFFC89007BFF4D207BFF411070000EA
 +S31550000D80932A601E92124008D22440107FFFFFC162
 +S31550000D909007BFF4D207BFF411030000932A601ED8
 +S31550000DA092124008D22440107FFFFFBA9007BFF43A
 +S31550000DB0D207BFF41104000090122003932A601E3C
 +S31550000DC092124008D22440107FFFFFB29007BFF422
 +S31550000DD0D207BFF411050000932A601E92124008F4
 +S31550000DE0D22440107FFFFFC0010000000100000028
 +S31550000DF081C7E00881E800009DE3BF90111400050B
 +S31550000E00E00A218025080000110000139012230CDF
 +S31550000E10A12C2002A00400087FFFFF9E9007BFF47C
 +S31550000E20D207BFF411050000932A601E92124008A3
 +S31550000E30D22480107FFFFF979007BFF4A2100008BE
 +S31550000E40D007BFF427040000912A201E90120013E9
 +S31550000E50D02480107FFFFF8F9007BFF4D207BFF4D6
 +S31550000E6011040004932A601E92124008D224801066
 +S31550000E707FFFFF889007BFF4D007BFF4A20C60FF36
 +S31550000E80912A201E9012001190120013D024801027
 +S31550000E907FFFFF95010000000100000081C7E008B8
 +S31550000EA081E800009DE3BF9011140005D20A21800D
 +S31550000EB02708000011000013932A60029012230C99
 +S31550000EC09202400893326002AC100009AB2A6002CD
 +S31550000ED0AE1000097FFFFF6F9007BFF4D007BFF435
 +S31550000EE023030000912A201E90120011D024C01511
 +S31550000EF07FFFFF7D0100000091322016A08A200F4F
 +S31550000F0032800011A2102000A4100011A32DA002BF
 +S31550000F107FFFFF609007BFF4D207BFF4932A601E8D
 +S31550000F2092124012D224C0117FFFFF6F01000000C1
 +S31550000F3091322016A08A200F02BFFFF60100000052
 +S31550000F40A210200080A440101ABFFFE3A52DE00296
 +S31550000F50290100007FFFFF4F9007BFF4D007BFF471
 +S31550000F60A2046001912A201E90120014D024C012AF
 +S31550000F707FFFFF5D01000000D02E0000808A20FF19
 +S31550000F8002800006B006200180A440100ABFFFF27E
 +S31550000F900100000030BFFFD00100000081C7E0080B
 +S31550000FA081E800009DE3BF9011140005D20A21800C
 +S31550000FB025080000D40E000011000013932A600289
 +S31550000FC09012230C80A2A000028000849202400856
 +S31550000FD0AD2A60109135A012A72A2002AA10000847
 +S31550000FE0A81000137FFFFF2B9007BFF4D007BFF464
 +S31550000FF021030000912A201E90120010D024801345
 +S315500010007FFFFF3901000000900A200680A22006CB
 +S315500010100280001001000000A2100010A12D6002F5
 +S315500010207FFFFF1C9007BFF4D207BFF4932A601EC0
 +S3155000103092124011D22480107FFFFF2B0100000036
 +S31550001040900A200680A2200612BFFFF6010000007B
 +S315500010507FFFFF109007BFF4D007BFF4D20E0000F9
 +S31550001060912A201E90120009D02480147FFFFF1E63
 +S31550001070B0062001D00E000080A2200012BFFFDA79
 +S31550001080010000009135A010D404800880A2A00071
 +S315500010900680004C010000009132A01D808A20017C
 +S315500010A00280004690102001C027BFF4D007BFF43D
 +S315500010B013030000912A201E901200099335A010A8
 +S315500010C0D0248009D404800980A2A0000680003470
 +S315500010D0900AA00680A22006028000169135A01222
 +S315500010E09A1000089E102001972A2002190300002A
 +S315500010F09132A01D808A2001128000039210200098
 +S315500011009210000F912A601E9012000CD024800B72
 +S31550001110D404800B80A2A0000680001A900AA00674
 +S3155000112080A2200612BFFFF49132A01DD227BFF431
 +S315500011309132A01D808A200102800010901020015B
 +S31550001140C027BFF4D007BFF49335A010912A201EB4
 +S31550001150D0248009D404800980A2A00016800021E2
 +S3155000116090100009D404800880A2A00006BFFFFE9C
 +S31550001170010000003080001B10BFFFF3D027BFF4E2
 +S31550001180912B6002D404800880A2A00006BFFFFE07
 +S315500011900100000010BFFFE3900AA006901000095E
 +S315500011A0D404800880A2A00006BFFFFE0100000004
 +S315500011B010BFFFC9900AA00610BFFFBDD027BFF4CD
 +S315500011C0D404800880A2A00006BFFFFE01000000E4
 +S315500011D010BFFFB39132A01D10BFFFABAD2A6010F8
 +S315500011E00100000081C7E00881E800009DE3BF9838
 +S315500011F035140005F60EA180921000183500001324
 +S31550001200B416A30CB72EE002B606C01A992EE010FB
 +S31550001210B53320129B2EA002A210001AA610001958
 +S315500012203B080000961020009410000DA410001AE0
 +S31550001230F807400D80A7200006800064B137201DB6
 +S31550001240B00E200180A00018B0603FFFB12E201EC6
 +S3155000125033030000B0160019F027400AF807400A79
 +S3155000126080A7200006800052B1372016B48E200F7A
 +S315500012701280001A82102000B3332012310003D09E
 +S31550001280901000199E162240B32E600237030000BC
 +S3155000129080A0400F8200600118800053B0102000DB
 +S315500012A0B137201DB00E200180A00018B0603FFF5E
 +S315500012B0B12E201EB016001BF0274019F807401912
 +S315500012C080A7200006800033B1372016B48E200F39
 +S315500012D002BFFFF180A0400F8210200080A0401A6C
 +S315500012E01ABFFFD4B1332012B72E20029010001827
 +S315500012F09E10001BA0100018F807401B80A7200066
 +S315500013000680001DB137201DB00E200180A00018A8
 +S31550001310B0603FFFB12E201E33010000B0160019F9
 +S31550001320F027400FF807400F80A720000680000CDA
 +S31550001330B12C20029602E001F82A400080A2C01388
 +S3155000134002800029B010000B8200600180A0401A74
 +S315500013500ABFFFEA9202600130BFFFB6F807401895
 +S3155000136080A7200006BFFFFE0100000010BFFFF35C
 +S315500013709602E001B12A2002F807401880A7200003
 +S3155000138006BFFFFE0100000010BFFFE0B137201D71
 +S31550001390B12A2002F807401880A7200006BFFFFE9A
 +S315500013A00100000010BFFFCAB1372016B12CA002B1
 +S315500013B0F807401880A7200006BFFFFE0100000076
 +S315500013C010BFFFABB1372016B12C6002F80740189A
 +S315500013D080A7200006BFFFFE0100000010BFFF9946
 +S315500013E0B137201D0100000081C7E00881E80000E8
 +S315500013F09DE3BF987FFFFE81B00E20FF7FFFFE4822
 +S3155000140081E800000100000000000000000000001C
 +S315500014100000000000000000000000000000000076
 +S315500014204572726F723400004572726F72330000EB
 +S315500014304F4B0000000000004572726F7232000080
 +S31550001440454E4400000000004572726F7235000030
 +S315500014504572726F723100000000000000000000FB
 +S3155000146000000000000000010000000E00000037E0
 +S31550001470000000B500004000000000030000000D11
 +S3155000148000000037000000B5000080000000000496
 +S315500014900000000F00000037000000B500010000FA
 +S315500014A00000000B0000001000000037000000B5DF
 +S315500014B00000000000000007000000100000001CA3
 +S315500014C0000000B900007000000000080000000F86
 +S315500014D00000001C000000B9000078000000000A5F
 +S315500014E00000000D0000001C000000B900007C0048
 +S315500014F00000000B0000000E0000001C000000B9A8
 +S31550001500000000000000000F000000100000001C4A
 +S31550001510000000DA00007000000000100000000F0C
 +S315500015200000001C000000DA0000700000000012ED
 +S315500015300000000D0000001C000000DA00007000E2
 +S31550001540000000130000000E0000001C000000DA2E
 +S3155000155000000003000001FB000000FD0000007EBB
 +S315500015600000003F0000002A000000150000000A9D
 +S3115000157000000000000000000000000019
 +S70550000000AA
 diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 6257ee44..625540bb 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -269,6 +269,122 @@ struct cc_telem {  int  cc_telem_parse(const char *input_line, struct cc_telem *telem); +struct ao_log_mega { +	char			type;			/* 0 */ +	uint8_t			is_config;		/* 1 */ +	uint16_t		tick;			/* 2 */ +	union {						/* 4 */ +		/* AO_LOG_FLIGHT */ +		struct { +			uint16_t	flight;		/* 4 */ +			int16_t		ground_accel;	/* 6 */ +			uint32_t	ground_pres;	/* 8 */ +		} flight;				/* 12 */ +		/* AO_LOG_STATE */ +		struct { +			uint16_t	state; +			uint16_t	reason; +		} state; +		/* AO_LOG_SENSOR */ +		struct { +			uint32_t	pres;		/* 4 */ +			uint32_t	temp;		/* 8 */ +			int16_t		accel_x;	/* 12 */ +			int16_t		accel_y;	/* 14 */ +			int16_t		accel_z;	/* 16 */ +			int16_t		gyro_x;		/* 18 */ +			int16_t		gyro_y;		/* 20 */ +			int16_t		gyro_z;		/* 22 */ +			int16_t		mag_x;		/* 24 */ +			int16_t		mag_y;		/* 26 */ +			int16_t		mag_z;		/* 28 */ +			int16_t		accel;		/* 30 */ +		} sensor;	/* 32 */ +		/* AO_LOG_TEMP_VOLT */ +		struct { +			int16_t		v_batt;		/* 4 */ +			int16_t		v_pbatt;	/* 6 */ +			int16_t		n_sense;	/* 8 */ +			int16_t		sense[10];	/* 10 */ +		} volt;					/* 30 */ +		/* AO_LOG_GPS_TIME */ +		struct { +			int32_t		latitude;	/* 4 */ +			int32_t		longitude;	/* 8 */ +			int16_t		altitude;	/* 12 */ +			uint8_t		hour;		/* 14 */ +			uint8_t		minute;		/* 15 */ +			uint8_t		second;		/* 16 */ +			uint8_t		flags;		/* 17 */ +			uint8_t		year;		/* 18 */ +			uint8_t		month;		/* 19 */ +			uint8_t		day;		/* 20 */ +			uint8_t		pad;		/* 21 */ +		} gps;	/* 22 */ +		/* AO_LOG_GPS_SAT */ +		struct { +			uint16_t	channels;	/* 4 */ +			struct { +				uint8_t	svid; +				uint8_t c_n; +			} sats[12];			/* 6 */ +		} gps_sat;				/* 30 */ + +		struct { +			uint32_t		kind; +			int32_t			data[6]; +		} config_int; + +		struct { +			uint32_t		kind; +			char			string[24]; +		} config_str; + +		/* Raw bytes */ +		uint8_t	bytes[28]; +	} u; +}; + +#define AO_CONFIG_CONFIG		1 +#define AO_CONFIG_MAIN			2 +#define AO_CONFIG_APOGEE		3 +#define AO_CONFIG_LOCKOUT		4 +#define AO_CONFIG_FREQUENCY		5 +#define AO_CONFIG_RADIO_ENABLE		6 +#define AO_CONFIG_ACCEL_CAL		7 +#define AO_CONFIG_RADIO_CAL		8 +#define AO_CONFIG_MAX_LOG		9 +#define AO_CONFIG_IGNITE_MODE		10 +#define AO_CONFIG_PAD_ORIENTATION	11 +#define AO_CONFIG_SERIAL_NUMBER		12 +#define AO_CONFIG_LOG_FORMAT		13 +#define AO_CONFIG_MS5607_RESERVED	14 +#define AO_CONFIG_MS5607_SENS		15 +#define AO_CONFIG_MS5607_OFF		16 +#define AO_CONFIG_MS5607_TCS		17 +#define AO_CONFIG_MS5607_TCO		18 +#define AO_CONFIG_MS5607_TREF		19 +#define AO_CONFIG_MS5607_TEMPSENS	20 +#define AO_CONFIG_MS5607_CRC		21 + + +#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_GPS_TIME		'G' +#define AO_LOG_GPS_LAT		'N' +#define AO_LOG_GPS_LON		'W' +#define AO_LOG_GPS_ALT		'H' +#define AO_LOG_GPS_SAT		'V' +#define AO_LOG_GPS_DATE		'Y' + +#define AO_LOG_CONFIG		'c' + +int +cc_mega_parse(const char *input_line, struct ao_log_mega *l); +  #ifndef TRUE  #define TRUE 1  #define FALSE 0 diff --git a/configure.ac b/configure.ac index e3b1185f..55dd20ec 100644 --- a/configure.ac +++ b/configure.ac @@ -164,6 +164,7 @@ ao-tools/ao-load/Makefile  ao-tools/ao-telem/Makefile  ao-tools/ao-stmload/Makefile  ao-tools/ao-send-telem/Makefile +ao-tools/ao-sky-flash/Makefile  ao-utils/Makefile  src/Version  ]) diff --git a/debian/rules b/debian/rules index 9f24321b..122a0fed 100755 --- a/debian/rules +++ b/debian/rules @@ -27,7 +27,7 @@ build-indep: build-stamp  build-stamp: configure-stamp    	dh_testdir -	$(MAKE) VERSION=$(PKG_VERSION) +	$(MAKE)  	(cd doc ; $(MAKE))  	touch $@ diff --git a/doc/altusmetrum.xsl b/doc/altusmetrum.xsl index b2677a02..e7ab353b 100644 --- a/doc/altusmetrum.xsl +++ b/doc/altusmetrum.xsl @@ -278,6 +278,19 @@ NAR #88757, TRA #12200        designed for use with single-cell batteries with 3.7 volts nominal.      </para>      <para> +      The battery connectors are a standard 2-pin JST connector and +      match batteries sold by Spark Fun. These batteries are +      single-cell Lithium Polymer batteries that nominally provide 3.7 +      volts.  Other vendors sell similar batteries for RC aircraft +      using mating connectors, however the polarity for those is +      generally reversed from the batteries used by Altus Metrum +      products. In particular, the Tenergy batteries supplied for use +      in Featherweight flight computers are not compatible with Altus +      Metrum flight computers or battery chargers. <emphasis>Check +      polarity and voltage before connecting any battery not purchased +      from Altus Metrum or Spark Fun.</emphasis> +    </para> +    <para>        By default, we use the unregulated output of the Li-Po battery directly        to fire ejection charges.  This works marvelously with standard        low-current e-matches like the J-Tek from MJG Technologies, and with @@ -481,7 +494,7 @@ NAR #88757, TRA #12200        <para>          You can monitor the operation of the radio link by watching the           lights on the devices. The red LED will flash each time a packet -        is tramsitted, while the green LED will light up on TeleDongle when  +        is transmitted, while the green LED will light up on TeleDongle when           it is waiting to receive a packet from the altimeter.        </para>      </section> @@ -2199,7 +2212,7 @@ NAR #88757, TRA #12200  	</listitem>  	<listitem>  	  <para> -	    RF interface for battery charging, configuration, and data recovery. +	    RF interface for configuration, and data recovery.  	  </para>  	</listitem>  	<listitem> diff --git a/src/avr/ao_usb_avr.c b/src/avr/ao_usb_avr.c index 9ba407af..2ef546c9 100644 --- a/src/avr/ao_usb_avr.c +++ b/src/avr/ao_usb_avr.c @@ -480,10 +480,10 @@ ao_usb_putchar(char c) __critical __reentrant  	ao_usb_in_flushed = 0;  } -static char +static int  _ao_usb_pollchar(void)  { -	char c; +	uint8_t c;  	uint8_t	intx;  	if (!ao_usb_running) @@ -517,10 +517,10 @@ _ao_usb_pollchar(void)  	return c;  } -char +int  ao_usb_pollchar(void)  { -	char	c; +	int	c;  	cli();  	c = _ao_usb_pollchar();  	sei(); @@ -530,7 +530,7 @@ ao_usb_pollchar(void)  char  ao_usb_getchar(void) __critical  { -	char	c; +	int	c;  	cli();  	while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) diff --git a/src/cc1111/ao_adc.c b/src/cc1111/ao_adc.c index f8000410..bfdc418a 100644 --- a/src/cc1111/ao_adc.c +++ b/src/cc1111/ao_adc.c @@ -56,7 +56,7 @@ ao_adc_isr(void) __interrupt 1  	uint8_t	__xdata *a;  	sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT; -#if TELEMETRUM_V_0_1 || TELEMETRUM_V_0_2 || TELEMETRUM_V_1_0 || TELEMETRUM_V_1_1 || TELEMETRUM_V_1_2 || TELELAUNCH_V_0_1 +#if TELEMETRUM_V_0_1 || TELEMETRUM_V_0_2 || TELEMETRUM_V_1_0 || TELEMETRUM_V_1_1 || TELEMETRUM_V_1_2 || TELELAUNCH_V_0_1 || TELEBALLOON_V_1_1  	/* TeleMetrum readings */  #if HAS_ACCEL_REF  	if (sequence == 2) { diff --git a/src/cc1111/ao_dbg.c b/src/cc1111/ao_dbg.c index 847b5aaf..4e534697 100644 --- a/src/cc1111/ao_dbg.c +++ b/src/cc1111/ao_dbg.c @@ -193,54 +193,39 @@ ao_dbg_long_delay(void)  #define AO_RESET_LOW_DELAY	AO_MS_TO_TICKS(100)  #define AO_RESET_HIGH_DELAY	AO_MS_TO_TICKS(100) -void -ao_dbg_debug_mode(void) +static void +ao_dbg_send_bits_delay(uint8_t msk, uint8_t val)  { -	ao_dbg_set_pins();  	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    ); -	ao_delay(AO_RESET_LOW_DELAY); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    ); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|DBG_RESET_N); -	ao_delay(AO_RESET_HIGH_DELAY); +	ao_dbg_send_bits(msk, val);  }  void -ao_dbg_reset(void) +ao_dbg_do_reset(uint8_t clock_up)  {  	ao_dbg_set_pins(); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); +	ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, clock_up |DBG_DATA|    0    );  	ao_delay(AO_RESET_LOW_DELAY); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); -	ao_dbg_long_delay(); -	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); +	ao_dbg_send_bits      (DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, clock_up |DBG_DATA|    0    ); +	ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_send_bits_delay(DBG_CLOCK|DBG_DATA|DBG_RESET_N, clock_up |DBG_DATA|DBG_RESET_N);  	ao_delay(AO_RESET_HIGH_DELAY);  }  static void  debug_enable(void)  { -	ao_dbg_debug_mode(); +	/* toggle clock line while holding reset low */ +	ao_dbg_do_reset(0);  }  static void  debug_reset(void)  { -	ao_dbg_reset(); +	/* hold clock high while holding reset low */ +	ao_dbg_do_reset(DBG_CLOCK);  }  static void @@ -281,22 +266,6 @@ debug_get(void)  	putchar('\n');  } -static uint8_t -getnibble(void) -{ -	__pdata char	c; - -	c = getchar(); -	if ('0' <= c && c <= '9') -		return c - '0'; -	if ('a' <= c && c <= 'f') -		return c - ('a' - 10); -	if ('A' <= c && c <= 'F') -		return c - ('A' - 10); -	ao_cmd_status = ao_cmd_lex_error; -	return 0; -} -  static void  debug_input(void)  { @@ -338,8 +307,8 @@ debug_output(void)  		return;  	ao_dbg_start_transfer(addr);  	while (count--) { -		b = getnibble() << 4; -		b |= getnibble(); +		b = ao_getnibble() << 4; +		b |= ao_getnibble();  		if (ao_cmd_status != ao_cmd_success)  			return;  		ao_dbg_write_byte(b); diff --git a/src/cc1111/ao_serial.c b/src/cc1111/ao_serial.c index 48383802..8913a9b0 100644 --- a/src/cc1111/ao_serial.c +++ b/src/cc1111/ao_serial.c @@ -34,8 +34,14 @@ const __code struct ao_serial_speed ao_serial_speeds[] = {  		/* .baud = */ 59,  		/* .gcr =  */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB  	}, +	/* [AO_SERIAL_SPEED_115200] = */ { +		/* .baud = */ 59, +		/* .gcr =  */ (12 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB +	},  }; +#define AO_SERIAL_SPEED_MAX	AO_SERIAL_SPEED_115200 +  #if HAS_SERIAL_0  volatile __xdata struct ao_fifo	ao_serial0_rx_fifo; @@ -85,10 +91,10 @@ ao_serial0_getchar(void) __critical  }  #if USE_SERIAL_0_STDIN -char +int  ao_serial0_pollchar(void) __critical  { -	char	c; +	uint8_t	c;  	if (ao_fifo_empty(ao_serial0_rx_fifo))  		return AO_READ_AGAIN;  	ao_fifo_remove(ao_serial0_rx_fifo,c); @@ -116,7 +122,7 @@ void  ao_serial0_set_speed(uint8_t speed)  {  	ao_serial0_drain(); -	if (speed > AO_SERIAL_SPEED_57600) +	if (speed > AO_SERIAL_SPEED_MAX)  		return;  	U0UCR |= UxUCR_FLUSH;  	U0BAUD = ao_serial_speeds[speed].baud; @@ -173,10 +179,10 @@ ao_serial1_getchar(void) __critical  }  #if USE_SERIAL_1_STDIN -char +int  ao_serial1_pollchar(void) __critical  { -	char	c; +	uint8_t	c;  	if (ao_fifo_empty(ao_serial1_rx_fifo))  		return AO_READ_AGAIN;  	ao_fifo_remove(ao_serial1_rx_fifo,c); @@ -204,7 +210,7 @@ void  ao_serial1_set_speed(uint8_t speed)  {  	ao_serial1_drain(); -	if (speed > AO_SERIAL_SPEED_57600) +	if (speed > AO_SERIAL_SPEED_MAX)  		return;  	U1UCR |= UxUCR_FLUSH;  	U1BAUD = ao_serial_speeds[speed].baud; diff --git a/src/cc1111/ao_usb.c b/src/cc1111/ao_usb.c index ce26e808..f66e807c 100644 --- a/src/cc1111/ao_usb.c +++ b/src/cc1111/ao_usb.c @@ -382,19 +382,19 @@ ao_usb_putchar(char c) __critical __reentrant  		ao_usb_in_send();  } -char +int  ao_usb_pollchar(void) __critical  { -	char c; +	uint8_t c;  	if (ao_usb_out_bytes == 0) {  		USBINDEX = AO_USB_OUT_EP;  		if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0) -			return AO_READ_AGAIN; +			return -1;  		ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;  		if (ao_usb_out_bytes == 0) {  			USBINDEX = AO_USB_OUT_EP;  			USBCSOL &= ~USBCSOL_OUTPKT_RDY; -			return AO_READ_AGAIN; +			return -1;  		}  	}  	--ao_usb_out_bytes; @@ -409,7 +409,7 @@ ao_usb_pollchar(void) __critical  char  ao_usb_getchar(void) __critical  { -	char	c; +	int	c;  	while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)  		ao_sleep(&ao_stdin_ready); diff --git a/src/core/ao.h b/src/core/ao.h index 81d92e72..df5bbf48 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -170,6 +170,10 @@ ao_cmd_hex(void);  void  ao_cmd_decimal(void); +/* Read a single hex nibble off stdin. */ +uint8_t +ao_getnibble(void); +  uint8_t  ao_match_word(__code char *word); @@ -525,6 +529,11 @@ ao_radio_recv_abort(void);  void  ao_radio_test(uint8_t on); +typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len); + +void +ao_radio_send_lots(ao_radio_fill_func fill); +  /*   * Compute the packet length as follows:   * @@ -595,10 +604,10 @@ ao_monitor_init(void) __reentrant;   * ao_stdio.c   */ -#define AO_READ_AGAIN	((char) -1) +#define AO_READ_AGAIN	(-1)  struct ao_stdio { -	char	(*pollchar)(void); +	int	(*pollchar)(void);  	void	(*putchar)(char c) __reentrant;  	void	(*flush)(void);  	uint8_t	echo; @@ -617,7 +626,7 @@ uint8_t  ao_echo(void);  int8_t -ao_add_stdio(char (*pollchar)(void), +ao_add_stdio(int (*pollchar)(void),  	     void (*putchar)(char) __reentrant,  	     void (*flush)(void)) __reentrant; @@ -675,7 +684,7 @@ extern __xdata uint8_t ao_force_freq;  #endif  #define AO_CONFIG_MAJOR	1 -#define AO_CONFIG_MINOR	12 +#define AO_CONFIG_MINOR	13  #define AO_AES_LEN 16 @@ -702,12 +711,17 @@ struct ao_config {  #if AO_PYRO_NUM  	struct ao_pyro	pyro[AO_PYRO_NUM];	/* minor version 12 */  #endif +	uint16_t	aprs_interval;		/* minor version 13 */  };  #define AO_IGNITE_MODE_DUAL		0  #define AO_IGNITE_MODE_APOGEE		1  #define AO_IGNITE_MODE_MAIN		2 +#define AO_RADIO_ENABLE_CORE		1 +#define AO_RADIO_DISABLE_TELEMETRY	2 +#define AO_RADIO_DISABLE_RDF		4 +  #define AO_PAD_ORIENTATION_ANTENNA_UP	0  #define AO_PAD_ORIENTATION_ANTENNA_DOWN	1 diff --git a/src/core/ao_cmd.c b/src/core/ao_cmd.c index 1814cecf..3d086a57 100644 --- a/src/core/ao_cmd.c +++ b/src/core/ao_cmd.c @@ -110,6 +110,22 @@ putnibble(uint8_t v)  		putchar(v + ('a' - 10));  } +uint8_t +ao_getnibble(void) +{ +	char	c; + +	c = getchar(); +	if ('0' <= c && c <= '9') +		return c - '0'; +	if ('a' <= c && c <= 'f') +		return c - ('a' - 10); +	if ('A' <= c && c <= 'F') +		return c - ('A' - 10); +	ao_cmd_status = ao_cmd_lex_error; +	return 0; +} +  void  ao_cmd_put16(uint16_t v)  { @@ -249,12 +265,25 @@ ao_reboot(void)  static void  version(void)  { -	printf("manufacturer     %s\n", ao_manufacturer); -	printf("product          %s\n", ao_product); -	printf("serial-number    %u\n", ao_serial_number); +	printf("manufacturer     %s\n" +	       "product          %s\n" +	       "serial-number    %u\n" +#if HAS_FLIGHT +	       "current-flight   %u\n" +#endif +#if HAS_LOG +	       "log-format       %u\n" +#endif +	       , ao_manufacturer +	       , ao_product +	       , ao_serial_number +#if HAS_FLIGHT +	       , ao_flight_number +#endif  #if HAS_LOG -	printf("log-format       %u\n", ao_log_format); +	       , ao_log_format  #endif +		);  #if HAS_MS5607  	ao_ms5607_info();  #endif diff --git a/src/core/ao_config.c b/src/core/ao_config.c index e85ddcb4..0aac16a6 100644 --- a/src/core/ao_config.c +++ b/src/core/ao_config.c @@ -128,7 +128,7 @@ _ao_config_get(void)  		if (minor < 6)  			ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION;  		if (minor < 8) -			ao_config.radio_enable = TRUE; +			ao_config.radio_enable = AO_RADIO_ENABLE_CORE;  		if (minor < 9)  			ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN);  		if (minor < 10) @@ -139,6 +139,8 @@ _ao_config_get(void)  		if (minor < 12)  			memset(&ao_config.pyro, '\0', sizeof (ao_config.pyro));  #endif +		if (minor < 13) +			ao_config.aprs_interval = 0;  		ao_config.minor = AO_CONFIG_MINOR;  		ao_config_dirty = 1;  	} @@ -498,6 +500,27 @@ ao_config_key_set(void) __reentrant  }  #endif +#if HAS_APRS + +void +ao_config_aprs_show(void) +{ +	printf ("APRS interval: %d\n", ao_config.aprs_interval); +} + +void +ao_config_aprs_set(void) +{ +	ao_cmd_decimal(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	_ao_config_edit_start(); +	ao_config.aprs_interval = ao_cmd_lex_i; +	_ao_config_edit_finish(); +} + +#endif /* HAS_APRS */ +  struct ao_config_var {  	__code char	*str;  	void		(*set)(void) __reentrant; @@ -529,15 +552,15 @@ __code struct ao_config_var ao_config_vars[] = {  	  ao_config_callsign_set,	ao_config_callsign_show },  	{ "e <0 disable, 1 enable>\0Enable telemetry and RDF",  	  ao_config_radio_enable_set, ao_config_radio_enable_show }, +	{ "f <cal>\0Radio calib (cal = rf/(xtal/2^16))", +	  ao_config_radio_cal_set,  	ao_config_radio_cal_show },  #endif /* HAS_RADIO */  #if HAS_ACCEL  	{ "a <+g> <-g>\0Accel calib (0 for auto)",  	  ao_config_accel_calibrate_set,ao_config_accel_calibrate_show }, +	{ "o <0 antenna up, 1 antenna down>\0Set pad orientation", +	  ao_config_pad_orientation_set,ao_config_pad_orientation_show },  #endif /* HAS_ACCEL */ -#if HAS_RADIO -	{ "f <cal>\0Radio calib (cal = rf/(xtal/2^16))", -	  ao_config_radio_cal_set,  	ao_config_radio_cal_show }, -#endif /* HAS_RADIO */  #if HAS_LOG  	{ "l <size>\0Flight log size (kB)",  	  ao_config_log_set,		ao_config_log_show }, @@ -546,10 +569,6 @@ __code struct ao_config_var ao_config_vars[] = {  	{ "i <0 dual, 1 apogee, 2 main>\0Set igniter mode",  	  ao_config_ignite_mode_set,	ao_config_ignite_mode_show },  #endif -#if HAS_ACCEL -	{ "o <0 antenna up, 1 antenna down>\0Set pad orientation", -	  ao_config_pad_orientation_set,ao_config_pad_orientation_show }, -#endif  #if HAS_AES  	{ "k <32 hex digits>\0Set AES encryption key",  	  ao_config_key_set, ao_config_key_show }, @@ -558,6 +577,10 @@ __code struct ao_config_var ao_config_vars[] = {  	{ "P <n,?>\0Configure pyro channels",  	  ao_pyro_set, ao_pyro_show },  #endif +#if HAS_APRS +	{ "A <secs>\0APRS packet interval (0 disable)", +	  ao_config_aprs_set, ao_config_aprs_show }, +#endif  	{ "s\0Show",  	  ao_config_show,		0 },  #if HAS_EEPROM diff --git a/src/core/ao_data.h b/src/core/ao_data.h index 6fdd19cb..7e2f85d8 100644 --- a/src/core/ao_data.h +++ b/src/core/ao_data.h @@ -288,4 +288,25 @@ typedef int16_t accel_t;  #endif +#if !HAS_GYRO && HAS_MPU6000 + +#define HAS_GYRO	1 + +typedef int16_t	gyro_t; +typedef int32_t angle_t; + +/* Y axis is aligned with the direction of motion (along) */ +/* X axis is aligned in the other board axis (across) */ +/* Z axis is aligned perpendicular to the board (through) */ + +#define ao_data_along(packet)	((packet)->mpu6000.accel_y) +#define ao_data_across(packet)	((packet)->mpu6000.accel_x) +#define ao_data_through(packet)	((packet)->mpu6000.accel_z) + +#define ao_data_roll(packet)	((packet)->mpu6000.gyro_y) +#define ao_data_pitch(packet)	((packet)->mpu6000.gyro_x) +#define ao_data_yaw(packet)	((packet)->mpu6000.gyro_z) + +#endif +  #endif /* _AO_DATA_H_ */ diff --git a/src/core/ao_log.h b/src/core/ao_log.h index 4eaed420..036d6f2d 100644 --- a/src/core/ao_log.h +++ b/src/core/ao_log.h @@ -199,10 +199,16 @@ struct ao_log_mega {  	union {						/* 4 */  		/* AO_LOG_FLIGHT */  		struct { -			uint16_t	flight;		/* 4 */ -			int16_t		ground_accel;	/* 6 */ -			uint32_t	ground_pres;	/* 8 */ -		} flight;				/* 12 */ +			uint16_t	flight;			/* 4 */ +			int16_t		ground_accel;		/* 6 */ +			uint32_t	ground_pres;		/* 8 */ +			int16_t		ground_accel_along;	/* 16 */ +			int16_t		ground_accel_across;	/* 12 */ +			int16_t		ground_accel_through;	/* 14 */ +			int16_t		ground_roll;		/* 18 */ +			int16_t		ground_pitch;		/* 20 */ +			int16_t		ground_yaw;		/* 22 */ +		} flight;					/* 24 */  		/* AO_LOG_STATE */  		struct {  			uint16_t	state; diff --git a/src/core/ao_log_mega.c b/src/core/ao_log_mega.c index ac1590db..e03687ad 100644 --- a/src/core/ao_log_mega.c +++ b/src/core/ao_log_mega.c @@ -95,6 +95,14 @@ ao_log(void)  #if HAS_ACCEL  	log.u.flight.ground_accel = ao_ground_accel;  #endif +#if HAS_GYRO +	log.u.flight.ground_accel_along = ao_ground_accel_along; +	log.u.flight.ground_accel_across = ao_ground_accel_across; +	log.u.flight.ground_accel_through = ao_ground_accel_through; +	log.u.flight.ground_pitch = ao_ground_pitch; +	log.u.flight.ground_yaw = ao_ground_yaw; +	log.u.flight.ground_roll = ao_ground_roll; +#endif  	log.u.flight.ground_pres = ao_ground_pres;  	log.u.flight.flight = ao_flight_number;  	ao_log_mega(&log); diff --git a/src/core/ao_log_telem.c b/src/core/ao_log_telem.c index 18ab85dd..23ebf7dd 100644 --- a/src/core/ao_log_telem.c +++ b/src/core/ao_log_telem.c @@ -102,9 +102,9 @@ ao_log_single(void)  		while (ao_log_running) {  			/* Write samples to EEPROM */  			while (ao_log_monitor_pos != ao_monitor_head) { -				memcpy(&ao_log_single_write_data.telemetry, -				       &ao_monitor_ring[ao_log_monitor_pos], -				       AO_LOG_SINGLE_SIZE); +				ao_xmemcpy(&ao_log_single_write_data.telemetry, +					   &ao_monitor_ring[ao_log_monitor_pos], +					   AO_LOG_SINGLE_SIZE);  				ao_log_single_write();  				ao_log_monitor_pos = ao_monitor_ring_next(ao_log_monitor_pos);  				ao_log_telem_track(); diff --git a/src/core/ao_packet.h b/src/core/ao_packet.h index 0eafd3b2..08b184d6 100644 --- a/src/core/ao_packet.h +++ b/src/core/ao_packet.h @@ -62,7 +62,7 @@ ao_packet_flush(void);  void  ao_packet_putchar(char c) __reentrant; -char +int  ao_packet_pollchar(void);  #if PACKET_HAS_MASTER diff --git a/src/core/ao_sample.c b/src/core/ao_sample.c index 985c0940..dec44f9f 100644 --- a/src/core/ao_sample.c +++ b/src/core/ao_sample.c @@ -37,6 +37,16 @@ __pdata alt_t		ao_sample_height;  #if HAS_ACCEL  __pdata accel_t		ao_sample_accel;  #endif +#if HAS_GYRO +__pdata accel_t		ao_sample_accel_along; +__pdata accel_t		ao_sample_accel_across; +__pdata accel_t		ao_sample_accel_through; +__pdata gyro_t		ao_sample_roll; +__pdata gyro_t		ao_sample_pitch; +__pdata gyro_t		ao_sample_yaw; +__pdata angle_t		ao_sample_angle; +__pdata angle_t		ao_sample_roll_angle; +#endif  __data uint8_t		ao_sample_data; @@ -53,6 +63,15 @@ __pdata accel_t		ao_accel_2g;		/* factory accel calibration */  __pdata int32_t		ao_accel_scale;		/* sensor to m/s² conversion */  #endif +#if HAS_GYRO +__pdata accel_t		ao_ground_accel_along; +__pdata accel_t		ao_ground_accel_across; +__pdata accel_t		ao_ground_accel_through; +__pdata gyro_t		ao_ground_pitch; +__pdata gyro_t		ao_ground_yaw; +__pdata gyro_t		ao_ground_roll; +#endif +  static __pdata uint8_t	ao_preflight;		/* in preflight mode */  static __pdata uint16_t	nsamples; @@ -60,6 +79,14 @@ __pdata int32_t ao_sample_pres_sum;  #if HAS_ACCEL  __pdata int32_t ao_sample_accel_sum;  #endif +#if HAS_GYRO +__pdata int32_t ao_sample_accel_along_sum; +__pdata int32_t ao_sample_accel_across_sum; +__pdata int32_t	ao_sample_accel_through_sum; +__pdata int32_t ao_sample_pitch_sum; +__pdata int32_t ao_sample_yaw_sum; +__pdata int32_t	ao_sample_roll_sum; +#endif  static void  ao_sample_preflight_add(void) @@ -68,6 +95,14 @@ ao_sample_preflight_add(void)  	ao_sample_accel_sum += ao_sample_accel;  #endif  	ao_sample_pres_sum += ao_sample_pres; +#if HAS_GYRO +	ao_sample_accel_along_sum += ao_sample_accel_along; +	ao_sample_accel_across_sum += ao_sample_accel_across; +	ao_sample_accel_through_sum += ao_sample_accel_through; +	ao_sample_pitch_sum += ao_sample_pitch; +	ao_sample_yaw_sum += ao_sample_yaw; +	ao_sample_roll_sum += ao_sample_roll; +#endif  	++nsamples;  } @@ -80,8 +115,23 @@ ao_sample_preflight_set(void)  #endif  	ao_ground_pres = ao_sample_pres_sum >> 9;  	ao_ground_height = pres_to_altitude(ao_ground_pres); -	nsamples = 0;  	ao_sample_pres_sum = 0; +#if HAS_GYRO +	ao_ground_accel_along = ao_sample_accel_along_sum >> 9; +	ao_ground_accel_across = ao_sample_accel_across_sum >> 9; +	ao_ground_accel_through = ao_sample_accel_through_sum >> 9; +	ao_ground_pitch = ao_sample_pitch_sum >> 9; +	ao_ground_yaw = ao_sample_yaw_sum >> 9; +	ao_ground_roll = ao_sample_roll_sum >> 9; +	ao_sample_accel_along_sum = 0; +	ao_sample_accel_across_sum = 0; +	ao_sample_accel_through_sum = 0; +	ao_sample_pitch_sum = 0; +	ao_sample_yaw_sum = 0; +	ao_sample_roll_sum = 0; +	ao_sample_angle = 0; +#endif	 +	nsamples = 0;  }  static void @@ -122,6 +172,25 @@ ao_sample_preflight_update(void)  		ao_sample_preflight_set();  } +#if 0 +#if HAS_GYRO +static int32_t	p_filt; +static int32_t	y_filt; + +static gyro_t inline ao_gyro(void) { +	gyro_t	p = ao_sample_pitch - ao_ground_pitch; +	gyro_t	y = ao_sample_yaw - ao_ground_yaw; + +	p_filt = p_filt - (p_filt >> 6) + p; +	y_filt = y_filt - (y_filt >> 6) + y; + +	p = p_filt >> 6; +	y = y_filt >> 6; +	return ao_sqrt(p*p + y*y); +} +#endif +#endif +  uint8_t  ao_sample(void)  { @@ -147,6 +216,14 @@ ao_sample(void)  			ao_sample_accel = ao_data_accel_invert(ao_sample_accel);  		ao_data_set_accel(ao_data, ao_sample_accel);  #endif +#if HAS_GYRO +		ao_sample_accel_along = ao_data_along(ao_data); +		ao_sample_accel_across = ao_data_across(ao_data); +		ao_sample_accel_through = ao_data_through(ao_data); +		ao_sample_pitch = ao_data_pitch(ao_data); +		ao_sample_yaw = ao_data_yaw(ao_data); +		ao_sample_roll = ao_data_roll(ao_data); +#endif  		if (ao_preflight)  			ao_sample_preflight(); @@ -154,6 +231,9 @@ ao_sample(void)  			if (ao_flight_state < ao_flight_boost)  				ao_sample_preflight_update();  			ao_kalman(); +#if HAS_GYRO +			/* do quaternion stuff here... */ +#endif  		}  		ao_sample_data = ao_data_ring_next(ao_sample_data);  	} @@ -171,6 +251,21 @@ ao_sample_init(void)  	ao_sample_accel_sum = 0;  	ao_sample_accel = 0;  #endif +#if HAS_GYRO +	ao_sample_accel_along_sum = 0; +	ao_sample_accel_across_sum = 0; +	ao_sample_accel_through_sum = 0; +	ao_sample_accel_along = 0; +	ao_sample_accel_across = 0; +	ao_sample_accel_through = 0; +	ao_sample_pitch_sum = 0; +	ao_sample_yaw_sum = 0; +	ao_sample_roll_sum = 0; +	ao_sample_pitch = 0; +	ao_sample_yaw = 0; +	ao_sample_roll = 0; +	ao_sample_angle = 0; +#endif  	ao_sample_data = ao_data_head;  	ao_preflight = TRUE;  } diff --git a/src/core/ao_sample.h b/src/core/ao_sample.h index 9336bdf9..a2dac979 100644 --- a/src/core/ao_sample.h +++ b/src/core/ao_sample.h @@ -111,6 +111,14 @@ extern __pdata accel_t	ao_ground_accel;	/* startup acceleration */  extern __pdata accel_t 	ao_accel_2g;		/* factory accel calibration */  extern __pdata int32_t	ao_accel_scale;		/* sensor to m/s² conversion */  #endif +#if HAS_GYRO +extern __pdata accel_t	ao_ground_accel_along; +extern __pdata accel_t	ao_ground_accel_across; +extern __pdata accel_t	ao_ground_accel_through; +extern __pdata gyro_t	ao_ground_pitch; +extern __pdata gyro_t	ao_ground_yaw; +extern __pdata gyro_t	ao_ground_roll; +#endif  void ao_sample_init(void); diff --git a/src/core/ao_send_packet.c b/src/core/ao_send_packet.c index 1a8e74de..66315d22 100644 --- a/src/core/ao_send_packet.c +++ b/src/core/ao_send_packet.c @@ -21,22 +21,6 @@  static __xdata uint8_t ao_send[AO_MAX_SEND]; -static uint8_t -getnibble(void) -{ -	char	c; - -	c = getchar(); -	if ('0' <= c && c <= '9') -		return c - '0'; -	if ('a' <= c && c <= 'f') -		return c - ('a' - 10); -	if ('A' <= c && c <= 'F') -		return c - ('A' - 10); -	ao_cmd_status = ao_cmd_lex_error; -	return 0; -} -  static void  ao_send_packet(void)  { @@ -53,8 +37,8 @@ ao_send_packet(void)  		return;  	}  	for (i = 0; i < count; i++) { -		b = getnibble() << 4; -		b |= getnibble(); +		b = ao_getnibble() << 4; +		b |= ao_getnibble();  		if (ao_cmd_status != ao_cmd_success)  			return;  		ao_send[i] = b; diff --git a/src/core/ao_serial.h b/src/core/ao_serial.h index 53aa8a89..a799bf2c 100644 --- a/src/core/ao_serial.h +++ b/src/core/ao_serial.h @@ -22,6 +22,7 @@  #define AO_SERIAL_SPEED_9600	1  #define AO_SERIAL_SPEED_19200	2  #define AO_SERIAL_SPEED_57600	3 +#define AO_SERIAL_SPEED_115200	4  #if HAS_SERIAL_0  extern volatile __xdata struct ao_fifo	ao_serial0_rx_fifo; @@ -30,6 +31,9 @@ extern volatile __xdata struct ao_fifo	ao_serial0_tx_fifo;  char  ao_serial0_getchar(void); +int +ao_serial0_pollchar(void); +  void  ao_serial0_putchar(char c); @@ -47,7 +51,7 @@ extern volatile __xdata struct ao_fifo	ao_serial1_tx_fifo;  char  ao_serial1_getchar(void); -char +int  ao_serial1_pollchar(void);  void @@ -67,7 +71,7 @@ extern volatile __xdata struct ao_fifo	ao_serial2_tx_fifo;  char  ao_serial2_getchar(void); -char +int  ao_serial2_pollchar(void);  void @@ -80,6 +84,26 @@ void  ao_serial2_set_speed(uint8_t speed);  #endif +#if HAS_SERIAL_3 +extern volatile __xdata struct ao_fifo	ao_serial3_rx_fifo; +extern volatile __xdata struct ao_fifo	ao_serial3_tx_fifo; + +char +ao_serial3_getchar(void); + +int +ao_serial3_pollchar(void); + +void +ao_serial3_putchar(char c); + +void +ao_serial3_drain(void); + +void +ao_serial3_set_speed(uint8_t speed); +#endif +  void  ao_serial_init(void); diff --git a/src/core/ao_sqrt.c b/src/core/ao_sqrt.c index 09c2e319..3a550eaa 100644 --- a/src/core/ao_sqrt.c +++ b/src/core/ao_sqrt.c @@ -15,7 +15,9 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ +#ifndef AO_FLIGHT_TEST  #include "ao.h" +#endif  /* Adapted from int_sqrt.c in the linux kernel, which is licensed GPLv2 */  /** diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c index 8cf66a23..1748dfe8 100644 --- a/src/core/ao_stdio.c +++ b/src/core/ao_stdio.c @@ -98,7 +98,7 @@ __xdata uint8_t ao_stdin_ready;  char  getchar(void) __reentrant  { -	char c; +	int c;  	ao_arch_critical(  		int8_t stdio = ao_cur_stdio; @@ -123,7 +123,7 @@ ao_echo(void)  }  int8_t -ao_add_stdio(char (*pollchar)(void), +ao_add_stdio(int (*pollchar)(void),  	     void (*putchar)(char),  	     void (*flush)(void)) __reentrant  { diff --git a/src/core/ao_task.c b/src/core/ao_task.c index 0411fbdd..9cb074b5 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -305,6 +305,8 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam  		);  } +__data uint8_t	ao_task_minimize_latency; +  /* Task switching function. This must not use any stack variables */  void  ao_yield(void) ao_arch_naked_define @@ -331,7 +333,12 @@ ao_yield(void) ao_arch_naked_define  	}  	ao_arch_isr_stack(); -	ao_arch_block_interrupts(); +#if !HAS_TASK_QUEUE +	if (ao_task_minimize_latency) +		ao_arch_release_interrupts(); +	else +#endif +		ao_arch_block_interrupts();  #if AO_CHECK_STACK  	in_yield = 1; @@ -374,7 +381,7 @@ ao_yield(void) ao_arch_naked_define  				break;  			/* Wait for interrupts when there's nothing ready */ -			if (ao_cur_task_index == ao_last_task_index) +			if (ao_cur_task_index == ao_last_task_index && !ao_task_minimize_latency)  				ao_arch_wait_interrupt();  		}  	} diff --git a/src/core/ao_task.h b/src/core/ao_task.h index 049f69a7..50bfb220 100644 --- a/src/core/ao_task.h +++ b/src/core/ao_task.h @@ -47,6 +47,7 @@ struct ao_task {  extern __xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];  extern __data uint8_t ao_num_tasks;  extern __xdata struct ao_task *__data ao_cur_task; +extern __data uint8_t ao_task_minimize_latency;	/* Reduce IRQ latency */  /*   ao_task.c diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c index 52ac9489..8d440e15 100644 --- a/src/core/ao_telemetry.c +++ b/src/core/ao_telemetry.c @@ -22,6 +22,12 @@ static __pdata uint16_t ao_telemetry_interval;  static __pdata uint8_t ao_rdf = 0;  static __pdata uint16_t ao_rdf_time; +#if HAS_APRS +static __pdata uint16_t ao_aprs_time; + +#include <ao_aprs.h> +#endif +  #if defined(MEGAMETRUM)  #define AO_SEND_MEGA	1  #endif @@ -288,30 +294,40 @@ ao_telemetry(void)  		while (ao_telemetry_interval == 0)  			ao_sleep(&telemetry);  		time = ao_rdf_time = ao_time(); +#if HAS_APRS +		ao_aprs_time = time; +#endif  		while (ao_telemetry_interval) { - +#if HAS_APRS +			if (!(ao_config.radio_enable & AO_RADIO_DISABLE_TELEMETRY)) +#endif +			{  #ifdef AO_SEND_ALL_BARO -			ao_send_baro(); +				ao_send_baro();  #endif  #ifdef AO_SEND_MEGA -			ao_send_mega_sensor(); -			ao_send_mega_data(); +				ao_send_mega_sensor(); +				ao_send_mega_data();  #else -			ao_send_sensor(); +				ao_send_sensor();  #endif  #if HAS_COMPANION -			if (ao_companion_running) -				ao_send_companion(); +				if (ao_companion_running) +					ao_send_companion();  #endif -			ao_send_configuration(); +				ao_send_configuration();  #if HAS_GPS -			ao_send_location(); -			ao_send_satellite(); +				ao_send_location(); +				ao_send_satellite();  #endif +			}  #ifndef AO_SEND_ALL_BARO  			if (ao_rdf && +#if HAS_APRS +			    !(ao_config.radio_enable & AO_RADIO_DISABLE_RDF) && +#endif  			    (int16_t) (ao_time() - ao_rdf_time) >= 0)  			{  #if HAS_IGNITE_REPORT @@ -325,6 +341,14 @@ ao_telemetry(void)  #endif  					ao_radio_rdf();  			} +#if HAS_APRS +			if (ao_config.aprs_interval != 0 && +			    (int16_t) (ao_time() - ao_aprs_time) >= 0) +			{ +				ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval); +				ao_aprs_send(); +			} +#endif  #endif  			time += ao_telemetry_interval;  			delay = time - ao_time(); @@ -389,8 +413,9 @@ ao_rdf_set(uint8_t rdf)  	ao_rdf = rdf;  	if (rdf == 0)  		ao_radio_rdf_abort(); -	else +	else {  		ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS; +	}  }  __xdata struct ao_task	ao_telemetry_task; diff --git a/src/core/ao_usb.h b/src/core/ao_usb.h index e051db93..4476ee6b 100644 --- a/src/core/ao_usb.h +++ b/src/core/ao_usb.h @@ -33,7 +33,7 @@ ao_usb_getchar(void);  /* Poll for a charcter on the USB input queue.   * returns AO_READ_AGAIN if none are available   */ -char +int  ao_usb_pollchar(void);  /* Flush the USB output queue */ diff --git a/src/drivers/ao_aprs.c b/src/drivers/ao_aprs.c new file mode 100644 index 00000000..03bcab05 --- /dev/null +++ b/src/drivers/ao_aprs.c @@ -0,0 +1,599 @@ +/**  + * http://ad7zj.net/kd7lmo/aprsbeacon_code.html + * + * @mainpage Pico Beacon + * + * @section overview_sec Overview + * + * The Pico Beacon is an APRS based tracking beacon that operates in the UHF 420-450MHz band.  The device utilizes a  + * Microchip PIC 18F2525 embedded controller, Motorola M12+ GPS engine, and Analog Devices AD9954 DDS.  The device is capable + * of generating a 1200bps A-FSK and 9600 bps FSK AX.25 compliant APRS (Automatic Position Reporting System) message. + + + * + * @section history_sec Revision History + * + * @subsection v305 V3.05 + * 23 Dec 2006, Change include; (1) change printf format width to conform to ANSI standard when new CCS 4.xx compiler released. + * + * + * @subsection v304 V3.04 + * 10 Jan 2006, Change include; (1) added amplitude control to engineering mode, + *                                     (2) corrected number of bytes reported in log, + *                                     (3) add engineering command to set high rate position reports (5 seconds), and + *                                     (4) corrected size of LOG_COORD block when searching for end of log. + * + * @subsection v303 V3.03 + * 15 Sep 2005, Change include; (1) removed AD9954 setting SDIO as input pin,  + *                                     (2) additional comments and Doxygen tags, + *                                     (3) integration and test code calculates DDS FTW, + *                                     (4) swapped bus and reference analog input ports (hardware change), + *                                     (5) added message that indicates we are reading flash log and reports length, + *                                     (6) report bus voltage in 10mV steps, and + *                                     (7) change log type enumerated values to XORed nibbles for error detection. + * + * + * @subsection v302 V3.02 + * 6 Apr 2005, Change include; (1) corrected tracked satellite count in NMEA-0183 $GPGGA message, + *                                    (2) Doxygen documentation clean up and additions, and + *                                    (3) added integration and test code to baseline. + * + *  + * @subsection v301 V3.01 + * 13 Jan 2005, Renamed project and files to Pico Beacon. + * + * + * @subsection v300 V3.00 + * 15 Nov 2004, Change include; (1) Micro Beacon extreme hardware changes including integral transmitter, + *                                     (2) PIC18F2525 processor, + *                                     (3) AD9954 DDS support functions, + *                                     (4) added comments and formatting for doxygen, + *                                     (5) process GPS data with native Motorola protocol, + *                                     (6) generate plain text $GPGGA and $GPRMC messages, + *                                     (7) power down GPS 5 hours after lock, + *                                     (8) added flight data recorder, and + *                                     (9) added diagnostics terminal mode. + * + *  + * @subsection v201 V2.01 + * 30 Jan 2004, Change include; (1) General clean up of in-line documentation, and  + *                                     (2) changed temperature resolution to 0.1 degrees F. + * + *  + * @subsection v200 V2.00 + * 26 Oct 2002, Change include; (1) Micro Beacon II hardware changes including PIC18F252 processor, + *                                     (2) serial EEPROM,  + *                                     (3) GPS power control,  + *                                     (4) additional ADC input, and  + *                                     (5) LM60 temperature sensor.                             + * + * + * @subsection v101 V1.01 + * 5 Dec 2001, Change include; (1) Changed startup message, and  + *                                    (2) applied SEPARATE pragma to several methods for memory usage. + * + * + * @subsection v100 V1.00 + * 25 Sep 2001, Initial release.  Flew ANSR-3 and ANSR-4. + *  + + + * + * + * @section copyright_sec Copyright + * + * Copyright (c) 2001-2009 Michael Gray, KD7LMO + + + * + * + * @section gpl_sec GNU General Public License + * + *  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 + *   + + + *  + *  + * @section design Design Details + * + * Provides design details on a variety of the components that make up the Pico Beacon. + * + *  @subpage power + */ + +/** + *  @page power Power Consumption + * + *  Measured DC power consumption. + *  + *  3VDC prime power current  + + * + *    7mA Held in reset  + + *   18mA Processor running, all I/O off  + + *  110mA GPS running  + + *  120mA GPS running w/antenna  + + *  250mA DDS running and GPS w/antenna  + + *  420mA DDS running, GPS w/antenna, and PA chain on with no RF  + + *  900mA Transmit  + + * + */ + +#ifndef AO_APRS_TEST +#include <ao.h> +#endif + +#include <ao_aprs.h> + +// Public methods, constants, and data structures for each class. + +static void timeInit(void); + +static void tncInit(void); +static void tnc1200TimerTick(void); + +/** @} */ + +/** + *  @defgroup sys System Library Functions + * + *  Generic system functions similiar to the run-time C library. + * + *  @{ + */ + +/** + *    Calculate the CRC-16 CCITT of buffer that is length bytes long. + *    The crc parameter allow the calculation on the CRC on multiple buffers. + * + *    @param buffer Pointer to data buffer. + *    @param length number of bytes in data buffer + *    @param crc starting value + * + *    @return CRC-16 of buffer[0 .. length] + */ +static uint16_t sysCRC16(const uint8_t *buffer, uint8_t length, uint16_t crc) +{ +    uint8_t i, bit, value; + +    for (i = 0; i < length; ++i)  +    { +        value = buffer[i]; + +        for (bit = 0; bit < 8; ++bit)  +        { +            crc ^= (value & 0x01); +            crc = ( crc & 0x01 ) ? ( crc >> 1 ) ^ 0x8408 : ( crc >> 1 ); +            value = value >> 1; +        } // END for +    } // END for + +    return crc ^ 0xffff; +} + +/** @} */ + +/** + *  @defgroup rtc Real Time Interrupt tick + * + *  Manage the built-in real time interrupt.  The interrupt clock PRI is 104uS (9600 bps). + * + *  @{ + */ + +/// 16-bit NCO where the upper 8-bits are used to index into the frequency generation table. +static uint16_t timeNCO; + +/// Audio tone NCO update step (phase). +static uint16_t timeNCOFreq; + +/** + *   Initialize the real-time clock. + */ +static void timeInit() +{ +    timeNCO = 0x00; +    timeNCOFreq = 0x2000; +} + +/** @} */ + +/** + *  @defgroup tnc TNC (Terminal Node Controller) + * + *  Functions that provide a subset of the TNC functions. + * + *  @{ + */ + +/// The number of start flag bytes to send before the packet message.  (360bits * 1200bps = 300mS) +#define TNC_TX_DELAY 45 + +/// The size of the TNC output buffer. +#define TNC_BUFFER_SIZE 40 + +/// States that define the current mode of the 1200 bps (A-FSK) state machine. +typedef enum +{ +    /// Stand by state ready to accept new message. +    TNC_TX_READY, + +    /// 0x7E bit stream pattern used to define start of APRS message. +    TNC_TX_SYNC, + +    /// Transmit the AX.25 header that contains the source/destination call signs, APRS path, and flags. +    TNC_TX_HEADER, + +    /// Transmit the message data. +    TNC_TX_DATA, + +    /// Transmit the end flag sequence. +    TNC_TX_END +} TNC_TX_1200BPS_STATE; + +/// AX.25 compliant packet header that contains destination, station call sign, and path. +/// 0x76 for SSID-11, 0x78 for SSID-12 +static uint8_t TNC_AX25_HEADER[] = {  +    'A' << 1, 'P' << 1, 'A' << 1, 'M' << 1, ' ' << 1, ' ' << 1, 0x60, \ +    'N' << 1, '0' << 1, 'C' << 1, 'A' << 1, 'L' << 1, 'L' << 1, 0x78, \ +    'W' << 1, 'I' << 1, 'D' << 1, 'E' << 1, '2' << 1, ' ' << 1, 0x65, \ +    0x03, 0xf0 }; + +#define TNC_CALLSIGN_OFF	7 +#define TNC_CALLSIGN_LEN	6 + +static void +tncSetCallsign(void) +{ +#ifndef AO_APRS_TEST +	uint8_t	i; + +	for (i = 0; i < TNC_CALLSIGN_LEN; i++) { +		if (!ao_config.callsign[i]) +			break; +		TNC_AX25_HEADER[TNC_CALLSIGN_OFF + i] = ao_config.callsign[i] << 1; +	} +	for (; i < TNC_CALLSIGN_LEN; i++) +		TNC_AX25_HEADER[TNC_CALLSIGN_OFF + i] = ' ' << 1; +#endif +} + +/// The next bit to transmit. +static uint8_t tncTxBit; + +/// Current mode of the 1200 bps state machine. +static TNC_TX_1200BPS_STATE tncMode; + +/// Counter for each bit (0 - 7) that we are going to transmit. +static uint8_t tncBitCount; + +/// A shift register that holds the data byte as we bit shift it for transmit. +static uint8_t tncShift; + +/// Index into the APRS header and data array for each byte as we transmit it. +static uint8_t tncIndex; + +/// The number of bytes in the message portion of the AX.25 message. +static uint8_t tncLength; + +/// A copy of the last 5 bits we've transmitted to determine if we need to bit stuff on the next bit. +static uint8_t tncBitStuff; + +/// Buffer to hold the message portion of the AX.25 packet as we prepare it. +static uint8_t tncBuffer[TNC_BUFFER_SIZE]; + +/**  + *   Initialize the TNC internal variables. + */ +static void tncInit() +{ +    tncTxBit = 0; +    tncMode = TNC_TX_READY; +} + +/** + *   Method that is called every 833uS to transmit the 1200bps A-FSK data stream. + *   The provides the pre and postamble as well as the bit stuffed data stream. + */ +static void tnc1200TimerTick() +{ +    // Set the A-FSK frequency. +    if (tncTxBit == 0x00) +        timeNCOFreq = 0x2000; +    else +        timeNCOFreq = 0x3aab; + +    switch (tncMode)  +    { +        case TNC_TX_READY: +            // Generate a test signal alteranting between high and low tones. +            tncTxBit = (tncTxBit == 0 ? 1 : 0); +            break; + +        case TNC_TX_SYNC: +            // The variable tncShift contains the lastest data byte. +            // NRZI enocde the data stream. +            if ((tncShift & 0x01) == 0x00) { +                if (tncTxBit == 0) +                    tncTxBit = 1; +                else +                    tncTxBit = 0; +	    } +                     +            // When the flag is done, determine if we need to send more or data. +            if (++tncBitCount == 8)  +            { +                tncBitCount = 0; +                tncShift = 0x7e; + +                // Once we transmit x mS of flags, send the data. +                // txDelay bytes * 8 bits/byte * 833uS/bit = x mS +                if (++tncIndex == TNC_TX_DELAY)  +                { +                    tncIndex = 0; +                    tncShift = TNC_AX25_HEADER[0]; +                    tncBitStuff = 0; +                    tncMode = TNC_TX_HEADER; +                } // END if +            } else +                tncShift = tncShift >> 1; +            break; + +        case TNC_TX_HEADER: +            // Determine if we have sent 5 ones in a row, if we have send a zero. +            if (tncBitStuff == 0x1f)  +            { +                if (tncTxBit == 0) +                    tncTxBit = 1; +                else +                    tncTxBit = 0; + +                tncBitStuff = 0x00; +                return; +            }    // END if + +            // The variable tncShift contains the lastest data byte. +            // NRZI enocde the data stream. +            if ((tncShift & 0x01) == 0x00) { +                if (tncTxBit == 0) +                    tncTxBit = 1; +                else +                    tncTxBit = 0; +	    } + +            // Save the data stream so we can determine if bit stuffing is  +            // required on the next bit time. +            tncBitStuff = ((tncBitStuff << 1) | (tncShift & 0x01)) & 0x1f; + +            // If all the bits were shifted, get the next byte. +            if (++tncBitCount == 8)  +            { +                tncBitCount = 0; + +                // After the header is sent, then send the data. +                if (++tncIndex == sizeof(TNC_AX25_HEADER))  +                { +                    tncIndex = 0; +                    tncShift = tncBuffer[0]; +                    tncMode = TNC_TX_DATA; +                } else +                    tncShift = TNC_AX25_HEADER[tncIndex]; + +            } else +                tncShift = tncShift >> 1; + +            break; + +        case TNC_TX_DATA: +            // Determine if we have sent 5 ones in a row, if we have send a zero. +            if (tncBitStuff == 0x1f)  +            { +                if (tncTxBit == 0) +                    tncTxBit = 1; +                else +                    tncTxBit = 0; + +                tncBitStuff = 0x00; +                return; +            }    // END if + +            // The variable tncShift contains the lastest data byte. +            // NRZI enocde the data stream. +            if ((tncShift & 0x01) == 0x00) { +                if (tncTxBit == 0) +                    tncTxBit = 1; +                else +                    tncTxBit = 0; +	    } + +            // Save the data stream so we can determine if bit stuffing is  +            // required on the next bit time. +            tncBitStuff = ((tncBitStuff << 1) | (tncShift & 0x01)) & 0x1f; + +            // If all the bits were shifted, get the next byte. +            if (++tncBitCount == 8)  +            { +                tncBitCount = 0; + +                // If everything was sent, transmit closing flags. +                if (++tncIndex == tncLength)  +                { +                    tncIndex = 0; +                    tncShift = 0x7e; +                    tncMode = TNC_TX_END; +                } else +                    tncShift = tncBuffer[tncIndex]; + +            } else +                tncShift = tncShift >> 1; + +            break; + +        case TNC_TX_END: +            // The variable tncShift contains the lastest data byte. +            // NRZI enocde the data stream.  +            if ((tncShift & 0x01) == 0x00) { +                if (tncTxBit == 0) +                    tncTxBit = 1; +                else +                    tncTxBit = 0; +	    } + +            // If all the bits were shifted, get the next one. +            if (++tncBitCount == 8)  +            { +                tncBitCount = 0; +                tncShift = 0x7e; +     +                // Transmit two closing flags. +                if (++tncIndex == 2)  +                { +                    tncMode = TNC_TX_READY; + +                    return; +                } // END if +            } else +                tncShift = tncShift >> 1; + +            break; +    } // END switch +} + +/** + *   Generate the plain text position packet. + */ +static int tncPositionPacket(void) +{ +    int32_t	latitude = ao_gps_data.latitude; +    int32_t	longitude = ao_gps_data.longitude; +    int32_t	altitude = ao_gps_data.altitude; + +    uint16_t	lat_deg; +    uint16_t	lon_deg; +    uint16_t	lat_min; +    uint16_t	lat_frac; +    uint16_t	lon_min; +    uint16_t	lon_frac; + +    char	lat_sign = 'N', lon_sign = 'E'; + +    if (latitude < 0) { +	lat_sign = 'S'; +	latitude = -latitude; +    } + +    if (longitude < 0) { +	lon_sign = 'W'; +	longitude = -longitude; +    } + +    /* Round latitude and longitude by 0.005 minutes */ +    latitude = latitude + 833; +    if (latitude > 900000000) +	latitude = 900000000; +    longitude = longitude + 833; +    if (longitude > 1800000000) +	    longitude = 1800000000; + +    lat_deg = latitude / 10000000; +    latitude -= lat_deg * 10000000; +    latitude *= 60; +    lat_min = latitude / 10000000; +    latitude -= lat_min * 10000000; +    lat_frac = latitude / 100000; + +    lon_deg = longitude / 10000000; +    longitude -= lon_deg * 10000000; +    longitude *= 60; +    lon_min = longitude / 10000000; +    longitude -= lon_min * 10000000; +    lon_frac = longitude / 100000; + +    if (altitude < 0) +	altitude = 0; + +    altitude = (altitude * (int32_t) 10000 + (3048/2)) / (int32_t) 3048; +     +    return sprintf ((char *) tncBuffer, "=%02u%02u.%02u%c\\%03u%02u.%02u%cO /A=%06u\015", +		    lat_deg, lat_min, lat_frac, lat_sign, +		    lon_deg, lon_min, lon_frac, lon_sign, +		    altitude); +} + +static int16_t +tncFill(uint8_t *buf, int16_t len) +{ +    int16_t	l = 0; +    uint8_t	b; +    uint8_t	bit; + +    while (tncMode != TNC_TX_READY && l < len) { +	b = 0; +	for (bit = 0; bit < 8; bit++) { +	    b = b << 1 | (timeNCO >> 15); +	    timeNCO += timeNCOFreq; +	} +	*buf++ = b; +	l++; +	tnc1200TimerTick(); +    } +    if (tncMode == TNC_TX_READY) +	l = -l; +    return l; +} + +/**  + *    Prepare an AX.25 data packet.  Each time this method is called, it automatically + *    rotates through 1 of 3 messages. + * + *    @param dataMode enumerated type that specifies 1200bps A-FSK or 9600bps FSK + */ +void ao_aprs_send(void) +{ +    uint16_t crc; + +    timeInit(); +    tncInit(); +    tncSetCallsign(); + +    tncLength = tncPositionPacket(); + +    // Calculate the CRC for the header and message. +    crc = sysCRC16(TNC_AX25_HEADER, sizeof(TNC_AX25_HEADER), 0xffff); +    crc = sysCRC16(tncBuffer, tncLength, crc ^ 0xffff); + +    // Save the CRC in the message. +    tncBuffer[tncLength++] = crc & 0xff; +    tncBuffer[tncLength++] = (crc >> 8) & 0xff; + +    // Prepare the variables that are used in the real-time clock interrupt. +    tncBitCount = 0; +    tncShift = 0x7e; +    tncTxBit = 0; +    tncIndex = 0; +    tncMode = TNC_TX_SYNC; + +    ao_radio_send_lots(tncFill); +} + +/** @} */ diff --git a/src/drivers/ao_aprs.h b/src/drivers/ao_aprs.h new file mode 100644 index 00000000..a033fa0b --- /dev/null +++ b/src/drivers/ao_aprs.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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. + */ + +#ifndef _AO_APRS_H_ +#define _AO_APRS_H_ + +void +ao_aprs_send(void); + +#endif /* _AO_APRS_H_ */ diff --git a/src/drivers/ao_btm.c b/src/drivers/ao_btm.c index f3816047..c862200a 100644 --- a/src/drivers/ao_btm.c +++ b/src/drivers/ao_btm.c @@ -120,7 +120,7 @@ uint8_t  ao_btm_get_line(void)  {  	uint8_t ao_btm_reply_len = 0; -	char c; +	int c;  	for (;;) { diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index f27958f9..3e894f76 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -24,10 +24,12 @@  #define AO_RADIO_MAX_RECV	sizeof(struct ao_packet)  #define AO_RADIO_MAX_SEND	sizeof(struct ao_packet) -uint8_t ao_radio_wake; -uint8_t ao_radio_mutex; -uint8_t ao_radio_abort; -uint8_t ao_radio_in_recv; +static uint8_t ao_radio_mutex; + +static uint8_t ao_radio_wake;		/* radio ready. Also used as sleep address */ +static uint8_t ao_radio_abort;		/* radio operation should abort */ +static uint8_t ao_radio_mcu_wake;	/* MARC status change */ +static uint8_t ao_radio_marc_status;	/* Last read MARC status value */  #define CC1120_DEBUG	AO_FEC_DEBUG  #define CC1120_TRACE	0 @@ -218,13 +220,32 @@ ao_radio_recv_abort(void)  #define ao_radio_rdf_value 0x55  static uint8_t -ao_radio_marc_status(void) +ao_radio_get_marc_status(void)  {  	return ao_radio_reg_read(CC1120_MARC_STATUS1);  }  static void -ao_radio_tx_isr(void) +ao_radio_mcu_wakeup_isr(void) +{ +	ao_radio_mcu_wake = 1; +	ao_wakeup(&ao_radio_wake); +} + + +static void +ao_radio_check_marc_status(void) +{ +	ao_radio_mcu_wake = 0; +	ao_radio_marc_status = ao_radio_get_marc_status(); +	 +	/* Anyt other than 'tx/rx finished' means an error occurred */ +	if (ao_radio_marc_status & ~(CC1120_MARC_STATUS1_TX_FINISHED|CC1120_MARC_STATUS1_RX_FINISHED)) +		ao_radio_abort = 1; +} + +static void +ao_radio_isr(void)  {  	ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);  	ao_radio_wake = 1; @@ -234,8 +255,9 @@ ao_radio_tx_isr(void)  static void  ao_radio_start_tx(void)  { -	ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr); +	ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);  	ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); +	ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);  	ao_radio_strobe(CC1120_STX);  } @@ -247,6 +269,8 @@ ao_radio_idle(void)  		if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)  			break;  	} +	/* Flush any pending TX bytes */ +	ao_radio_strobe(CC1120_SFTX);  }  /* @@ -261,7 +285,7 @@ ao_radio_idle(void)  #define PACKET_DEV_M	80  /* - * For our packet data, set the symbol rate to 38360 Baud + * For our packet data, set the symbol rate to 38400 Baud   *   *              (2**20 + DATARATE_M) * 2 ** DATARATE_E   *	Rdata = -------------------------------------- * fosc @@ -294,18 +318,19 @@ static const uint16_t packet_setup[] = {  				 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |  				 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |  				 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)), +	AO_CC1120_MARC_GPIO_IOCFG,		CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,  };  static const uint16_t packet_tx_setup[] = {  	CC1120_PKT_CFG2,	((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |  				 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)), -	CC1120_IOCFG2, 		CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG, +	AO_CC1120_INT_GPIO_IOCFG, 		CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,  };  static const uint16_t packet_rx_setup[] = {  	CC1120_PKT_CFG2,	((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |  				 (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)), -	CC1120_IOCFG2, 		CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT, +	AO_CC1120_INT_GPIO_IOCFG, 		CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,  };  /* @@ -323,12 +348,12 @@ static const uint16_t packet_rx_setup[] = {  /*   * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)   * - *              (2**20 - DATARATE_M) * 2 ** DATARATE_E + *              (2**20 + DATARATE_M) * 2 ** DATARATE_E   *	Rdata = -------------------------------------- * fosc   *		             2 ** 39   * - *	DATARATE_M = 511705 - *	DATARATE_E = 6 + *	DATARATE_M = 25166 + *	DATARATE_E = 5   *   * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes   */ @@ -358,7 +383,64 @@ static const uint16_t rdf_setup[] = {  				 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),  }; -static uint8_t ao_radio_mode; +/* + * APRS deviation is 5kHz + * + *	fdev = fosc >> 24 * (256 + dev_m) << dev_e + * + *     	32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989 + */ + +#define APRS_DEV_E	3 +#define APRS_DEV_M	71 +#define APRS_PACKET_LEN	50 + +/* + * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate) + * + *              (2**20 + DATARATE_M) * 2 ** DATARATE_E + *	Rdata = -------------------------------------- * fosc + *		             2 ** 39 + * + *	DATARATE_M = 239914 + *	DATARATE_E = 7 + * + *	Rdata = 9599.998593330383301 + * + */ +#define APRS_DRATE_E	7 +#define APRS_DRATE_M	239914 + +static const uint16_t aprs_setup[] = { +	CC1120_DEVIATION_M,	APRS_DEV_M, +	CC1120_MODCFG_DEV_E,	((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) | +				 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) | +				 (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)), +	CC1120_DRATE2,		((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) | +				 (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)), +	CC1120_DRATE1,		((APRS_DRATE_M >> 8) & 0xff), +	CC1120_DRATE0,		((APRS_DRATE_M >> 0) & 0xff), +	CC1120_PKT_CFG2,	((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) | +				 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)), +	CC1120_PKT_CFG1,	((0 << CC1120_PKT_CFG1_WHITE_DATA) | +				 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) | +				 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) | +				 (0 << CC1120_PKT_CFG1_APPEND_STATUS)), +}; + +#define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |	\ +			      (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \ +			      (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |	\ +			      (0 << CC1120_PKT_CFG0_UART_MODE_EN) |	\ +			      (0 << CC1120_PKT_CFG0_UART_SWAP_EN)) + +#define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) |		\ +			   (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \ +			   (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |		\ +			   (0 << CC1120_PKT_CFG0_UART_MODE_EN) |	\ +			   (0 << CC1120_PKT_CFG0_UART_SWAP_EN)) + +static uint16_t ao_radio_mode;  #define AO_RADIO_MODE_BITS_PACKET	1  #define AO_RADIO_MODE_BITS_PACKET_TX	2 @@ -366,17 +448,23 @@ static uint8_t ao_radio_mode;  #define AO_RADIO_MODE_BITS_TX_FINISH	8  #define AO_RADIO_MODE_BITS_PACKET_RX	16  #define AO_RADIO_MODE_BITS_RDF		32 +#define AO_RADIO_MODE_BITS_APRS		64 +#define AO_RADIO_MODE_BITS_INFINITE	128 +#define AO_RADIO_MODE_BITS_FIXED	256  #define AO_RADIO_MODE_NONE		0  #define AO_RADIO_MODE_PACKET_TX_BUF	(AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)  #define AO_RADIO_MODE_PACKET_TX_FINISH	(AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)  #define AO_RADIO_MODE_PACKET_RX		(AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)  #define AO_RADIO_MODE_RDF		(AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH) +#define AO_RADIO_MODE_APRS_BUF		(AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF) +#define AO_RADIO_MODE_APRS_LAST_BUF	(AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF) +#define AO_RADIO_MODE_APRS_FINISH	(AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)  static void -ao_radio_set_mode(uint8_t new_mode) +ao_radio_set_mode(uint16_t new_mode)  { -	uint8_t	changes; +	uint16_t changes;  	int i;  	if (new_mode == ao_radio_mode) @@ -392,10 +480,10 @@ ao_radio_set_mode(uint8_t new_mode)  			ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);  	if (changes & AO_RADIO_MODE_BITS_TX_BUF) -		ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR); +		ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);  	if (changes & AO_RADIO_MODE_BITS_TX_FINISH) -		ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG); +		ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);  	if (changes & AO_RADIO_MODE_BITS_PACKET_RX)  		for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2) @@ -404,6 +492,17 @@ ao_radio_set_mode(uint8_t new_mode)  	if (changes & AO_RADIO_MODE_BITS_RDF)  		for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)  			ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]); + +	if (changes & AO_RADIO_MODE_BITS_APRS) +		for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2) +			ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]); + +	if (changes & AO_RADIO_MODE_BITS_INFINITE) +		ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE); + +	if (changes & AO_RADIO_MODE_BITS_FIXED) +		ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED); +  	ao_radio_mode = new_mode;  } @@ -431,10 +530,20 @@ ao_radio_setup(void)  }  static void +ao_radio_set_len(uint8_t len) +{ +	static uint8_t	last_len; + +	if (len != last_len) { +		ao_radio_reg_write(CC1120_PKT_LEN, len); +		last_len = len; +	} +} + +static void  ao_radio_get(uint8_t len)  {  	static uint32_t	last_radio_setting; -	static uint8_t	last_len;  	ao_mutex_get(&ao_radio_mutex);  	if (!ao_radio_configured) @@ -445,10 +554,7 @@ ao_radio_get(uint8_t len)  		ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);  		last_radio_setting = ao_config.radio_setting;  	} -	if (len != last_len) { -		ao_radio_reg_write(CC1120_PKT_LEN, len); -		last_len = len; -	} +	ao_radio_set_len(len);  }  #define ao_radio_put()	ao_mutex_put(&ao_radio_mutex) @@ -470,9 +576,11 @@ ao_rdf_run(void)  	ao_radio_start_tx();  	ao_arch_block_interrupts(); -	while (!ao_radio_wake && !ao_radio_abort) +	while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake)  		ao_sleep(&ao_radio_wake);  	ao_arch_release_interrupts(); +	if (ao_radio_mcu_wake) +		ao_radio_check_marc_status();  	if (!ao_radio_wake)  		ao_radio_idle();  	ao_radio_put(); @@ -562,6 +670,31 @@ ao_radio_test_cmd(void)  	}  } +static void +ao_radio_wait_isr(void) +{ +	ao_arch_block_interrupts(); +	while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort) +		ao_sleep(&ao_radio_wake); +	ao_arch_release_interrupts(); +	if (ao_radio_mcu_wake) +		ao_radio_check_marc_status(); +} + +static uint8_t +ao_radio_wait_tx(uint8_t wait_fifo) +{ +	uint8_t	fifo_space = 0; + +	do { +		ao_radio_wait_isr(); +		if (!wait_fifo) +			return 0; +		fifo_space = ao_radio_tx_fifo_space(); +	} while (!fifo_space && !ao_radio_abort); +	return fifo_space; +} +  static uint8_t	tx_data[(AO_RADIO_MAX_SEND + 4) * 2];  void @@ -583,6 +716,7 @@ ao_radio_send(const void *d, uint8_t size)  	while (encode_len) {  		this_len = encode_len; +		ao_radio_wake = 0;  		if (this_len > fifo_space) {  			this_len = fifo_space;  			ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF); @@ -601,16 +735,81 @@ ao_radio_send(const void *d, uint8_t size)  			ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);  		} -		do { -			ao_radio_wake = 0; -			ao_arch_block_interrupts(); -			while (!ao_radio_wake) -				ao_sleep(&ao_radio_wake); -			ao_arch_release_interrupts(); -			if (!encode_len) +		fifo_space = ao_radio_wait_tx(encode_len != 0); +		if (ao_radio_abort) { +			ao_radio_idle(); +			break; +		} +	} +	ao_radio_put(); +} + +#define AO_RADIO_LOTS	64 + +void +ao_radio_send_lots(ao_radio_fill_func fill) +{ +	uint8_t	buf[AO_RADIO_LOTS], *b; +	int	cnt; +	int	total = 0; +	uint8_t	done = 0; +	uint8_t	started = 0; +	uint8_t	fifo_space; + +	ao_radio_get(0xff); +	fifo_space = CC1120_FIFO_SIZE; +	while (!done) { +		cnt = (*fill)(buf, sizeof(buf)); +		if (cnt < 0) { +			done = 1; +			cnt = -cnt; +		} +		total += cnt; + +		/* At the last buffer, set the total length */ +		if (done) +			ao_radio_set_len(total & 0xff); + +		b = buf; +		while (cnt) { +			uint8_t	this_len = cnt; + +			/* Wait for some space in the fifo */ +			while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) { +				ao_radio_wake = 0; +				ao_radio_wait_isr(); +			} +			if (ao_radio_abort)  				break; -			fifo_space = ao_radio_tx_fifo_space(); -		} while (!fifo_space); +			if (this_len > fifo_space) +				this_len = fifo_space; + +			cnt -= this_len; + +			if (done) { +				if (cnt) +					ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF); +				else +					ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH); +			} else +				ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF); + +			ao_radio_fifo_write(b, this_len); +			b += this_len; + +			if (!started) { +				ao_radio_start_tx(); +				started = 1; +			} else +				ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); +		} +		if (ao_radio_abort) { +			ao_radio_idle(); +			break; +		} +		/* Wait for the transmitter to go idle */ +		ao_radio_wake = 0; +		ao_radio_wait_isr();  	}  	ao_radio_put();  } @@ -660,14 +859,21 @@ ao_radio_rx_isr(void)  static uint16_t  ao_radio_rx_wait(void)  { -	ao_arch_block_interrupts(); -	rx_waiting = 1; -	while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK && -	       !ao_radio_abort) { -		ao_sleep(&ao_radio_wake); -	} -	rx_waiting = 0; -	ao_arch_release_interrupts(); +	do { +		if (ao_radio_mcu_wake) +			ao_radio_check_marc_status(); +		ao_arch_block_interrupts(); +		rx_waiting = 1; +		while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK && +		       !ao_radio_abort && +		       !ao_radio_mcu_wake) +		{ +			if (ao_sleep(&ao_radio_wake)) +				ao_radio_abort = 1; +		} +		rx_waiting = 0; +		ao_arch_release_interrupts(); +	} while (ao_radio_mcu_wake);  	if (ao_radio_abort)  		return 0;  	rx_data_consumed += AO_FEC_DECODE_BLOCK; @@ -703,30 +909,53 @@ ao_radio_recv(__xdata void *d, uint8_t size)  	rx_data_consumed = 0;  	rx_ignore = 2; +	/* Must be set before changing the frequency; any abort +	 * after the frequency is set needs to terminate the read +	 * so that the registers can be reprogrammed +	 */  	ao_radio_abort = 0; -	ao_radio_in_recv = 1; +  	/* configure interrupt pin */  	ao_radio_get(len);  	ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);  	ao_radio_wake = 0; +	ao_radio_mcu_wake = 0;  	stm_spi2.cr2 = 0;  	/* clear any RXNE */  	(void) stm_spi2.dr; -	ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr); +	/* Have the radio signal when the preamble quality goes high */ +	ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_PQT_REACHED); +	ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, +			 AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH); +	ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);  	ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); +	ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);  	ao_radio_strobe(CC1120_SRX); +	/* Wait for the preamble to appear */ +	ao_radio_wait_isr(); +	if (ao_radio_abort) +		goto abort; + +	ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT); +	ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, +			 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH); + +	ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr); +	ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); +  	ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);  	ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);  	ao_radio_burst_read_stop(); +abort:  	ao_radio_strobe(CC1120_SIDLE);  	/* Convert from 'real' rssi to cc1111-style values */ @@ -739,11 +968,6 @@ ao_radio_recv(__xdata void *d, uint8_t size)  	((uint8_t *) d)[size] = (uint8_t) rssi; -	ao_radio_in_recv = 0; - -	if (ao_radio_abort) -		ao_delay(1); -  #if AO_PROFILE  	rx_last_done_tick = rx_done_tick;  	rx_done_tick = ao_profile_tick(); @@ -963,7 +1187,7 @@ static void ao_radio_show(void) {  	printf ("Status:   %02x\n", status);  	printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);  	printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]); -	printf ("MARC:     %02x\n", ao_radio_marc_status()); +	printf ("MARC:     %02x\n", ao_radio_get_marc_status());  	for (i = 0; i < AO_NUM_CC1120_REG; i++)  		printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name); @@ -1007,11 +1231,21 @@ ao_radio_test_recv()  	}  } +#include <ao_aprs.h> + +static void +ao_radio_aprs() +{ +	ao_packet_slave_stop(); +	ao_aprs_send(); +} +  #endif  static const struct ao_cmds ao_radio_cmds[] = {  	{ ao_radio_test_cmd,	"C <1 start, 0 stop, none both>\0Radio carrier test" },  #if CC1120_DEBUG +	{ ao_radio_aprs,	"G\0Send APRS packet" },  	{ ao_radio_show,	"R\0Show CC1120 status" },  	{ ao_radio_beep,	"b\0Emit an RDF beacon" },  	{ ao_radio_packet,	"p\0Send a test packet" }, @@ -1043,7 +1277,13 @@ ao_radio_init(void)  	ao_enable_port(AO_CC1120_INT_PORT);  	ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,  		      AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH, -		      ao_radio_tx_isr); +		      ao_radio_isr); + +	/* Enable the hacked up GPIO3 pin */ +	ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT); +	ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN, +		      AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, +		      ao_radio_mcu_wakeup_isr);  	ao_cmd_register(&ao_radio_cmds[0]);  } diff --git a/src/drivers/ao_companion.c b/src/drivers/ao_companion.c index c749adea..0ebe8429 100644 --- a/src/drivers/ao_companion.c +++ b/src/drivers/ao_companion.c @@ -118,10 +118,13 @@ ao_companion_status(void) __reentrant  	printf("Companion running: %d\n", ao_companion_running);  	if (!ao_companion_running)  		return; -	printf("device: %d\n", ao_companion_setup.board_id); -	printf("update period: %d\n", ao_companion_setup.update_period); -	printf("channels: %d\n", ao_companion_setup.channels); -	printf("data:"); +	printf("device: %d\n" +	       "update period: %d\n" +	       "channels: %d\n" +	       "data:", +	       ao_companion_setup.board_id, +	       ao_companion_setup.update_period, +	       ao_companion_setup.channels);  	for(i = 0; i < ao_companion_setup.channels; i++)  		printf(" %5u", ao_companion_data[i]);  	printf("\n"); diff --git a/src/drivers/ao_gps_skytraq.c b/src/drivers/ao_gps_skytraq.c index d80da97c..d2f67e6b 100644 --- a/src/drivers/ao_gps_skytraq.c +++ b/src/drivers/ao_gps_skytraq.c @@ -21,6 +21,7 @@  #ifndef ao_gps_getchar  #define ao_gps_getchar	ao_serial1_getchar +#define ao_gps_fifo	ao_serial1_rx_fifo  #endif  #ifndef ao_gps_putchar @@ -453,6 +454,8 @@ ao_gps_nmea_parse(void)  	}  } +static uint8_t	ao_gps_updating; +  void  ao_gps(void) __reentrant  { @@ -468,6 +471,13 @@ ao_gps(void) __reentrant  		if (ao_gps_getchar() == '$') {  			ao_gps_nmea_parse();  		} +#ifndef AO_GPS_TEST +		while (ao_gps_updating) { +			ao_usb_putchar(ao_gps_getchar()); +			if (ao_fifo_empty(ao_gps_fifo)) +				flush(); +		} +#endif  	}  } @@ -492,8 +502,38 @@ gps_dump(void) __reentrant  	ao_mutex_put(&ao_gps_mutex);  } +static __code uint8_t ao_gps_115200[] = { +	SKYTRAQ_MSG_3(5,0,5,0)	/* Set to 115200 baud */ +}; + +static void +ao_gps_set_speed_delay(uint8_t speed) { +	ao_delay(AO_MS_TO_TICKS(500)); +	ao_gps_set_speed(speed); +	ao_delay(AO_MS_TO_TICKS(500)); +} + +static void +gps_update(void) __reentrant +{ +	ao_gps_updating = 1; +	ao_task_minimize_latency = 1; +#if HAS_ADC +	ao_timer_set_adc_interval(0); +#endif +	ao_skytraq_sendstruct(ao_gps_115200); +	ao_gps_set_speed_delay(AO_SERIAL_SPEED_4800); +	ao_skytraq_sendstruct(ao_gps_115200); +	ao_gps_set_speed_delay(AO_SERIAL_SPEED_115200); + +	/* It's a binary protocol; abandon attempts to escape */ +	for (;;) +		ao_gps_putchar(ao_usb_getchar()); +} +  __code struct ao_cmds ao_gps_cmds[] = {  	{ gps_dump, 	"g\0Display GPS" }, +	{ gps_update,	"U\0Update GPS firmware" },  	{ 0, NULL },  }; diff --git a/src/drivers/ao_m25.c b/src/drivers/ao_m25.c index 9603c1de..9f696ace 100644 --- a/src/drivers/ao_m25.c +++ b/src/drivers/ao_m25.c @@ -99,18 +99,7 @@ static __xdata uint8_t ao_m25_mutex;  static __xdata uint8_t	ao_m25_instruction[4]; -#if HAS_BOOT_RADIO -extern uint8_t ao_radio_in_recv; - -static void ao_boot_radio(void) { -	if (ao_radio_in_recv) -		ao_radio_recv_abort(); -} -#else -#define ao_boot_radio() -#endif - -#define M25_SELECT(cs)		do { ao_boot_radio(); ao_spi_get_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS, AO_SPI_SPEED_FAST); } while (0) +#define M25_SELECT(cs)		ao_spi_get_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS, AO_SPI_SPEED_FAST)  #define M25_DESELECT(cs)	ao_spi_put_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS)  #define M25_BLOCK_SHIFT			16 diff --git a/src/drivers/ao_packet.c b/src/drivers/ao_packet.c index 3c1e7a18..91319923 100644 --- a/src/drivers/ao_packet.c +++ b/src/drivers/ao_packet.c @@ -21,8 +21,8 @@ __xdata struct ao_packet_recv ao_rx_packet;  __xdata struct ao_packet ao_tx_packet;  __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; -static __xdata char tx_data[AO_PACKET_MAX]; -static __xdata char rx_data[AO_PACKET_MAX]; +static __xdata uint8_t tx_data[AO_PACKET_MAX]; +static __xdata uint8_t rx_data[AO_PACKET_MAX];  static __pdata uint8_t rx_seq;  __xdata struct ao_task	ao_packet_task; @@ -169,7 +169,7 @@ ao_packet_putchar(char c) __reentrant  		tx_data[ao_packet_tx_used++] = c;  } -char +int  ao_packet_pollchar(void)  {  	/* No need to block interrupts, all variables here diff --git a/src/drivers/ao_packet_master.c b/src/drivers/ao_packet_master.c index 481232df..023c788b 100644 --- a/src/drivers/ao_packet_master.c +++ b/src/drivers/ao_packet_master.c @@ -20,7 +20,7 @@  static char  ao_packet_getchar(void)  { -	char c; +	int c;  	while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {  		if (!ao_packet_enable)  			break; @@ -35,7 +35,7 @@ ao_packet_getchar(void)  static void  ao_packet_echo(void) __reentrant  { -	char	c; +	int	c;  	while (ao_packet_enable) {  		c = ao_packet_getchar();  		if (c != AO_READ_AGAIN) diff --git a/src/megadongle-v0.1/ao_pins.h b/src/megadongle-v0.1/ao_pins.h index cabe9ee2..d810cd4c 100644 --- a/src/megadongle-v0.1/ao_pins.h +++ b/src/megadongle-v0.1/ao_pins.h @@ -139,8 +139,14 @@  #define AO_CC1120_INT_PORT	(&stm_gpioc)  #define AO_CC1120_INT_PIN	14 +#define AO_CC1120_MCU_WAKEUP_PORT	(&stm_gpioc) +#define AO_CC1120_MCU_WAKEUP_PIN	(0) +  #define AO_CC1120_INT_GPIO	2 -#define HAS_BOOT_RADIO		1 +#define AO_CC1120_INT_GPIO_IOCFG	CC1120_IOCFG2 + +#define AO_CC1120_MARC_GPIO	3 +#define AO_CC1120_MARC_GPIO_IOCFG	CC1120_IOCFG3  /*   * Profiling Viterbi decoding diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile index 7d6c7388..a5fdcbb2 100644 --- a/src/megametrum-v0.1/Makefile +++ b/src/megametrum-v0.1/Makefile @@ -37,12 +37,12 @@ INC = \  #PROFILE=ao_profile.c  #PROFILE_DEF=-DAO_PROFILE=1 -SAMPLE_PROFILE=ao_sample_profile.c \ -	ao_sample_profile_timer.c -SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 +#SAMPLE_PROFILE=ao_sample_profile.c \ +#	ao_sample_profile_timer.c +#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 -STACK_GUARD=ao_mpu_stm.c -STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1  ALTOS_SRC = \  	ao_interrupt.c \ @@ -90,6 +90,7 @@ ALTOS_SRC = \  	ao_packet.c \  	ao_companion.c \  	ao_pyro.c \ +	ao_aprs.c \  	$(PROFILE) \  	$(SAMPLE_PROFILE) \  	$(STACK_GUARD) diff --git a/src/megametrum-v0.1/ao_megametrum.c b/src/megametrum-v0.1/ao_megametrum.c index cb1eb417..fbdab64a 100644 --- a/src/megametrum-v0.1/ao_megametrum.c +++ b/src/megametrum-v0.1/ao_megametrum.c @@ -53,7 +53,9 @@ main(void)  	ao_exti_init();  	ao_adc_init(); +#if HAS_BEEP  	ao_beep_init(); +#endif  	ao_cmd_init();  #if HAS_MS5607 diff --git a/src/megametrum-v0.1/ao_pins.h b/src/megametrum-v0.1/ao_pins.h index 5ae80ac5..b1a70ea2 100644 --- a/src/megametrum-v0.1/ao_pins.h +++ b/src/megametrum-v0.1/ao_pins.h @@ -62,6 +62,7 @@  #define ao_gps_getchar		ao_serial3_getchar  #define ao_gps_putchar		ao_serial3_putchar  #define ao_gps_set_speed	ao_serial3_set_speed +#define ao_gps_fifo		(ao_stm_usart3.rx_fifo)  #define HAS_EEPROM		1  #define USE_INTERNAL_FLASH	0 @@ -69,6 +70,7 @@  #define HAS_BEEP		1  #define HAS_RADIO		1  #define HAS_TELEMETRY		1 +#define HAS_APRS		1  #define HAS_SPI_1		1  #define SPI_1_PA5_PA6_PA7	1	/* Barometer */ @@ -280,11 +282,19 @@ struct ao_adc {  #define AO_CC1120_SPI_CS_PIN	5  #define AO_CC1120_SPI_BUS	AO_SPI_2_PB13_PB14_PB15 -#define AO_CC1120_INT_PORT	(&stm_gpioc) -#define AO_CC1120_INT_PIN	14 +#define AO_CC1120_INT_PORT		(&stm_gpioc) +#define AO_CC1120_INT_PIN		14 +#define AO_CC1120_MCU_WAKEUP_PORT	(&stm_gpioc) +#define AO_CC1120_MCU_WAKEUP_PIN	(0)  #define AO_CC1120_INT_GPIO	2 -#define HAS_BOOT_RADIO		1 +#define AO_CC1120_INT_GPIO_IOCFG	CC1120_IOCFG2 + +#define AO_CC1120_MARC_GPIO	3 +#define AO_CC1120_MARC_GPIO_IOCFG	CC1120_IOCFG3 + + +#define HAS_BOOT_RADIO		0  /*   * Mag sensor (hmc5883) diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index e270199e..007f7e2e 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -123,42 +123,6 @@ void ao_lcd_font_init(void);  void ao_lcd_font_string(char *s); -char -ao_serial1_getchar(void); - -void -ao_serial1_putchar(char c); - -char -ao_serial1_pollchar(void); - -void -ao_serial1_set_speed(uint8_t speed); - -char -ao_serial2_getchar(void); - -void -ao_serial2_putchar(char c); - -char -ao_serial2_pollchar(void); - -void -ao_serial2_set_speed(uint8_t speed); - -char -ao_serial3_getchar(void); - -void -ao_serial3_putchar(char c); - -char -ao_serial3_pollchar(void); - -void -ao_serial3_set_speed(uint8_t speed); -  extern const uint32_t	ao_radio_cal;  void diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index d6ab1465..87bbe73e 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -210,6 +210,26 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop);  void  ao_i2c_init(void); +/* ao_serial_stm.c */ +struct ao_stm_usart { +	struct ao_fifo		rx_fifo; +	struct ao_fifo		tx_fifo; +	struct stm_usart	*reg; +	uint8_t			tx_started; +}; + +#if HAS_SERIAL_1 +extern struct ao_stm_usart	ao_stm_usart1; +#endif + +#if HAS_SERIAL_2 +extern struct ao_stm_usart	ao_stm_usart2; +#endif + +#if HAS_SERIAL_3 +extern struct ao_stm_usart	ao_stm_usart3; +#endif +  #define ARM_PUSH32(stack, val)	(*(--(stack)) = (val))  static inline uint32_t diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index 00409f4a..ce33f97e 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -17,13 +17,6 @@  #include <ao.h> -struct ao_stm_usart { -	struct ao_fifo		rx_fifo; -	struct ao_fifo		tx_fifo; -	struct stm_usart	*reg; -	uint8_t			tx_started; -}; -  void  ao_debug_out(char c)  { @@ -78,16 +71,19 @@ ao_usart_getchar(struct ao_stm_usart *usart)  	return c;  } -char +int  ao_usart_pollchar(struct ao_stm_usart *usart)  { -	char	c; +	int	c;  	ao_arch_block_interrupts();  	if (ao_fifo_empty(usart->rx_fifo))  		c = AO_READ_AGAIN; -	else -		ao_fifo_remove(usart->rx_fifo,c); +	else { +		uint8_t	u; +		ao_fifo_remove(usart->rx_fifo,u); +		c = u; +	}  	ao_arch_release_interrupts();  	return c;  } @@ -127,12 +123,15 @@ static const struct {  	[AO_SERIAL_SPEED_57600] = {  		AO_PCLK1 / 57600  	}, +	[AO_SERIAL_SPEED_115200] = { +		AO_PCLK1 / 115200 +	},  };  void  ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed)  { -	if (speed > AO_SERIAL_SPEED_57600) +	if (speed > AO_SERIAL_SPEED_115200)  		return;  	usart->reg->brr = ao_usart_speeds[speed].brr;  } @@ -201,7 +200,7 @@ ao_serial1_putchar(char c)  	ao_usart_putchar(&ao_stm_usart1, c);  } -char +int  ao_serial1_pollchar(void)  {  	return ao_usart_pollchar(&ao_stm_usart1); @@ -232,7 +231,7 @@ ao_serial2_putchar(char c)  	ao_usart_putchar(&ao_stm_usart2, c);  } -char +int  ao_serial2_pollchar(void)  {  	return ao_usart_pollchar(&ao_stm_usart2); @@ -263,7 +262,7 @@ ao_serial3_putchar(char c)  	ao_usart_putchar(&ao_stm_usart3, c);  } -char +int  ao_serial3_pollchar(void)  {  	return ao_usart_pollchar(&ao_stm_usart3); diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index d93a0c17..9379e5cd 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -873,10 +873,10 @@ _ao_usb_out_recv(void)  	ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID);  } -static char +static int  _ao_usb_pollchar(void)  { -	char c; +	uint8_t c;  	if (!ao_usb_running)  		return AO_READ_AGAIN; @@ -896,10 +896,10 @@ _ao_usb_pollchar(void)  	return c;  } -char +int  ao_usb_pollchar(void)  { -	char	c; +	int	c;  	ao_arch_block_interrupts();  	c = _ao_usb_pollchar();  	ao_arch_release_interrupts(); @@ -909,7 +909,7 @@ ao_usb_pollchar(void)  char  ao_usb_getchar(void)  { -	char	c; +	int	c;  	ao_arch_block_interrupts();  	while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) diff --git a/src/teleballoon-v1.1/ao_pins.h b/src/teleballoon-v1.1/ao_pins.h index 3305719a..7ba48c96 100644 --- a/src/teleballoon-v1.1/ao_pins.h +++ b/src/teleballoon-v1.1/ao_pins.h @@ -43,9 +43,9 @@  	#define PACKET_HAS_SLAVE	1  	#define HAS_COMPANION		1 -	#define COMPANION_CS_ON_P1	1 -	#define COMPANION_CS_MASK	0x4	/* CS1 is P1_2 */ -	#define COMPANION_CS		P1_2 +	#define AO_COMPANION_CS_PORT	P1 +	#define AO_COMPANION_CS_PIN	2 +	#define AO_COMPANION_CS		P1_2  	#define AO_LED_RED		1  	#define LEDS_AVAILABLE		(AO_LED_RED) @@ -53,7 +53,7 @@  	#define HAS_ACCEL_REF		1  	#define SPI_CS_ON_P1		1  	#define SPI_CS_ON_P0		0 -	#define M25_CS_MASK		0x02	/* CS0 is P1_1 */ +	#define AO_M25_SPI_CS_MASK	0x02	/* CS0 is P1_1 */  	#define M25_MAX_CHIPS		1  	#define HAS_ACCEL		1  	#define HAS_IGNITE		0 @@ -114,6 +114,8 @@  	#define SPI_CS_DIR	P0DIR  #endif +#define AO_M25_SPI_CS_PORT	SPI_CS_PORT +  #ifndef IGNITE_ON_P2  #error Please define IGNITE_ON_P2  #endif @@ -212,4 +214,16 @@  #define AO_IGNITER_FIRE_TIME	AO_MS_TO_TICKS(50)  #define AO_IGNITER_CHARGE_TIME	AO_MS_TO_TICKS(2000) +struct ao_adc { +	int16_t		accel;		/* accelerometer */ +	int16_t		pres;		/* pressure sensor */ +	int16_t		temp;		/* temperature sensor */ +	int16_t		v_batt;		/* battery voltage */ +	int16_t		sense_d;	/* drogue continuity sense */ +	int16_t		sense_m;	/* main continuity sense */ +#if HAS_ACCEL_REF +	uint16_t	accel_ref;	/* acceleration reference */ +#endif +}; +  #endif /* _AO_PINS_H_ */ diff --git a/src/teleballoon-v1.1/ao_teleballoon.c b/src/teleballoon-v1.1/ao_teleballoon.c index 3f12a59c..c8bf7760 100644 --- a/src/teleballoon-v1.1/ao_teleballoon.c +++ b/src/teleballoon-v1.1/ao_teleballoon.c @@ -26,6 +26,8 @@ ao_ignite_set_pins(void)  	AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;  } +__pdata uint16_t ao_motor_number; +  void  main(void)  { diff --git a/src/test/Makefile b/src/test/Makefile index 44cee904..092bf360 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,7 +1,8 @@  vpath % ..:../core:../drivers:../util  PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \ -	ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test ao_fec_test +	ao_gps_test ao_gps_test_skytraq ao_convert_test ao_convert_pa_test ao_fec_test \ +	ao_aprs_test  INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h @@ -9,7 +10,7 @@ KALMAN=make-kalman  CFLAGS=-I.. -I. -I../core -I../drivers -O0 -g -Wall -all: $(PROGS) +all: $(PROGS) ao_aprs_data.wav  clean:  	rm -f $(PROGS) run-out.baro run-out.full @@ -29,7 +30,7 @@ ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kal  	cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c  ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) -	cc -DMEGAMETRUM=1 $(CFLAGS) -o $@ $< +	cc -DMEGAMETRUM=1 $(CFLAGS) -o $@ $< -lm  ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h  	cc $(CFLAGS) -o $@ $< @@ -49,5 +50,14 @@ ao_kalman.h: $(KALMAN)  ao_fec_test: ao_fec_test.c ao_fec_tx.c ao_fec_rx.c  	cc $(CFLAGS) -DAO_FEC_DEBUG=1 -o $@ ao_fec_test.c ../core/ao_fec_tx.c ../core/ao_fec_rx.c -lm +ao_aprs_test: ao_aprs_test.c ao_aprs.c +	cc $(CFLAGS) -o $@ ao_aprs_test.c + +SOX_INPUT_ARGS=--type raw --encoding unsigned-integer -b 8 -c 1 -r 9600 +SOX_OUTPUT_ARGS=--type wav + +ao_aprs_data.wav: ao_aprs_test +	./ao_aprs_test | sox $(SOX_INPUT_ARGS) - $(SOX_OUTPUT_ARGS) $@ +  check: ao_fec_test ao_flight_test ao_flight_test_baro run-tests  	./ao_fec_test && ./run-tests
\ No newline at end of file diff --git a/src/test/ao_aprs_test.c b/src/test/ao_aprs_test.c new file mode 100644 index 00000000..3b31f2d3 --- /dev/null +++ b/src/test/ao_aprs_test.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <stdarg.h> + +#include <ao_telemetry.h> + +struct ao_telemetry_location ao_gps_data; + +#define AO_APRS_TEST + +typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len); + +#define DEBUG 0 +#if DEBUG +void +ao_aprs_bit(uint8_t bit) +{ +	static int	seq = 0; +	printf ("%6d %d\n", seq++, bit ? 1 : 0); +} +#else +void +ao_aprs_bit(uint8_t bit) +{ +	putchar (bit ? 0xc0 : 0x40); +} +#endif + +void +ao_radio_send_lots(ao_radio_fill_func fill); + +#include <ao_aprs.c> + +/* + * @section copyright_sec Copyright + * + * Copyright (c) 2001-2009 Michael Gray, KD7LMO + + + * + * + * @section gpl_sec GNU General Public License + * + *  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 + *   + + */ + +static void +audio_gap(int secs) +{ +#if !DEBUG +	int	samples = secs * 9600; + +	while (samples--) +		ao_aprs_bit(0); +#endif +} + +// This is where we go after reset. +int main(int argc, char **argv) +{ +    audio_gap(1); + +    ao_gps_data.latitude = (45.0 + 28.25 / 60.0) * 10000000; +    ao_gps_data.longitude = (-(122 + 44.2649 / 60.0)) * 10000000; +    ao_gps_data.altitude = 84; + +    /* Transmit one packet */ +    ao_aprs_send(); + +    tncBuffer[strlen((char *) tncBuffer) - 2] = '\0'; +    fprintf(stderr, "packet: %s\n", tncBuffer); + +    exit(0); +} + +void +ao_radio_send_lots(ao_radio_fill_func fill) +{ +	int16_t	len; +	uint8_t	done = 0; +	uint8_t	buf[16], *b, c; +	uint8_t bit; + +	while (!done) { +		len = (*fill)(buf, sizeof (buf)); +		if (len < 0) { +			done = 1; +			len = -len; +		} +		b = buf; +		while (len--) { +			c = *b++; +			for (bit = 0; bit < 8; bit++) { +				ao_aprs_bit(c & 0x80); +				c <<= 1; +			} +		} +	} +} diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 7180f02d..cdd1f236 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -236,10 +236,14 @@ extern int32_t	ao_accel_scale;  extern alt_t	ao_ground_height;  extern alt_t	ao_sample_alt; +double ao_sample_qangle; +  int ao_sample_prev_tick;  uint16_t	prev_tick; +  #include "ao_kalman.c" +#include "ao_sqrt.c"  #include "ao_sample.c"  #include "ao_flight.c" @@ -309,7 +313,7 @@ ao_mpu6000_accel(int16_t sensor)  }  static double -ao_mpu6000_gyro(int16_t sensor) +ao_mpu6000_gyro(int32_t sensor)  {  	return sensor / 32767.0 * MPU6000_GYRO_FULLSCALE;  } @@ -370,6 +374,7 @@ ao_insert(void)  		if (!ao_summary) {  			printf("%7.2f height %8.2f accel %8.3f "  #if MEGAMETRUM +			       "roll %8.3f angle %8.3f qangle %8.3f "  			       "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f "  #endif  			       "state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n", @@ -377,6 +382,9 @@ ao_insert(void)  			       height,  			       accel,  #if MEGAMETRUM +			       ao_mpu6000_gyro(ao_sample_roll_angle) / 100.0, +			       ao_mpu6000_gyro(ao_sample_angle) / 100.0, +			       ao_sample_qangle,  			       ao_mpu6000_accel(ao_data_static.mpu6000.accel_x),  			       ao_mpu6000_accel(ao_data_static.mpu6000.accel_y),  			       ao_mpu6000_accel(ao_data_static.mpu6000.accel_z), @@ -547,6 +555,207 @@ int32(uint8_t *bytes, int off)  static int log_format; +#if MEGAMETRUM + +static double +ao_vec_norm(double x, double y, double z) +{ +	return x*x + y*y + z*z; +} + +static void +ao_vec_normalize(double *x, double *y, double *z) +{ +	double	scale = 1/sqrt(ao_vec_norm(*x, *y, *z)); + +	*x *= scale; +	*y *= scale; +	*z *= scale; +} + +struct ao_quat { +	double	q0, q1, q2, q3; +}; + +static void +ao_quat_mul(struct ao_quat *r, struct ao_quat *a, struct ao_quat *b) +{ +	r->q0 = a->q0 * b->q0 - a->q1 * b->q1 - a->q2 * b->q2 - a->q3 * b->q3; +	r->q1 = a->q0 * b->q1 + a->q1 * b->q0 + a->q2 * b->q3 - a->q3 * b->q2; +	r->q2 = a->q0 * b->q2 - a->q1 * b->q3 + a->q2 * b->q0 + a->q3 * b->q1; +	r->q3 = a->q0 * b->q3 + a->q1 * b->q2 - a->q2 * b->q1 + a->q3 * b->q0; +} + +#if 0 +static void +ao_quat_scale(struct ao_quat *r, struct ao_quat *a, double s) +{ +	r->q0 = a->q0 * s; +	r->q1 = a->q1 * s; +	r->q2 = a->q2 * s; +	r->q3 = a->q3 * s; +} +#endif + +static void +ao_quat_conj(struct ao_quat *r, struct ao_quat *a) +{ +	r->q0 =  a->q0; +	r->q1 = -a->q1; +	r->q2 = -a->q2; +	r->q3 = -a->q3; +} + +static void +ao_quat_rot(struct ao_quat *r, struct ao_quat *a, struct ao_quat *q) +{ +	struct ao_quat	t; +	struct ao_quat	c; +	ao_quat_mul(&t, q, a); +	ao_quat_conj(&c, q); +	ao_quat_mul(r, &t, &c); +} + +static void +ao_quat_from_angle(struct ao_quat *r, +		   double x_rad, +		   double y_rad, +		   double z_rad) +{ +	double angle = sqrt (x_rad * x_rad + y_rad * y_rad + z_rad * z_rad); +	double s = sin(angle/2); +	double c = cos(angle/2); + +	r->q0 = c; +	r->q1 = x_rad * s / angle; +	r->q2 = y_rad * s / angle; +	r->q3 = z_rad * s / angle; +} + +static void +ao_quat_from_vector(struct ao_quat *r, double x, double y, double z) +{ +	ao_vec_normalize(&x, &y, &z); +	double	x_rad = atan2(z, y); +	double	y_rad = atan2(x, z); +	double	z_rad = atan2(y, x); + +	ao_quat_from_angle(r, x_rad, y_rad, z_rad); +} + +static double +ao_quat_norm(struct ao_quat *a) +{ +	return (a->q0 * a->q0 + +		a->q1 * a->q1 + +		a->q2 * a->q2 + +		a->q3 * a->q3); +} + +static void +ao_quat_normalize(struct ao_quat *a) +{ +	double	norm = ao_quat_norm(a); + +	if (norm) { +		double m = 1/sqrt(norm); + +		a->q0 *= m; +		a->q1 *= m; +		a->q2 *= m; +		a->q3 *= m; +	} +} + +static struct ao_quat	ao_up, ao_current; +static struct ao_quat	ao_orient; +static int		ao_orient_tick; + +void +set_orientation(double x, double y, double z, int tick) +{ +	struct ao_quat	t; + +	printf ("set_orientation %g %g %g\n", x, y, z); +	ao_quat_from_vector(&ao_orient, x, y, z); +	ao_up.q1 = ao_up.q2 = 0; +	ao_up.q0 = ao_up.q3 = sqrt(2)/2; +	ao_orient_tick = tick; + +	ao_orient.q0 = 1; +	ao_orient.q1 = 0; +	ao_orient.q2 = 0; +	ao_orient.q3 = 0; + +	printf ("orient (%g) %g %g %g up (%g) %g %g %g\n", +		ao_orient.q0, +		ao_orient.q1, +		ao_orient.q2, +		ao_orient.q3, +		ao_up.q0, +		ao_up.q1, +		ao_up.q2, +		ao_up.q3); + +	ao_quat_rot(&t, &ao_up, &ao_orient); +	printf ("pad orient (%g) %g %g %g\n", +		t.q0, +		t.q1, +		t.q2, +		t.q3); + +} + +void +update_orientation (double rate_x, double rate_y, double rate_z, int tick) +{ +	struct ao_quat	q_dot; +	double		lambda; +	double		dt = (tick - ao_orient_tick) / 100.0; + +	ao_orient_tick = tick; +  +//	lambda = 1 - ao_quat_norm(&ao_orient); +	lambda = 0; + +	q_dot.q0 = -0.5 * (ao_orient.q1 * rate_x + ao_orient.q2 * rate_y + ao_orient.q3 * rate_z) + lambda * ao_orient.q0; +	q_dot.q1 =  0.5 * (ao_orient.q0 * rate_x + ao_orient.q2 * rate_z - ao_orient.q3 * rate_y) + lambda * ao_orient.q1; +	q_dot.q2 =  0.5 * (ao_orient.q0 * rate_y + ao_orient.q3 * rate_x - ao_orient.q1 * rate_z) + lambda * ao_orient.q2; +	q_dot.q3 =  0.5 * (ao_orient.q0 * rate_z + ao_orient.q1 * rate_y - ao_orient.q2 * rate_x) + lambda * ao_orient.q3; + +#if 0 +	printf ("update_orientation %g %g %g (%g s)\n", rate_x, rate_y, rate_z, dt); +	printf ("q_dot (%g) %g %g %g\n", +		q_dot.q0, +		q_dot.q1, +		q_dot.q2, +		q_dot.q3); +#endif + +	ao_orient.q0 += q_dot.q0 * dt; +	ao_orient.q1 += q_dot.q1 * dt; +	ao_orient.q2 += q_dot.q2 * dt; +	ao_orient.q3 += q_dot.q3 * dt; + +	ao_quat_normalize(&ao_orient); + +	ao_quat_rot(&ao_current, &ao_up, &ao_orient); + +	ao_sample_qangle = 180 / M_PI * acos(ao_current.q3 * sqrt(2)); +#if 0 +	printf ("orient (%g) %g %g %g current (%g) %g %g %g\n", +		ao_orient.q0, +		ao_orient.q1, +		ao_orient.q2, +		ao_orient.q3, +		ao_current.q0, +		ao_current.q1, +		ao_current.q2, +		ao_current.q3); +#endif +} +#endif +  void  ao_sleep(void *wchan)  { @@ -635,6 +844,21 @@ ao_sleep(void *wchan)  						f(gyro_x);  						f(gyro_y);  						f(gyro_z); + +						double		accel_x = ao_mpu6000_accel(ao_ground_mpu6000.accel_x); +						double		accel_y = ao_mpu6000_accel(ao_ground_mpu6000.accel_y); +						double		accel_z = ao_mpu6000_accel(ao_ground_mpu6000.accel_z); + +						/* X and Y are in the ground plane, arbitraryily picked as MPU X and Z axes +						 * Z is normal to the ground, the MPU y axis +						 */ +						set_orientation(accel_x, accel_z, accel_y, tick); +					} else { +						double		rate_x = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x); +						double		rate_y = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y); +						double		rate_z = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z); + +						update_orientation(rate_x * M_PI / 180, rate_z * M_PI / 180, rate_y * M_PI / 180, tick);  					}  					ao_records_read++;  					ao_insert(); @@ -779,6 +1003,8 @@ ao_sleep(void *wchan)  				continue;  #if MEGAMETRUM +			(void) a; +			(void) b;  #else  			switch (type) {  			case 'F': diff --git a/src/test/ao_gps_test.c b/src/test/ao_gps_test.c index d75a12ec..3844a326 100644 --- a/src/test/ao_gps_test.c +++ b/src/test/ao_gps_test.c @@ -88,6 +88,7 @@ ao_mutex_put(uint8_t *mutex)  static int  ao_gps_fd; +#if 0  static void  ao_dbg_char(char c)  { @@ -103,6 +104,7 @@ ao_dbg_char(char c)  	}  	write(1, line, strlen(line));  } +#endif  #define QUEUE_LEN	4096 @@ -391,6 +393,7 @@ ao_serial1_putchar(char c)  #define AO_SERIAL_SPEED_4800	0  #define AO_SERIAL_SPEED_57600	1 +#define AO_SERIAL_SPEED_115200	2  static void  ao_serial1_set_speed(uint8_t speed) @@ -407,6 +410,9 @@ ao_serial1_set_speed(uint8_t speed)  	case AO_SERIAL_SPEED_57600:  		cfsetspeed(&termios, B57600);  		break; +	case AO_SERIAL_SPEED_115200: +		cfsetspeed(&termios, B115200); +		break;  	}  	tcsetattr(fd, TCSAFLUSH, &termios);  	tcflush(fd, TCIFLUSH); @@ -420,7 +426,6 @@ ao_serial1_set_speed(uint8_t speed)  void  ao_dump_state(void *wchan)  { -	double	lat, lon;  	int	i;  	if (wchan == &ao_gps_data)  		ao_gps_print(&ao_gps_data); @@ -510,4 +515,5 @@ main (int argc, char **argv)  	}  	ao_gps_setup();  	ao_gps(); +	return 0;  } diff --git a/src/test/ao_gps_test_skytraq.c b/src/test/ao_gps_test_skytraq.c index 846daa94..81008b39 100644 --- a/src/test/ao_gps_test_skytraq.c +++ b/src/test/ao_gps_test_skytraq.c @@ -397,6 +397,7 @@ ao_serial1_putchar(char c)  #define AO_SERIAL_SPEED_4800	0  #define AO_SERIAL_SPEED_9600	1  #define AO_SERIAL_SPEED_57600	2 +#define AO_SERIAL_SPEED_115200	3  static void  ao_serial1_set_speed(uint8_t speed) @@ -411,11 +412,14 @@ ao_serial1_set_speed(uint8_t speed)  		cfsetspeed(&termios, B4800);  		break;  	case AO_SERIAL_SPEED_9600: -		cfsetspeed(&termios, B38400); +		cfsetspeed(&termios, B9600);  		break;  	case AO_SERIAL_SPEED_57600:  		cfsetspeed(&termios, B57600);  		break; +	case AO_SERIAL_SPEED_115200: +		cfsetspeed(&termios, B115200); +		break;  	}  	tcsetattr(fd, TCSAFLUSH, &termios);  	tcflush(fd, TCIFLUSH); @@ -423,6 +427,10 @@ ao_serial1_set_speed(uint8_t speed)  #define ao_time() 0 +uint8_t	ao_task_minimize_latency; + +#define ao_usb_getchar()	0 +  #include "ao_gps_print.c"  #include "ao_gps_skytraq.c" | 
