diff options
44 files changed, 1779 insertions, 528 deletions
diff --git a/Makefile.am b/Makefile.am index cac02c62..4f47417e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,6 +64,7 @@ fat_altos = \  	src/teledongle-v0.2/teledongle-v0.2-$(VERSION).ihx \  	src/teledongle-v3.0/teledongle-v3.0-$(VERSION).ihx \  	src/telegps-v1.0/telegps-v1.0-$(VERSION).ihx \ +	src/telegps-v2.0/telegps-v2.0-$(VERSION).ihx \  	src/telemega-v1.0/telemega-v1.0-$(VERSION).ihx \  	src/telemega-v2.0/telemega-v2.0-$(VERSION).ihx \  	src/telemetrum-v1.0/telemetrum-v1.0-$(VERSION).ihx \ @@ -95,11 +95,8 @@ These are Bdale's notes on how to do a release.  		--with-fat-dir=/home/bdale/web/altusmetrum/  	make && make fat -		this pushes packages for each platform and application -		to web site, including auto-generated mdwn files and -		release notes in html format. +	- store a stable copy of ARM binaries for production use -	# store a stable copy of ARM binaries for production use  	cp src/chaoskey-v1.0/{*.elf,*.ihx} \  	   src/easymega-v1.0/{*.elf,*.ihx} \  	   src/easymini-v1.0/{*.elf,*.ihx} \ @@ -108,6 +105,7 @@ These are Bdale's notes on how to do a release.  	   src/telebt-v4.0/{*.elf,*.ihx} \  	   src/teledongle-v3.0/{*.elf,*.ihx} \  	   src/telegps-v1.0/{*.elf,*.ihx} \ +	   src/telegps-v2.0/{*.elf,*.ihx} \  	   src/telemega-v1.0/{*.elf,*.ihx} \  	   src/telemega-v2.0/{*.elf,*.ihx} \  	   src/telemetrum-v2.0/{*.elf,*.ihx} \ @@ -118,9 +116,10 @@ These are Bdale's notes on how to do a release.  	   src/easymini-v1.0/flash-loader/*.elf \  	   src/easymini-v2.0/flash-loader/{*.elf,*.bin} \  	   src/telebt-v3.0/flash-loader/*.elf \ -	   src/telebt-v4.0/flash-loader/*.elf \ +	   src/telebt-v4.0/flash-loader/{*.elf,*.bin} \  	   src/teledongle-v3.0/flash-loader/*.elf \  	   src/telegps-v1.0/flash-loader/*.elf \ +	   src/telegps-v2.0/flash-loader/*.elf \  	   src/telemega-v1.0/flash-loader/*.elf \  	   src/telemega-v2.0/flash-loader/*.elf \  	   src/telemetrum-v2.0/flash-loader/*.elf \ @@ -129,26 +128,23 @@ These are Bdale's notes on how to do a release.  	(cd ~/altusmetrumllc ; git add Binaries ; git commit -a)   	(cd ~/altusmetrumllc ; git push)  -	- copy the relevant release notes .html file from doc/ to  -	    /home/bdale/web/altusmetrum/AltOS/releases/<rev> -  	- Push new release to web site  	make fat-install  	(cd doc ; make publish) -	(cd ~/web/altusmetrum/ && git add AltOS/releases -	TeleGPS/releases MicroPeak/releases && git commit -m'Release -	<rev>' && git push origin master) +	(cd ~/web/altusmetrum/ && \ +		git add */releases && git commit -m'Release <rev>' && \ +		git push origin master) + +	- upload the Debian package  -		this pushes fresh documents to the web site +	- clean up  	sudo debian/rules clean  	git push origin master branch-<version> debian pristine-tar  	git push --tags -		push commits and leave the build tree in an uncluttered state -  Testing before a release  	To verify that a build works, the following need to be checked diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 924ab4c9..0776fa00 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -77,6 +77,75 @@ class SavedState {  	}  } +class Tracker implements CharSequence, Comparable { +	int	serial; +	String	call; +	double	frequency; + +	String	display; + +	public Tracker(int serial, String call, double frequency) { +		if (call == null) +			call = "none"; + +		this.serial = serial; +		this.call = call; +		this.frequency = frequency; +		if (frequency == 0.0) +			display = "Auto"; +		else if (frequency == AltosLib.MISSING) { +			display = String.format("%-8.8s  %6d", call, serial); +		} else { +			display = String.format("%-8.8s %7.3f %6d", call, frequency, serial); +		} +	} + +	public Tracker(AltosState s) { +		this(s == null ? 0 : s.cal_data().serial, +		     s == null ? null : s.cal_data().callsign, +		     s == null ? 0.0 : s.frequency); +	} + +	/* CharSequence */ +	public char charAt(int index) { +		return display.charAt(index); +	} + +	public int length() { +		return display.length(); +	} + +	public CharSequence subSequence(int start, int end) throws IndexOutOfBoundsException { +		return display.subSequence(start, end); +	} + +	public String toString() { +		return display.toString(); +	} + +	/* Comparable */ +	public int compareTo (Object other) { +		Tracker	o = (Tracker) other; +		if (frequency == 0.0) { +			if (o.frequency == 0.0) +				return 0; +			return -1; +		} +		if (o.frequency == 0.0) +			return 1; + +		int	a = serial - o.serial; +		int	b = call.compareTo(o.call); +		int	c = (int) Math.signum(frequency - o.frequency); + +		if (b != 0) +			return b; +		if (c != 0) +			return c; +		return a; +	} +} +  public class AltosDroid extends FragmentActivity implements AltosUnitsListener, LocationListener {  	// Actions sent to the telemetry server at startup time @@ -151,7 +220,8 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,  	private Timer timer;  	TelemetryState	telemetry_state; -	Integer[] 	serials; +	Tracker[]	trackers; +  	UsbDevice	pending_usb_device;  	boolean		start_with_usb; @@ -323,8 +393,20 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,  			AltosPreferences.register_units_listener(this);  		} -		serials = telemetry_state.states.keySet().toArray(new Integer[0]); -		Arrays.sort(serials); +		int	num_trackers = 0; +		for (AltosState s : telemetry_state.states.values()) { +			num_trackers++; +		} + +		trackers = new Tracker[num_trackers + 1]; + +		int n = 0; +		trackers[n++] = new Tracker(0, "auto", 0.0); + +		for (AltosState s : telemetry_state.states.values()) +			trackers[n++] = new Tracker(s); + +		Arrays.sort(trackers);  		update_title(telemetry_state); @@ -955,11 +1037,11 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,  		}  		if (serial != 0) { -			for (i = 0; i < serials.length; i++) -				if (serials[i] == serial) +			for (i = 0; i < trackers.length; i++) +				if (trackers[i].serial == serial)  					break; -			if (i == serials.length) { +			if (i == trackers.length) {  				AltosDebug.debug("attempt to select unknown tracker %d\n", serial);  				return;  			} @@ -972,17 +1054,22 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,  	void touch_trackers(Integer[] serials) {  		AlertDialog.Builder builder_tracker = new AlertDialog.Builder(this);  		builder_tracker.setTitle("Select Tracker"); -		final String[] trackers = new String[serials.length + 1]; -		trackers[0] = "Auto"; -		for (int i = 0; i < serials.length; i++) -			trackers[i+1] = String.format("%d", serials[i]); -		builder_tracker.setItems(trackers, + +		final Tracker[] my_trackers = new Tracker[serials.length + 1]; + +		my_trackers[0] = new Tracker(null); + +		for (int i = 0; i < serials.length; i++) { +			AltosState	s = telemetry_state.states.get(serials[i]); +			my_trackers[i+1] = new Tracker(s); +		} +		builder_tracker.setItems(my_trackers,  					 new DialogInterface.OnClickListener() {  						 public void onClick(DialogInterface dialog, int item) {  							 if (item == 0)  								 select_tracker(0);  							 else -								 select_tracker(Integer.parseInt(trackers[item])); +								 select_tracker(my_trackers[item].serial);  						 }  					 });  		AlertDialog alert_tracker = builder_tracker.create(); @@ -1040,20 +1127,17 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,  			alert_freq.show();  			return true;  		case R.id.select_tracker: -			if (serials != null) { -				String[] trackers = new String[serials.length+1]; -				trackers[0] = "Auto"; -				for (int i = 0; i < serials.length; i++) -					trackers[i+1] = String.format("%d", serials[i]); +			if (trackers != null) {  				AlertDialog.Builder builder_serial = new AlertDialog.Builder(this);  				builder_serial.setTitle("Select a tracker");  				builder_serial.setItems(trackers,  							new DialogInterface.OnClickListener() {  								public void onClick(DialogInterface dialog, int item) { +									System.out.printf("select item %d %s\n", item, trackers[item].display);  									if (item == 0)  										select_tracker(0);  									else -										select_tracker(serials[item-1]); +										select_tracker(trackers[item].serial);  								}  							});  				AlertDialog alert_serial = builder_serial.create(); @@ -1062,16 +1146,16 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,  			}  			return true;  		case R.id.delete_track: -			if (serials != null) { -				String[] trackers = new String[serials.length]; -				for (int i = 0; i < serials.length; i++) -					trackers[i] = String.format("%d", serials[i]); +			if (trackers != null) {  				AlertDialog.Builder builder_serial = new AlertDialog.Builder(this);  				builder_serial.setTitle("Delete a track"); -				builder_serial.setItems(trackers, +				final Tracker[] my_trackers = new Tracker[trackers.length - 1]; +				for (int i = 0; i < trackers.length - 1; i++) +					my_trackers[i] = trackers[i+1]; +				builder_serial.setItems(my_trackers,  							new DialogInterface.OnClickListener() {  								public void onClick(DialogInterface dialog, int item) { -									delete_track(serials[item]); +									delete_track(my_trackers[item].serial);  								}  							});  				AlertDialog alert_serial = builder_serial.create(); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java index d097a550..69685dc7 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java @@ -60,6 +60,7 @@ public class TelemetryReader extends Thread {  			while (telemQueue != null) {  				try {  					AltosTelemetry	telem = read(); +					telem.set_frequency(link.frequency);  					handler.obtainMessage(TelemetryService.MSG_TELEMETRY, telem).sendToTarget();  				} catch (ParseException pp) {  					AltosDebug.error("Parse error: %d \"%s\"", pp.getErrorOffset(), pp.getMessage()); diff --git a/altoslib/AltosAccelCal.java b/altoslib/AltosAccelCal.java new file mode 100644 index 00000000..03d9fbf2 --- /dev/null +++ b/altoslib/AltosAccelCal.java @@ -0,0 +1,217 @@ +/* + * Copyright © 2017 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 3 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.altusmetrum.altoslib_12; + +import java.io.*; +import java.util.concurrent.*; + +public class AltosAccelCal implements Runnable { + +	AltosLink		link; +	AltosAccelCalListener	listener; + +	boolean			remote; +	boolean			close_on_exit; +	double			frequency; +	String			callsign; + +	Thread			accel_thread; + +	AltosConfigData		config_data; + +	public static final int	phase_antenna_up = 0; +	public static final int	phase_antenna_down = 1; + +	void start_link() throws InterruptedException, TimeoutException { +		if (remote) { +			link.set_radio_frequency(frequency); +			link.set_callsign(callsign); +			link.start_remote(); +		} else +			link.flush_input(); +	} + +	boolean stop_link() throws InterruptedException, TimeoutException { +		if (remote) +			link.stop_remote(); +		return link.reply_abort; +	} + +	public void set_frequency(double in_frequency) { +		frequency = in_frequency; +		link.abort_reply(); +	} + +	public void set_callsign(String in_callsign) { +		callsign = in_callsign; +		link.abort_reply(); +	} + +	public void abort() throws InterruptedException { +		while (accel_thread.isAlive()) { +			accel_thread.interrupt(); +			link.abort_reply(); +			Thread.sleep(100); +		} +		accel_thread.join(); +	} + +	static private final String press_msg = "press a key..."; + +	private Semaphore ui_signal_semaphore; +	private boolean ui_signal_reply; + +	public void signal(boolean reply) { +		System.out.printf("Signal cal semaphore %b\n", reply); +		ui_signal_reply = reply; +		ui_signal_semaphore.release(); +	} + +	private boolean wait_signal() throws InterruptedException { +		System.out.printf("\twait for cal signal...\n"); +		ui_signal_semaphore.acquire(); +		System.out.printf("\tgot cal signal %b\n", ui_signal_reply); +		return ui_signal_reply; +	} + +	private boolean wait_press(int timeout) throws InterruptedException { +		for (;;) { +			String line = link.get_reply(timeout); +			if (line == null) { +				System.out.printf("get_reply timeout\n"); +				return false; +			} +			System.out.printf("got line %s\n", line); +			if (line.contains(press_msg)) +				return true; +			if (line.contains("Invalid")) +				return false; +			if (line.contains("Syntax")) +				return false; +			if (line.contains("Calibrating")) +				listener.message(this, line); +		} +	} + +	static final int cal_timeout = 20 * 1000; + +	public void run() { +		System.out.printf("start accel cal procedure\n"); +		try { +			AltosConfigData new_config = null; + +			try { +				start_link(); +				config_data = link.config_data(); + +				/* set back to antenna up for calibration */ +				if (config_data.pad_orientation != 0) +					link.printf("c o 0\n"); + +				/* Start calibration */ +				try { +					System.out.printf("*** start cal\n"); +					link.set_match(press_msg); +					link.printf("c a 0\n"); +					System.out.printf("*** wait press\n"); +					if (!wait_press(cal_timeout)) +						throw new TimeoutException("timeout"); +					System.out.printf("*** set_phase antenna_up\n"); +					listener.set_phase(this, phase_antenna_up); +					System.out.printf("*** wait_signal\n"); +					if (!wait_signal()) +						throw new InterruptedException("aborted"); +					link.set_match(press_msg); +					System.out.printf("*** send newline\n"); +					link.printf("\n"); +					System.out.printf("*** wait press\n"); +					if (!wait_press(cal_timeout)) +						throw new TimeoutException("timeout"); +					System.out.printf("***set_phase antenna_down\n"); +					listener.set_phase(this, phase_antenna_down); +					System.out.printf("*** wait_signal\n"); +					if (!wait_signal()) +						throw new InterruptedException("aborted"); +					System.out.printf("*** send newline and version command\n"); +					link.printf("\nv\n"); +				} catch (TimeoutException e) { +					throw e; +				} catch (InterruptedException e) { +					throw e; +				} +				link.set_match(null); + +				boolean worked = true; +				for (;;) { +					String line = link.get_reply(cal_timeout); +					if (line == null) +						throw new TimeoutException(); +					System.out.printf("*** waiting for finish: %s\n", line); +					if (line.contains("Invalid")) +						worked = false; +					if (line.contains("software-version")) +						break; +					if (line.contains("Calibrating")) +						listener.message(this, line); +				} +				System.out.printf("*** worked: %b\n", worked); +				if (worked) +					new_config = new AltosConfigData(link); +			} finally { +				System.out.printf("Restore orientation %d +g %d -g %d\n", +						  config_data.pad_orientation, +						  config_data.accel_cal_plus, +						  config_data.accel_cal_minus); +				if (config_data.pad_orientation != AltosLib.MISSING && config_data.pad_orientation != 0) +					link.printf("c o %d\n", config_data.pad_orientation); +				if (config_data.accel_cal_plus != AltosLib.MISSING && config_data.accel_cal_minus != AltosLib.MISSING) +					link.printf("c a %d %d\n", +						    config_data.accel_cal_plus, config_data.accel_cal_minus); +				stop_link(); +			} +			if (new_config != null) { +				System.out.printf("*** +1g %d -1g %d\n", +						  new_config.accel_cal_plus, +						  new_config.accel_cal_minus); +				listener.cal_done(this, new_config.accel_cal_plus, new_config.accel_cal_minus); +				if (!wait_signal()) +					throw new InterruptedException("aborted"); +			} else +				listener.error(this, "Calibration failed"); +		} catch (TimeoutException te) { +			System.out.printf("timeout"); +			listener.error(this, "timeout"); +		} catch (InterruptedException ie) { +			System.out.printf("interrupted\n"); +			listener.error(this, "interrupted"); +		} +	} + +	public void start() { +		accel_thread = new Thread(this); +		listener.set_thread(this, accel_thread); +		accel_thread.start(); +	} + +	public AltosAccelCal(AltosLink link, AltosAccelCalListener listener) { +		this.link = link; +		this.listener = listener; +		ui_signal_semaphore = new Semaphore(0); +	} +} diff --git a/altoslib/AltosAccelCalListener.java b/altoslib/AltosAccelCalListener.java new file mode 100644 index 00000000..17359245 --- /dev/null +++ b/altoslib/AltosAccelCalListener.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2017 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 3 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.altusmetrum.altoslib_12; + +import java.io.*; +import java.util.concurrent.*; + +public interface AltosAccelCalListener { +	public void set_thread(AltosAccelCal cal, Thread thread); + +	public void set_phase(AltosAccelCal cal, int phase); + +	public void cal_done(AltosAccelCal cal, int plus, int minus); + +	public void error(AltosAccelCal cal, String msg); + +	public void message(AltosAccelCal cal, String msg); +} diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 63c34310..dc036867 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -405,7 +405,7 @@ public class AltosConfigData {  		/* HAS_GYRO */  		try { -			if (line.startsWith("IMU call along")) { +			if (line.startsWith("IMU cal along")) {  				String[] bits = line.split("\\s+");  				if (bits.length >= 8) {  					accel_zero_along = Integer.parseInt(bits[3]); @@ -525,6 +525,12 @@ public class AltosConfigData {  		if (pad_orientation != AltosLib.MISSING)  			pad_orientation = source.pad_orientation(); +		if (accel_cal_plus != AltosLib.MISSING) +			accel_cal_plus = source.accel_cal_plus(); + +		if (accel_cal_minus != AltosLib.MISSING) +			accel_cal_minus = source.accel_cal_minus(); +  		/* HAS_LOG */  		if (flight_log_max != AltosLib.MISSING)  			flight_log_max = source.flight_log_max(); @@ -592,6 +598,7 @@ public class AltosConfigData {  		dest.set_flight_log_max(flight_log_max);  		dest.set_ignite_mode(ignite_mode);  		dest.set_pad_orientation(pad_orientation); +		dest.set_accel_cal(accel_cal_plus, accel_cal_minus);  		dest.set_callsign(callsign);  		if (npyro != AltosLib.MISSING)  			dest.set_pyros(pyros); @@ -669,9 +676,10 @@ public class AltosConfigData {  			link.printf("c e %d\n", radio_enable);  		/* HAS_ACCEL */ -		/* UI doesn't support accel cal */  		if (pad_orientation != AltosLib.MISSING)  			link.printf("c o %d\n", pad_orientation); +		if (accel_cal_plus != AltosLib.MISSING && accel_cal_minus != AltosLib.MISSING) +			link.printf("c a %d %d\n", accel_cal_plus, accel_cal_minus);  		/* HAS_LOG */  		if (flight_log_max != 0) diff --git a/altoslib/AltosConfigValues.java b/altoslib/AltosConfigValues.java index 170b1112..10478fd4 100644 --- a/altoslib/AltosConfigValues.java +++ b/altoslib/AltosConfigValues.java @@ -74,6 +74,16 @@ public interface AltosConfigValues {  	public abstract int pad_orientation(); +	public abstract void set_accel_cal(int accel_cal_plus, int accel_cal_minus); + +	public abstract int accel_cal_plus(); + +	public abstract int accel_cal_minus(); + +	public abstract void set_dirty(); + +	public abstract void set_clean(); +  	public abstract void set_pyros(AltosPyro[] new_pyros);  	public abstract AltosPyro[] pyros() throws AltosConfigDataException; diff --git a/altoslib/AltosDataListener.java b/altoslib/AltosDataListener.java index 5f89b3e4..be6d840f 100644 --- a/altoslib/AltosDataListener.java +++ b/altoslib/AltosDataListener.java @@ -20,6 +20,7 @@ public abstract class AltosDataListener {  	public double		time = AltosLib.MISSING;  	public int		state = AltosLib.MISSING; +	public double		frequency = AltosLib.MISSING;  	public void set_tick(int tick) {  		cal_data.set_tick(tick); @@ -55,6 +56,10 @@ public abstract class AltosDataListener {  		cal_data().set_flight(flight);  	} +	public void set_frequency(double frequency) { +		this.frequency = frequency; +	} +  	/* Called after all records are captured */  	public void finish() {  	} diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java index c2e4e2a3..ea1a9675 100644 --- a/altoslib/AltosFlightStats.java +++ b/altoslib/AltosFlightStats.java @@ -212,8 +212,11 @@ public class AltosFlightStats {  					add_times(series, (int) prev.value, prev.time, state.time);  				prev = state;  			} -			if (prev != null) -				add_times(series, (int) prev.value, prev.time, series.accel_series.last().time); +			if (prev != null) { +				AltosTimeValue last_accel = series.accel_series.last(); +				if (last_accel != null) +					add_times(series, (int) prev.value, prev.time, last_accel.time); +			}  		}  		for (int s = 0; s <= AltosLib.ao_flight_invalid; s++) { @@ -245,14 +248,15 @@ public class AltosFlightStats {  			has_gps = true;  			lat = pad_lat = gps.lat;  			lon = pad_lon = gps.lon; -			for (AltosGPSTimeValue gtv : series.gps_series) { -				gps = gtv.gps; -				if (gps.locked && gps.nsat >= 4) { -					lat = gps.lat; -					lon = gps.lon; +			if (series.gps_series != null) { +				for (AltosGPSTimeValue gtv : series.gps_series) { +					gps = gtv.gps; +					if (gps.locked && gps.nsat >= 4) { +						lat = gps.lat; +						lon = gps.lon; +					}  				}  			} -  		}  		max_height = AltosLib.MISSING; diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 5a802ef1..5413de9d 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -43,6 +43,8 @@ public abstract class AltosLink implements Runnable {  	public LinkedBlockingQueue<AltosLine> reply_queue = new LinkedBlockingQueue<AltosLine>();  	public LinkedBlockingQueue<byte[]> binary_queue = new LinkedBlockingQueue<byte[]>(); +	private String match_string = null; +  	public synchronized void add_monitor(LinkedBlockingQueue<AltosLine> q) {  		set_monitor(true);  		monitors.add(q); @@ -112,6 +114,15 @@ public abstract class AltosLink implements Runnable {  	private int	len_read = 0; +	private boolean match_bytes(byte[] bytes, int byte_count, String match) { +		if (byte_count < match.length()) +			return false; +		String	line = new String(bytes, 0, byte_count, AltosLib.unicode_set); +		if (line == null) +			return false; +		return line.indexOf(match) >= 0; +	} +  	public void run () {  		int c;  		byte[] line_bytes = null; @@ -159,6 +170,11 @@ public abstract class AltosLink implements Runnable {  							line_count = 0;  							len_read = 0;  						} +						if (match_string != null && match_bytes(line_bytes, line_count, match_string)) { +							match_string = null; +							add_bytes(line_bytes, line_count); +							line_count = 0; +						}  					}  				}  			} @@ -166,6 +182,9 @@ public abstract class AltosLink implements Runnable {  		}  	} +	public void set_match(String match) { +		match_string = match; +	}  	public String get_reply(int timeout) throws InterruptedException {  		boolean	can_cancel = can_cancel_reply(); diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 9ee3d57d..39ab10da 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -1060,7 +1060,6 @@ public class AltosState extends AltosDataListener {  	}  	public AltosState() { -		Thread.dumpStack();  		init();  	} diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index 7d576942..f17e1171 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -38,6 +38,9 @@ public abstract class AltosTelemetry implements AltosDataProvider {  	/* Mark when we received the packet */  	long		received_time; +	/* Mark frequency packet was received on */ +	public double		frequency = AltosLib.MISSING; +  	static boolean cksum(int[] bytes) {  		int	sum = 0x5a;  		for (int i = 1; i < bytes.length - 1; i++) @@ -50,6 +53,8 @@ public abstract class AltosTelemetry implements AltosDataProvider {  		listener.set_serial(serial());  		if (listener.state == AltosLib.ao_flight_invalid)  			listener.set_state(AltosLib.ao_flight_startup); +		if (frequency != AltosLib.MISSING) +			listener.set_frequency(frequency);  		listener.set_tick(tick());  		listener.set_rssi(rssi(), status());  		listener.set_received_time(received_time); @@ -108,6 +113,10 @@ public abstract class AltosTelemetry implements AltosDataProvider {  		return telem;  	} +	public void set_frequency(double frequency) { +		this.frequency = frequency; +	} +  	public AltosTelemetry() {  		this.received_time = System.currentTimeMillis();  	} diff --git a/altoslib/AltosTimeSeries.java b/altoslib/AltosTimeSeries.java index b3c432fc..9f3b4d80 100644 --- a/altoslib/AltosTimeSeries.java +++ b/altoslib/AltosTimeSeries.java @@ -151,11 +151,15 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue>, Comparable<Alt  	}  	public AltosTimeValue first() { -		return values.get(0); +		if (values.size() > 0) +			return values.get(0); +		return null;  	}  	public AltosTimeValue last() { -		return values.get(values.size() - 1); +		if (values.size() > 0) +			return values.get(values.size() - 1); +		return null;  	}  	public double average() { diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 11b5d562..08af9496 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -26,6 +26,8 @@ record_files = \  altoslib_JAVA = \  	AltosLib.java \ +	AltosAccelCal.java \ +	AltosAccelCalListener.java \  	AltosCalData.java \  	AltosCompanion.java \  	AltosConfigData.java \ diff --git a/altosui/AltosConfigFC.java b/altosui/AltosConfigFC.java index beff71b7..5e2aa7f4 100644 --- a/altosui/AltosConfigFC.java +++ b/altosui/AltosConfigFC.java @@ -268,6 +268,13 @@ public class AltosConfigFC implements ActionListener {  				if (serial_line != null)  					serial_line.close();  			} +			else if (cmd.equals("Accel")) { +				if (data.pad_orientation != AltosLib.MISSING) { +					AltosUIAccelCal accel_ui = new AltosUIAccelCal(owner, serial_line, config_ui); +					if (accel_ui != null) +						accel_ui.doit(); +				} +			}  		} catch (InterruptedException ie) {  			abort();  		} catch (TimeoutException te) { diff --git a/altosui/AltosConfigFCUI.java b/altosui/AltosConfigFCUI.java index c0c37254..1e875dec 100644 --- a/altosui/AltosConfigFCUI.java +++ b/altosui/AltosConfigFCUI.java @@ -49,6 +49,8 @@ public class AltosConfigFCUI  	JLabel			flight_log_max_label;  	JLabel			ignite_mode_label;  	JLabel			pad_orientation_label; +	JLabel			accel_plus_label; +	JLabel			accel_minus_label;  	JLabel			callsign_label;  	JLabel			beep_label;  	JLabel			tracker_motion_label; @@ -73,12 +75,15 @@ public class AltosConfigFCUI  	JComboBox<String>	flight_log_max_value;  	JComboBox<String>	ignite_mode_value;  	JComboBox<String>	pad_orientation_value; +	JTextField		accel_plus_value; +	JTextField		accel_minus_value;  	JTextField		callsign_value;  	JComboBox<String>	beep_value;  	JComboBox<String>	tracker_motion_value;  	JComboBox<String>	tracker_interval_value;  	JButton			pyro; +	JButton			accel_cal;  	JButton			save;  	JButton			reset; @@ -250,9 +255,9 @@ public class AltosConfigFCUI  	}  	void set_pad_orientation_tool_tip() { -		if (pad_orientation_value.isVisible()) +		if (pad_orientation_value.isVisible()) {  			pad_orientation_value.setToolTipText("How will the computer be mounted in the airframe"); -		else { +		} else {  			if (is_telemetrum())  				pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward");  			else if (is_telemini() || is_easymini()) @@ -262,6 +267,16 @@ public class AltosConfigFCUI  		}  	} +	void set_accel_tool_tips() { +		if (accel_plus_value.isVisible()) { +			accel_plus_value.setToolTipText("Pad acceleration value in flight orientation"); +			accel_minus_value.setToolTipText("Upside-down acceleration value"); +		} else { +			accel_plus_value.setToolTipText("No accelerometer"); +			accel_minus_value.setToolTipText("No accelerometer"); +		} +	} +  	void set_beep_tool_tip() {  		if (beep_value.isVisible())  			beep_value.setToolTipText("What frequency the beeper will sound at"); @@ -709,6 +724,57 @@ public class AltosConfigFCUI  		set_pad_orientation_tool_tip();  		row++; +		/* Accel plus */ +		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; +		accel_plus_label = new JLabel("Accel Plus:"); +		pane.add(accel_plus_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; +		accel_plus_value = new JTextField(10); +		accel_plus_value.setEditable(true); +		accel_plus_value.getDocument().addDocumentListener(this); +		pane.add(accel_plus_value, c); +		row++; + +		/* Accel minus */ +		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; +		accel_minus_label = new JLabel("Accel Minus:"); +		pane.add(accel_minus_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; +		accel_minus_value = new JTextField(10); +		accel_minus_value.setEditable(true); +		accel_minus_value.getDocument().addDocumentListener(this); +		pane.add(accel_minus_value, c); +		row++; +		set_accel_tool_tips(); +  		/* Beeper */  		c = new GridBagConstraints();  		c.gridx = 0; c.gridy = row; @@ -800,6 +866,20 @@ public class AltosConfigFCUI  		pyro.setActionCommand("Pyro");  		row++; +		/* Accel cal */ +		c = new GridBagConstraints(); +		c.gridx = 5; c.gridy = row; +		c.gridwidth = 5; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		c.ipady = 5; +		accel_cal = new JButton("Calibrate Accelerometer"); +		pane.add(accel_cal, c); +		accel_cal.addActionListener(this); +		accel_cal.setActionCommand("Accel"); +		row++; +  		/* Buttons */  		c = new GridBagConstraints();  		c.gridx = 0; c.gridy = row; @@ -873,7 +953,7 @@ public class AltosConfigFCUI  		return true;  	} -	void set_dirty() { +	public void set_dirty() {  		dirty = true;  		save.setEnabled(true);  	} @@ -912,7 +992,8 @@ public class AltosConfigFCUI  			setVisible(false);  			dispose();  		} -		set_clean(); +		if (cmd.equals("Save") || cmd.equals("Reset")) +			set_clean();  	}  	/* ItemListener interface method */ @@ -943,6 +1024,7 @@ public class AltosConfigFCUI  		radio_frequency_value.set_product(product);  		product_value.setText(product);  		set_pad_orientation_tool_tip(); +		set_accel_tool_tips();  		set_flight_log_max_tool_tip();  	} @@ -1196,6 +1278,7 @@ public class AltosConfigFCUI  		}  		pad_orientation_value.setVisible(new_pad_orientation != AltosLib.MISSING);  		pad_orientation_label.setVisible(new_pad_orientation != AltosLib.MISSING); +		accel_cal.setVisible(new_pad_orientation != AltosLib.MISSING);  		set_pad_orientation_tool_tip();  	} @@ -1207,6 +1290,31 @@ public class AltosConfigFCUI  			return AltosLib.MISSING;  	} +	public void set_accel_cal(int accel_plus, int accel_minus) { +		if (accel_plus != AltosLib.MISSING) { +			accel_plus_value.setText(String.format("%d", accel_plus)); +			accel_minus_value.setText(String.format("%d", accel_minus)); +		} +		accel_plus_value.setVisible(accel_plus != AltosLib.MISSING); +		accel_plus_label.setVisible(accel_plus != AltosLib.MISSING); +		accel_minus_value.setVisible(accel_minus != AltosLib.MISSING); +		accel_minus_label.setVisible(accel_minus != AltosLib.MISSING); + +		set_accel_tool_tips(); +	} + +	public int accel_cal_plus() { +		if (accel_plus_value.isVisible()) +			return Integer.parseInt(accel_plus_value.getText()); +		return AltosLib.MISSING; +	} + +	public int accel_cal_minus() { +		if (accel_minus_value.isVisible()) +			return Integer.parseInt(accel_minus_value.getText()); +		return AltosLib.MISSING; +	} +  	public void set_beep(int new_beep) {  		if (new_beep != AltosLib.MISSING) {  			int new_freq = (int) Math.floor (AltosConvert.beep_value_to_freq(new_beep) + 0.5); diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index f6c906c6..042f9277 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -48,7 +48,6 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt  		if (flight_series.gps_series != null) {  			for (AltosGPSTimeValue gtv : flight_series.gps_series) { -				gtv_last = gtv;  				AltosGPS gps = gtv.gps;  				if (gps != null &&  				    gps.locked && @@ -57,6 +56,7 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt  						map = new AltosUIMap();  					map.show(gps, (int) flight_series.value_before(AltosFlightSeries.state_name, gtv.time));  					this.gps = gps; +					gtv_last = gtv;  					has_gps = true;  				}  			} diff --git a/altosuilib/AltosUIAccelCal.java b/altosuilib/AltosUIAccelCal.java new file mode 100644 index 00000000..af72a21d --- /dev/null +++ b/altosuilib/AltosUIAccelCal.java @@ -0,0 +1,249 @@ +/* + * Copyright © 2017 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 3 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.altusmetrum.altosuilib_12; + +import java.awt.*; +import java.awt.event.*; +import java.beans.*; +import javax.swing.*; +import javax.swing.event.*; +import org.altusmetrum.altoslib_12.*; + +public class AltosUIAccelCal +	extends AltosUIDialog +	implements AltosAccelCalListener, ActionListener +{ +	Frame owner; +	AltosLink link; +	AltosAccelCal cal; +	AltosConfigValues	config_values; +	Thread thread; +	Container pane; +	JTextField message; +	JButton	antenna_up; +	JButton	antenna_down; +	JButton	ok; +	JButton cancel; +	boolean success; +	int accel_plus, accel_minus; + +	private void make_visible() { +		pack(); +		cal.start(); +		setVisible(true); +	} + +	public boolean doit() { +		success = false; +		make_visible(); +		return success; +	} + +	public int accel_cal_plus() { +		if (success) +			return accel_plus; +		return AltosLib.MISSING; +	} + +	public int accel_cal_minus() { +		if (success) +			return accel_minus; +		return AltosLib.MISSING; +	} + +	private void setDefaultButton(JButton button) { +		this.getRootPane().setDefaultButton(button); +	} + +	/* AltosAccelCalListener interface */ +	public void set_thread(AltosAccelCal cal, Thread thread) { +		this.thread = thread; +	} + +	public void set_phase(AltosAccelCal cal, final int phase) { +		SwingUtilities.invokeLater(new Runnable() { +				public void run() { +					switch (phase) { +					case AltosAccelCal.phase_antenna_up: +						message.setText("Orient antenna upwards and click on Antenna Up"); +						antenna_up.setEnabled(true); +						setDefaultButton(antenna_up); +						antenna_down.setEnabled(false); +						ok.setEnabled(false); +						break; +					case AltosAccelCal.phase_antenna_down: +						message.setText("Orient antenna downwards and click on Antenna Down"); +						antenna_up.setEnabled(false); +						antenna_down.setEnabled(true); +						setDefaultButton(antenna_down); +						ok.setEnabled(false); +						break; +					} +				} +			}); +	} + +	public void cal_done(AltosAccelCal cal, int plus, int minus) { +		accel_plus = plus; +		accel_minus = minus; +		success = true; +		SwingUtilities.invokeLater(new Runnable() { +				public void run() { +					message.setText(String.format("Calibration succeeded, plus %d minus %d, press OK to continue", accel_plus, accel_minus)); +					antenna_up.setEnabled(false); +					antenna_down.setEnabled(false); +					ok.setEnabled(true); +					setDefaultButton(ok); +				} +			}); +	} + +	public void message(AltosAccelCal cal, final String msg) { +		SwingUtilities.invokeLater(new Runnable() { +				public void run() { +					message.setText(msg); +				} +			}); +	} + +	public void error(AltosAccelCal cal, String msg) { +		message(cal, msg); +	} + +	/* ActionListener interface */ +	public void actionPerformed(ActionEvent e) { +		String	cmd = e.getActionCommand(); + +		if ("up".equals(cmd)) { +			cal.signal(true); +			antenna_up.setEnabled(false); +		} else if ("down".equals(cmd)) { +			cal.signal(true); +			antenna_down.setEnabled(false); +			this.setDefaultButton(antenna_down); +		} else if ("ok".equals(cmd)) { +			cal.signal(true); +			this.setVisible(false); +			if (success) { +				config_values.set_accel_cal(accel_plus, accel_minus); +				config_values.set_dirty(); +			} +			try { +				cal.abort(); +			} catch (InterruptedException ie) { +			} +		} else if ("cancel".equals(cmd)) { +			cal.signal(false); +			this.setVisible(false); +			try { +				cal.abort(); +			} catch (InterruptedException ie) { +			} +		} +	} +	public AltosUIAccelCal(Frame owner, AltosLink link, AltosConfigValues config_values) { +		super(owner, "Calibrate Accelerometer", true); + +		this.owner = owner; +		this.link = link; +		this.config_values = config_values; + +		pane = getContentPane(); +		pane.setLayout(new GridBagLayout()); + +		GridBagConstraints c = new GridBagConstraints(); +		c.insets = new Insets(4,4,4,4); + +		int x = 0; +		int y = 0; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.anchor = GridBagConstraints.WEST; +		c.gridx = x; +		c.gridy = y; +		c.gridwidth = 4; +		c.gridheight = 1; +		c.weightx = 0; +		c.weighty = 0; +		message = new JTextField(64); +		pane.add(message, c); + +		y++; x = 0; + +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.WEST; +		c.gridx = x; +		c.gridy = y; +		c.gridwidth = 1; +		c.gridheight = 1; +		c.weightx = 0; +		c.weighty = 0; +		antenna_up = new JButton("Antenna Up"); +		antenna_up.setActionCommand("up"); +		antenna_up.setEnabled(false); +		antenna_up.addActionListener(this); +		pane.add(antenna_up, c); + +		x++; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.WEST; +		c.gridx = x; +		c.gridy = y; +		c.gridwidth = 1; +		c.gridheight = 1; +		c.weightx = 0; +		c.weighty = 0; +		antenna_down = new JButton("Antenna Down"); +		antenna_down.setActionCommand("down"); +		antenna_down.setEnabled(false); +		antenna_down.addActionListener(this); +		pane.add(antenna_down, c); + +		x++; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.WEST; +		c.gridx = x; +		c.gridy = y; +		c.gridwidth = 1; +		c.gridheight = 1; +		c.weightx = 0; +		c.weighty = 0; +		ok = new JButton("OK"); +		ok.setActionCommand("ok"); +		ok.setEnabled(false); +		ok.addActionListener(this); +		pane.add(ok, c); + +		x++; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.WEST; +		c.gridx = x; +		c.gridy = y; +		c.gridwidth = 1; +		c.gridheight = 1; +		c.weightx = 0; +		c.weighty = 0; +		cancel = new JButton("Cancel"); +		cancel.setActionCommand("cancel"); +		cancel.setEnabled(true); +		cancel.addActionListener(this); +		pane.add(cancel, c); + +		cal = new AltosAccelCal(this.link, this); +	} +} diff --git a/altosuilib/Makefile.am b/altosuilib/Makefile.am index 4b5eb524..ce86d21e 100644 --- a/altosuilib/Makefile.am +++ b/altosuilib/Makefile.am @@ -13,6 +13,7 @@ altosuilib_JAVA = \  	AltosDevice.java \  	AltosDeviceDialog.java \  	AltosPositionListener.java \ +	AltosUIAccelCal.java \  	AltosUIConfigure.java \  	AltosUIAxis.java \  	AltosUIDataMissing.java \ diff --git a/ao-bringup/test-telegps b/ao-bringup/test-telegps-v1 index 0b275802..0b275802 100755 --- a/ao-bringup/test-telegps +++ b/ao-bringup/test-telegps-v1 diff --git a/ao-bringup/test-telegps-v2 b/ao-bringup/test-telegps-v2 new file mode 100755 index 00000000..b103aed4 --- /dev/null +++ b/ao-bringup/test-telegps-v2 @@ -0,0 +1,52 @@ +#!/bin/sh + +VERSION=2.0 +PRODUCT=TeleGPS +BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` + +echo "$PRODUCT-v$VERSION Test Program" +echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2" +echo +echo "Expectations:" +echo "\t$PRODUCT v$VERSION powered from USB" +echo + +ret=1 +ao-list | while read product serial dev; do +    case "$product" in +	"$PRODUCT-v$VERSION") + +	    echo "Testing $product $serial $dev" + +	    FLASHSIZE=2097152 + +	    echo "Testing flash" +	    ../ao-tools/ao-test-flash/ao-test-flash --tty="$dev" "$FLASHSIZE" + +	    case $? in +		0) +		    ;; +		*) +		    echo "failed" +		    exit 1 +	    esac + +	    echo "Testing GPS" +	    ../ao-tools/ao-test-gps/ao-test-gps --tty="$dev" + +	    case $? in +		0) +		    ;; +		*) +		    echo "failed" +		    exit 1 +	    esac + +	    echo "$PRODUCT-v$VERSION" serial "$serial" passed functional tests +	    ret=0 +	    ;; +	*) +	    echo "Skipping $product $serial $dev" +	    ;; +    esac +done diff --git a/ao-bringup/turnon_telebt b/ao-bringup/turnon_telebt index 912ba459..fb8318b3 100755 --- a/ao-bringup/turnon_telebt +++ b/ao-bringup/turnon_telebt @@ -80,7 +80,7 @@ else  fi  echo -n "checking BTLE functionality... " -btdev=`sudo timeout -s SIGINT 5s hcitool lescan | awk -F \- '/TeleBT/ { print $2 }'` +btdev=`sudo timeout -s SIGINT 5s hcitool lescan | awk -F \- '/TeleBT/ { print $2 }' | head -n 1`  if [ "$btdev" = "$SERIAL" ]; then  	echo "working!"  else diff --git a/ao-bringup/turnon_telegps b/ao-bringup/turnon_telegps index b6da2898..fd879abd 100755 --- a/ao-bringup/turnon_telegps +++ b/ao-bringup/turnon_telegps @@ -1,12 +1,10 @@  #!/bin/sh -if [ -x ../ao-tools/ao-flash/ao-flash-lpc ]; then -        FLASH_LPC=../ao-tools/ao-flash/ao-flash-lpc -elif [ -x /usr/bin/ao-flash-lpc ]; then -        FLASH_LPC=/usr/bin/ao-flash-lpc +if [ -x /usr/bin/dfu-util ]; then +    DFU_UTIL=/usr/bin/dfu-util  else -        echo "Can't find ao-flash-lpc!  Aborting." -        exit 1 +    echo "Can't find dfu-util! Aborting." +    exit 1  fi  if [ -x /usr/bin/ao-usbload ]; then @@ -17,16 +15,17 @@ else  fi  PRODUCT=TeleGPS -VERSION=1.0 -BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` -echo $FILE +VERSION=2.0 +REPO=~/altusmetrumllc/Binaries + +#BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` +#echo $FILE  echo "$PRODUCT v$VERSION Turn-On and Calibration Program" -echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2" +echo "Copyright 2017 by Bdale Garbee.  Released under GPL v3+"  echo  echo "Expectations:" -echo "\t$PRODUCT v$VERSION powered from USB" -echo "\t\twith ST-Link-V2 cabled to debug header" +echo "\t$PRODUCT v$VERSION powered from / attached to USB on this computer"  echo  case $# in @@ -47,35 +46,31 @@ esac  #  # Use released versions of everything  # -FLASH_FILE=~/altusmetrumllc/Binaries/loaders/telegps-v1.0-altos-flash-*.elf -ALTOS_FILE=~/altusmetrumllc/Binaries/telegps-v1.0-*.elf - -echo $FLASH_LPC $FLASH_FILE +FLASH_FILE=$REPO/loaders/telegps-v2.0-altos-flash-*.bin +ALTOS_FILE=$REPO/telegps-v2.0-*.elf -$FLASH_LPC $FLASH_FILE || exit 1 +$DFU_UTIL -a 0 -s 0x08000000:leave -D $FLASH_FILE || exit 1  sleep 2 -echo $USBLOAD $ALTOS_FILE -  $USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1 -sleep 2 +sleep 3 -dev=`ao-list | awk '/TeleGPS-v'"$VERSION"'/ { print $3; exit(0); }'` +dev=`ao-list | awk '/'"$PRODUCT"'-v'"$VERSION"'/ { print $3; exit(0); }'`  case "$dev" in  /dev/tty*) -        echo "TeleGPS found on $dev" +        echo "$PRODUCT found on $dev"          ;;  *) -        echo 'No TeleGPS-v'"$VERSION"' found' +        echo 'No '"$PRODUCT"'-v'"$VERSION"' found'          exit 1          ;;  esac  SERIAL=$SERIAL ./cal-freq $dev -./test-telegps +./test-telegps-v2  exit $? diff --git a/ao-bringup/turnon_telegps_v1 b/ao-bringup/turnon_telegps_v1 new file mode 100755 index 00000000..5341acc7 --- /dev/null +++ b/ao-bringup/turnon_telegps_v1 @@ -0,0 +1,81 @@ +#!/bin/sh + +if [ -x ../ao-tools/ao-flash/ao-flash-lpc ]; then +        FLASH_LPC=../ao-tools/ao-flash/ao-flash-lpc +elif [ -x /usr/bin/ao-flash-lpc ]; then +        FLASH_LPC=/usr/bin/ao-flash-lpc +else +        echo "Can't find ao-flash-lpc!  Aborting." +        exit 1 +fi + +if [ -x /usr/bin/ao-usbload ]; then +	USBLOAD=/usr/bin/ao-usbload +else +	echo "Can't find ao-usbload!  Aborting." +	exit 1 +fi + +PRODUCT=TeleGPS +VERSION=1.0 +BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` +echo $FILE + +echo "$PRODUCT v$VERSION Turn-On and Calibration Program" +echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2" +echo +echo "Expectations:" +echo "\t$PRODUCT v$VERSION powered from USB" +echo "\t\twith ST-Link-V2 cabled to debug header" +echo + +case $# in +    1) +	SERIAL="$1" +	echo "$PRODUCT-$VERSION serial number: $SERIAL"  +	;; +    0) +	echo -n "$PRODUCT-$VERSION serial number: " +	read SERIAL +	;; +    *) +	echo "Usage: $0 <serial-number>" 1>&2 +	exit 1; +	;; +esac + +# +# Use released versions of everything +# +FLASH_FILE=~/altusmetrumllc/Binaries/loaders/telegps-v1.0-altos-flash-*.elf +ALTOS_FILE=~/altusmetrumllc/Binaries/telegps-v1.0-*.elf + +echo $FLASH_LPC $FLASH_FILE + +$FLASH_LPC $FLASH_FILE || exit 1 + +sleep 2 + +echo $USBLOAD $ALTOS_FILE + +$USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1 + +sleep 2 + +dev=`ao-list | awk '/TeleGPS-v'"$VERSION"'/ { print $3; exit(0); }'` + +case "$dev" in +/dev/tty*) +        echo "TeleGPS found on $dev" +        ;; +*) +        echo 'No TeleGPS-v'"$VERSION"' found' +        exit 1 +        ;; +esac + +SERIAL=$SERIAL ./cal-freq $dev + +./test-telegps-v1 + +exit $? diff --git a/ao-tools/ao-chaosread/Makefile.am b/ao-tools/ao-chaosread/Makefile.am index 581eb2d2..6ba8885c 100644 --- a/ao-tools/ao-chaosread/Makefile.am +++ b/ao-tools/ao-chaosread/Makefile.am @@ -1,6 +1,6 @@  bin_PROGRAMS=ao-chaosread -AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) +AM_CFLAGS=$(LIBUSB_CFLAGS) -Wall -Wextra  ao_chaosread_LDADD=$(LIBUSB_LIBS) diff --git a/ao-tools/ao-chaosread/ao-chaosread.c b/ao-tools/ao-chaosread/ao-chaosread.c index 7808f6c9..6d860139 100644 --- a/ao-tools/ao-chaosread/ao-chaosread.c +++ b/ao-tools/ao-chaosread/ao-chaosread.c @@ -74,7 +74,7 @@ chaoskey_match(libusb_device *dev, char *match_serial)  		goto out;  	} -	ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, device_serial, match_len + 1); +	ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *) device_serial, match_len + 1);  	if (ret < 0) {  		fprintf(stderr, "failed to get serial number: %s\n", libusb_strerror(ret)); @@ -103,7 +103,6 @@ chaoskey_open(char *serial)  	int		ret;  	ssize_t		num;  	libusb_device	**list; -	libusb_device	*device = NULL;  	int		d;  	ck = calloc(sizeof (struct chaoskey), 1); @@ -173,12 +172,6 @@ chaoskey_close(struct chaoskey *ck)  	free(ck);  } -void -chaoskey_transfer_callback(struct libusb_transfer *transfer) -{ -	struct chaoskey *ck = transfer->user_data; -} -  #define ENDPOINT	0x86  int @@ -202,7 +195,9 @@ chaoskey_read(struct chaoskey *ck, void *buffer, int len)  		}  		len -= transferred;  		buf += transferred; +		total += transferred;  	} +	return total;  }  static const struct option options[] = { @@ -283,8 +278,17 @@ main (int argc, char **argv)  			int i;  			for (i = 0; i < got / 2; i++)  				putchar((buf[i] >> 1 & 0xff)); -		} else -			write(1, buf, got); +		} else { +			int i; +			int ret; +			for (i = 0; i < got; i += ret) { +				ret = write(1, ((char *) buf) + i, got - i); +				if (ret <= 0) { +					perror("write"); +					exit(1); +				} +			} +		}  		length -= got;  	}  	exit(0); diff --git a/configure.ac b/configure.ac index dc80f6e3..2bf6c7e3 100644 --- a/configure.ac +++ b/configure.ac @@ -18,13 +18,13 @@ dnl  dnl Process this file with autoconf to create configure.  AC_PREREQ(2.57) -AC_INIT([altos], 1.8.1) -ANDROID_VERSION=15 +AC_INIT([altos], 1.8.2) +ANDROID_VERSION=16  AC_CONFIG_SRCDIR([src/kernel/ao.h])  AM_INIT_AUTOMAKE([foreign dist-bzip2])  AM_MAINTAINER_MODE -RELEASE_DATE=2017-08-27 +RELEASE_DATE=2017-09-18  AC_SUBST(RELEASE_DATE)  VERSION_DASH=`echo $VERSION | sed 's/\./-/g'` diff --git a/doc/Makefile b/doc/Makefile index 5b264e02..b1bff848 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -3,6 +3,7 @@  #  RELNOTES_INC=\ +	release-notes-1.8.2.inc \  	release-notes-1.8.1.inc \  	release-notes-1.8.inc \  	release-notes-1.7.inc \ diff --git a/doc/altusmetrum-docinfo.xml b/doc/altusmetrum-docinfo.xml index 595422f1..c2bc14d1 100644 --- a/doc/altusmetrum-docinfo.xml +++ b/doc/altusmetrum-docinfo.xml @@ -47,6 +47,14 @@  <revhistory>    <?dbhtml filename="altusmetrum-revhistory.html"?>    <revision> +    <revnumber>1.8.2</revnumber> +    <date>18 Sep 2017</date> +    <revremark> +      Support TeleGPS v2.0 hardware. Add accelerometer recalibration +      UI. +    </revremark> +  </revision> +  <revision>      <revnumber>1.8.1</revnumber>      <date>27 Aug 2017</date>      <revremark> diff --git a/doc/config-device.inc b/doc/config-device.inc index 35848882..99d5c008 100644 --- a/doc/config-device.inc +++ b/doc/config-device.inc @@ -206,6 +206,22 @@ ifdef::telegps[]  		in the log.  endif::telegps[] +ifdef::telemega,easymega,telemetrum[] + +	==== Calibrate Accelerometer + +		This opens a separate window to recalibrate the +		accelerometers. Follow the instructions, orienting the +		flight computer with the antenna end, or end opposite +		the screw terminals, in the case of EasyMega, first up +		and then down. + +		When the calibration is complete, return to the +		Configure Altimeter window and save the new +		calibration values. + +endif::telemega,easymega,telemetrum[] +  ifdef::telemega,easymega[]  	==== Configure Pyro Channels diff --git a/doc/release-notes-1.8.2.inc b/doc/release-notes-1.8.2.inc new file mode 100644 index 00000000..2923ec11 --- /dev/null +++ b/doc/release-notes-1.8.2.inc @@ -0,0 +1,28 @@ += Release Notes for Version 1.8.2 +:toc!: +:doctype: article + +	Version 1.8.2 includes support for TeleGPS version 2.0 along +	with accelerometer recalibration support in AltosUI. + +	1.8.2 also contains a couple of minor fixes for AltosUI when +	analyzing saved data files. + +	== AltOS + +	AltOS New Features + +	* Support for TeleGPS version 2.0 hardware. + +	== AltosUI and TeleGPS Applications + +	AltosUI and TeleGPS New Features + +	* Support for TeleGPS version 2.0. + +	* Accelerometer re-calibration user interface. + +	AltosUI and TeleGPS Bug Fixes + +	* Prevent some crashes when reading older saved flight data +          for graphing or KML export. diff --git a/doc/release-notes.inc b/doc/release-notes.inc index adcf57ed..a102b2dc 100644 --- a/doc/release-notes.inc +++ b/doc/release-notes.inc @@ -2,6 +2,10 @@  == Release Notes  	:leveloffset: 2 +	include::release-notes-1.8.2.raw[] + +	<<<< +	:leveloffset: 2  	include::release-notes-1.8.1.raw[]  	<<<< diff --git a/doc/usage.inc b/doc/usage.inc index 29587b7e..d010f398 100644 --- a/doc/usage.inc +++ b/doc/usage.inc @@ -238,14 +238,16 @@  		ifdef::radio[disabled, and the radio goes into transmit-only mode.]  		ifndef::radio[disabled.]  		The only way to get out of this -		mode is to power the flight computer down. +		mode is to power the flight computer down. See below for how to get the flight +		computer to come up in Flight/Pad mode at power on.  		Idle::  		The flight computer is ready to communicate over USB  		ifdef::radio[and in packet mode over the radio.]  		You can configure  		the flight computer, download data or display -		the current state. +		the current state. See below for how to get the flight +		computer to come up in Idle mode at power on.  		ifdef::telemetrum,easymega,telemega[]  		For flight computers with accelerometers (TeleMetrum, diff --git a/src/Makefile b/src/Makefile index 25e43a0e..661fd333 100644 --- a/src/Makefile +++ b/src/Makefile @@ -35,6 +35,7 @@ ARMM3DIRS=\  	megadongle-v0.1 megadongle-v0.1/flash-loader \  	telegps-v0.3 telegps-v0.3/flash-loader \  	telegps-v1.0 telegps-v1.0/flash-loader \ +	telegps-v2.0 telegps-v2.0/flash-loader \  	telelco-v0.2 telelco-v0.2/flash-loader \  	telelco-v0.3 telelco-v0.3/flash-loader \  	telescience-v0.2 telescience-v0.2/flash-loader \ diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index b1227aaa..7cda053d 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -153,10 +153,20 @@ ao_trng_send(void)  	ao_crc_reset(); -	ao_delay(TRNG_ENABLE_DELAY); -  	for (s = 0; s < AO_TRNG_START_WAIT; s++) { -		if (ao_trng_get_cooked(buffer[0])) +		int i; +		uint16_t	min, max; +		uint16_t	buf[AO_USB_IN_SIZE>>1]; + +		ao_trng_get_raw(buf); +		min = max = buf[0]; +		for (i = 1; i < (AO_USB_IN_SIZE>>1); i++) { +			uint16_t v = buf[i]; +			if (v < min) min = v; +			if (v > max) max = v; +		} +		/* Wait for at least 10 bits of range */ +		if ((uint16_t) (max - min) >= 1024)  			break;  		ao_delay(AO_MS_TO_TICKS(10));  	} diff --git a/src/kernel/ao_pyro.c b/src/kernel/ao_pyro.c index a0881f9e..9543b3ef 100644 --- a/src/kernel/ao_pyro.c +++ b/src/kernel/ao_pyro.c @@ -181,7 +181,7 @@ ao_pyro_ready(struct ao_pyro *pyro)  		case ao_pyro_state_greater_or_equal:  			if (ao_flight_state >= pyro->state_greater_or_equal)  				continue; -			DBG("state %d >= %d\n", ao_flight_state, pyro->state_less); +			DBG("state %d < %d\n", ao_flight_state, pyro->state_greater_or_equal);  			break;  		default: diff --git a/src/telegps-v2.0/ao_pins.h b/src/telegps-v2.0/ao_pins.h index f92564d6..fa175371 100644 --- a/src/telegps-v2.0/ao_pins.h +++ b/src/telegps-v2.0/ao_pins.h @@ -33,11 +33,11 @@  #define IS_FLASH_LOADER		0  #define HAS_BEEP 	       0 -#define AO_HSE                  32000000 +#define AO_HSE                  16000000  #define AO_RCC_CFGR_PLLMUL      STM_RCC_CFGR_PLLMUL_3 -#define AO_RCC_CFGR2_PLLDIV	STM_RCC_CFGR2_PREDIV_2 +#define AO_RCC_CFGR2_PLLDIV	STM_RCC_CFGR2_PREDIV_1  #define AO_PLLMUL               3 -#define AO_PLLDIV               2 +#define AO_PLLDIV               1  /* HCLK = 48MHz */  #define AO_AHB_PRESCALER        1 @@ -50,6 +50,9 @@  #define HAS_USB                         1  #define AO_USB_DIRECTIO                 0  #define AO_PA11_PA12_RMP                1 +#define HAS_USB_CONNECT			1 +#define AO_USB_CONNECT_PORT		(&stm_gpiob) +#define AO_USB_CONNECT_PIN		3  #define IS_FLASH_LOADER 0 @@ -110,6 +113,8 @@ struct ao_adc {  #define HAS_SERIAL_2	       	1  #define SERIAL_2_PA2_PA3	1  #define USE_SERIAL_2_STDIN	0 +#define USE_SERIAL_2_FLOW       0 +#define USE_SERIAL_2_SW_FLOW    0  #define ao_gps_getchar		ao_serial2_getchar  #define ao_gps_putchar		ao_serial2_putchar diff --git a/src/test/Makefile b/src/test/Makefile index a0c2d5fe..08808430 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -6,7 +6,10 @@ PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noi  	ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test ao_int64_test \  	ao_ms5607_convert_test ao_quaternion_test ao_lisp_test -INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h +INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h ao_eeprom_read.h +TEST_SRC=ao_flight_test.c +TEST_SRC_ALL=ao_flight_test.c ao_eeprom_read.c ao_eeprom_read_old.c +TEST_LIB=-ljson-c  KALMAN=make-kalman  @@ -19,26 +22,26 @@ clean:  install: -ao_flight_test: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h $(INCS) -	cc $(CFLAGS) -o $@ $< +ao_flight_test: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c altitude.h $(INCS) +	cc $(CFLAGS) -o $@ $(TEST_SRC) $(TEST_LIB) -ao_flight_test_noisy_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) -	cc -DNOISY_ACCEL=1 $(CFLAGS) -o $@ $< +ao_flight_test_noisy_accel: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS) +	cc -DNOISY_ACCEL=1 $(CFLAGS) -o $@ $(TEST_SRC) $(TEST_LIB) -ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kalman.c $(INCS) -	cc $(CFLAGS) -o $@ -DHAS_ACCEL=0 ao_flight_test.c +ao_flight_test_baro: $(TEST_SRC_ALL) ao_host.h ao_flight.c  ao_sample.c ao_kalman.c $(INCS) +	cc $(CFLAGS) -o $@ -DHAS_ACCEL=0 $(TEST_SRC) $(TEST_LIB) -ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kalman.c $(INCS) -	cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c +ao_flight_test_accel: $(TEST_SRC_ALL) ao_host.h ao_flight.c  ao_sample.c ao_kalman.c $(INCS) +	cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 $(TEST_SRC) $(TEST_LIB) -ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) -	cc -DTELEMEGA=1 $(CFLAGS) -o $@ $< -lm +ao_flight_test_mm: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) +	cc -DTELEMEGA=1 $(CFLAGS) -o $@ $(TEST_SRC)  $(TEST_LIB) -lm -ao_flight_test_metrum: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) -	cc -DTELEMETRUM_V2=1 $(CFLAGS) -o $@ $< -lm +ao_flight_test_metrum: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) +	cc -DTELEMETRUM_V2=1 $(CFLAGS) -o $@ $(TEST_SRC)  $(TEST_LIB) -lm -ao_flight_test_mini: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) -	cc -DEASYMINI=1 -DHAS_ACCEL=0 $(CFLAGS) -o $@ $< -lm +ao_flight_test_mini: $(TEST_SRC_ALL) ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS) +	cc -DEASYMINI=1 -DHAS_ACCEL=0 $(CFLAGS) -o $@ $(TEST_SRC)  $(TEST_LIB) -lm  ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h  	cc $(CFLAGS) -o $@ $< diff --git a/src/test/ao_eeprom_read.c b/src/test/ao_eeprom_read.c new file mode 100644 index 00000000..803ef36c --- /dev/null +++ b/src/test/ao_eeprom_read.c @@ -0,0 +1,262 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_eeprom_read.h" +#include <json-c/json.h> +#include <string.h> +#include <errno.h> + +static struct json_object * +ao_eeprom_read_config(FILE *file) +{ +	char			line[1024]; +	struct json_tokener	*tok; +	struct json_object	*obj = NULL; +	enum json_tokener_error	err; + +	tok = json_tokener_new(); +	if (!tok) +		goto fail_tok; + +	for (;;) { +		if (fgets(line, sizeof(line), file) == NULL) +			goto fail_read; +		obj = json_tokener_parse_ex(tok, line, strlen(line)); +		err = json_tokener_get_error(tok); +		if (err == json_tokener_success) +			break; +		if (err != json_tokener_continue) +			goto fail_read; +	} +	json_tokener_free(tok); +	return obj; +fail_read: +	json_tokener_free(tok); +fail_tok: +	return NULL; +} + +static int +ao_eeprom_read_byte(FILE *file) +{ +	int	byte; +	if (fscanf(file, "%x", &byte) != 1) +		return EOF; +	return byte; +} + +static int +ao_eeprom_read_data(FILE *file, struct ao_eeprom *eeprom) +{ +	uint8_t	*data = NULL, *ndata; +	int	len = 0; +	int	size = 0; +	int	byte; + +	data = malloc(size = 64); +	if (!data) +		goto fail_alloc; +	while ((byte = ao_eeprom_read_byte(file)) != EOF) { +		if (len == size) { +			ndata = realloc(data, size *= 2); +			if (!ndata) +				goto fail_realloc; +			data = ndata; +		} +		data[len++] = (uint8_t) byte; +	} +	eeprom->data = data; +	eeprom->len = len; +	return 1; +fail_realloc: +	free(data); +fail_alloc: +	return 0; +} + +static int +ao_json_get_int(struct json_object *obj, const char *key, int def) +{ +	struct json_object *value; +	int i; + +	if (!json_object_object_get_ex(obj, key, &value)) +		return def; +	errno = 0; +	i = (int) json_object_get_int(value); +	if (errno != 0) +		return def; +	return i; +} + +static const char * +ao_json_get_string(struct json_object *obj, const char *key, const char *def) +{ +	struct json_object *value; +	const char *str; + +	if (!json_object_object_get_ex(obj, key, &value)) +		return def; +	errno = 0; +	str = json_object_get_string(value); +	if (errno) +		return def; +	if (!str) +		return def; +	return str; +} + +#if AO_PYRO_NUM +static int +ao_eeprom_get_pyro(struct ao_config *config, struct json_object *obj) +{ +	struct json_object	*pyros; +	struct json_object	*pyro; +	int			i, p; + +	if (!json_object_object_get_ex(obj, "pyros", &pyros)) +		return 1; + +	if (json_object_get_type(pyros) != json_type_array) +		return 0; + +	for (i = 0; i < json_object_array_length(pyros); i++) { +		pyro = json_object_array_get_idx(pyros, i); +		if (pyro) { +			p = ao_json_get_int(pyro, "channel", -1); +			if (0 <= p && p < AO_PYRO_NUM) { +				config->pyro[p].flags		= ao_json_get_int(pyro, "flags", 0); +				config->pyro[p].accel_less	= ao_json_get_int(pyro, "accel_less", 0); +				config->pyro[p].accel_greater	= ao_json_get_int(pyro, "accel_greater", 0); +				config->pyro[p].speed_less	= ao_json_get_int(pyro, "speed_less", 0); +				config->pyro[p].speed_greater	= ao_json_get_int(pyro, "speed_greater", 0); +				config->pyro[p].height_less	= ao_json_get_int(pyro, "height_less", 0); +				config->pyro[p].height_greater	= ao_json_get_int(pyro, "height_greater", 0); +				config->pyro[p].orient_less	= ao_json_get_int(pyro, "orient_less", 0); +				config->pyro[p].orient_greater	= ao_json_get_int(pyro, "orient_greater", 0); +				config->pyro[p].time_less	= ao_json_get_int(pyro, "time_less", 0); +				config->pyro[p].time_greater	= ao_json_get_int(pyro, "time_greater", 0); +				config->pyro[p].delay		= ao_json_get_int(pyro, "delay", 0); +				config->pyro[p].state_less	= ao_json_get_int(pyro, "state_less", 0); +				config->pyro[p].state_greater_or_equal	= ao_json_get_int(pyro, "state_greater_or_equal", 0); +				config->pyro[p].motor		= ao_json_get_int(pyro, "motor", 0); +			} +		} +	} +	return 1; +} +#endif + +static int +ao_eeprom_get_ms5607(struct ao_ms5607_prom *ms5607_prom, struct json_object *obj) +{ +	struct json_object	*ms5607; + +	if (!json_object_object_get_ex(obj, "ms5607", &ms5607)) +		return 1; + +	if (json_object_get_type(ms5607) != json_type_object) +		return 0; + +	ms5607_prom->reserved =	ao_json_get_int(ms5607, "reserved", 0); +	ms5607_prom->sens =	ao_json_get_int(ms5607, "sens", 0); +	ms5607_prom->off =	ao_json_get_int(ms5607, "off", 0); +	ms5607_prom->tcs =	ao_json_get_int(ms5607, "tcs", 0); +	ms5607_prom->tco =	ao_json_get_int(ms5607, "tco", 0); +	ms5607_prom->tref =	ao_json_get_int(ms5607, "tref", 0); +	ms5607_prom->tempsens =	ao_json_get_int(ms5607, "tempsens", 0); +	ms5607_prom->crc =	ao_json_get_int(ms5607, "crc", 0); +	return 1; +} + +static int +ao_eeprom_get_config(struct ao_eeprom *ao_eeprom, struct json_object *obj) +{ +	struct ao_config	*config = &ao_eeprom->config; +	const char		*s; + +	if (json_object_get_type(obj) != json_type_object) +		return 0; + +	ao_eeprom->log_format = 	ao_json_get_int(obj, "log_format", 0); +	ao_eeprom->serial_number =	ao_json_get_int(obj, "serial", 0); + +	config->major =			ao_json_get_int(obj, "config_major", 0); +	config->minor = 		ao_json_get_int(obj, "config_minor", 0); +	if (config->major == 0 || config->minor == 0) +		return 0; + +	config->main_deploy = 		ao_json_get_int(obj, "main_deploy", 250); +	config->accel_plus_g = 		ao_json_get_int(obj, "accel_cal_plus", 0); + +	s = ao_json_get_string(obj, "callsign", "N0CALL"); +	strncpy(config->callsign, s, sizeof(config->callsign)); + +	config->apogee_delay =		ao_json_get_int(obj, "apogee_delay", 0); +	config->accel_minus_g =		ao_json_get_int(obj, "accel_cal_minus", 0); +	config->radio_cal =		ao_json_get_int(obj, "radio_calibration", 0); +	config->flight_log_max =	ao_json_get_int(obj, "flight_log_max", 0); +	config->ignite_mode = 		ao_json_get_int(obj, "ignite_mode", 0); +	config->pad_orientation = 	ao_json_get_int(obj, "pad_orientation", 0); +	config->radio_setting = 	ao_json_get_int(obj, "radio_setting", 0); +	config->radio_enable = 		ao_json_get_int(obj, "radio_enable", 1); +	config->frequency = 		ao_json_get_int(obj, "frequency", 434550); +	config->apogee_lockout = 	ao_json_get_int(obj, "apogee_lockout", 0); +#if AO_PYRO_NUM +	if (!ao_eeprom_get_pyro(config, obj)) +		return 0; +#endif +	config->ignite_mode = 		ao_json_get_int(obj, "ignite_mode", 0); +	config->ignite_mode = 		ao_json_get_int(obj, "ignite_mode", 0); +	config->ignite_mode = 		ao_json_get_int(obj, "ignite_mode", 0); +	config->ignite_mode = 		ao_json_get_int(obj, "ignite_mode", 0); +	config->ignite_mode = 		ao_json_get_int(obj, "ignite_mode", 0); +	config->ignite_mode = 		ao_json_get_int(obj, "ignite_mode", 0); + +	if (!ao_eeprom_get_ms5607(&ao_eeprom->ms5607_prom, obj)) +		return 0; + +	return 1; +} + +struct ao_eeprom * +ao_eeprom_read(FILE *file) +{ +	struct ao_eeprom	*ao_eeprom; +	struct json_object	*obj; +	int			ret; + +	ao_eeprom = calloc(1, sizeof (struct ao_eeprom)); +	if (!ao_eeprom) +		goto fail_ao_eeprom; + +	obj = ao_eeprom_read_config(file); +	if (!obj) +		goto fail_config; + +	ret = ao_eeprom_get_config(ao_eeprom, obj); +	json_object_put(obj); +	if (!ret) +		goto fail_config; + +	if (!ao_eeprom_read_data(file, ao_eeprom)) +		goto fail_data; + +	return ao_eeprom; +fail_data: +fail_config: +	free(ao_eeprom); +fail_ao_eeprom: +	return NULL; +} diff --git a/src/test/ao_eeprom_read.h b/src/test/ao_eeprom_read.h new file mode 100644 index 00000000..03c327ca --- /dev/null +++ b/src/test/ao_eeprom_read.h @@ -0,0 +1,47 @@ +/* + * Copyright © 2017 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. + */ + +#ifndef _AO_EEPROM_READ_H_ +#define _AO_EEPROM_READ_H_ + +#define __pdata +#define __data +#define __xdata +#define __code +#define __reentrant + +#include <stdint.h> +#include <stdio.h> +#include <ao_telemetry.h> +#include <ao_config.h> +#include <ao_ms5607.h> +#include <ao_log.h> + +struct ao_eeprom { +	struct ao_config	config; +	struct ao_ms5607_prom	ms5607_prom; +	int			log_format; +	uint16_t		serial_number; +	uint8_t			*data; +	uint32_t		len; +	uint32_t		size; +}; + +struct ao_eeprom *ao_eeprom_read(FILE *file); + +struct ao_eeprom *ao_eeprom_read_old(FILE *file); + +void ao_eeprom_free_data(struct ao_eeprom *ao_eeprom); + +#endif /* _AO_EEPROM_READ_H_ */ diff --git a/src/test/ao_eeprom_read_old.c b/src/test/ao_eeprom_read_old.c new file mode 100644 index 00000000..c66ffae5 --- /dev/null +++ b/src/test/ao_eeprom_read_old.c @@ -0,0 +1,172 @@ +/* + * Copyright © 2017 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 "ao_eeprom_read.h" +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +static int +ao_eeprom_add_u8(struct ao_eeprom *ao_eeprom, uint8_t byte) +{ +	if (ao_eeprom->len == ao_eeprom->size) { +		uint32_t	nsize = ao_eeprom->size * 2; +		uint8_t		*ndata = realloc(ao_eeprom->data, nsize); +		if (!ndata) +			return 0; +		ao_eeprom->data = ndata; +		ao_eeprom->size = nsize; +	} +	ao_eeprom->data[ao_eeprom->len++] = byte; +	return 1; +} + +static int +ao_eeprom_add_u16(struct ao_eeprom *ao_eeprom, uint16_t u16) +{ +	if (!ao_eeprom_add_u8(ao_eeprom, u16 & 0xff)) +		return 0; + +	return ao_eeprom_add_u8(ao_eeprom, u16 >> 8); +} + +struct ao_eeprom * +ao_eeprom_read_old(FILE *file) +{ +	struct ao_eeprom	*ao_eeprom; +	char			line[1024]; +	char			*l; + +	ao_eeprom = calloc(1, sizeof (struct ao_eeprom)); +	if (!ao_eeprom) +		return NULL; + +	ao_eeprom->log_format = -1; +	ao_eeprom->size = 64; +	ao_eeprom->data = malloc(ao_eeprom->size); +	if (!ao_eeprom->data) { +		free(ao_eeprom); +		return NULL; +	} +	while (fgets(line, sizeof(line), file) != NULL) { +		int nword; +		char *words[64]; +		char *saveptr; +		l = line; +		for (nword = 0; nword < 64; nword++) { +			words[nword] = strtok_r(l, " \t\n", &saveptr); +			l = NULL; +			if (words[nword] == NULL) +				break; +		} +		if (((ao_eeprom->log_format == AO_LOG_FORMAT_TELEMEGA_OLD || ao_eeprom->log_format == AO_LOG_FORMAT_TELEMEGA) && nword == 30 && strlen(words[0]) == 1) || +		    ((ao_eeprom->log_format == AO_LOG_FORMAT_EASYMINI1 || ao_eeprom->log_format == AO_LOG_FORMAT_EASYMINI2) && nword == 14 && strlen(words[0]) == 1) || +		    (ao_eeprom->log_format == AO_LOG_FORMAT_TELEMETRUM && nword == 14 && strlen(words[0]) == 1)) +		{ +			int		i; +			uint8_t		type; +			uint16_t	tick; + +			type = words[0][0]; +			tick = strtoul(words[1], NULL, 16); +			ao_eeprom_add_u8(ao_eeprom, type); +			ao_eeprom_add_u8(ao_eeprom, 0);	/* checksum */ +			ao_eeprom_add_u16(ao_eeprom, tick); +			for (i = 2; i < nword; i++) +				ao_eeprom_add_u8(ao_eeprom, strtoul(words[i], NULL, 16)); +		} +		else if (nword == 4 && strlen(words[0]) == 1) { +			uint8_t		type; +			uint16_t	tick, a, b; +			type = words[0][0]; +			tick = strtoul(words[1], NULL, 16); +			a = strtoul(words[2], NULL, 16); +			b = strtoul(words[3], NULL, 16); +			if (type == 'P') +				type = 'A'; +			ao_eeprom_add_u8(ao_eeprom, type); +			ao_eeprom_add_u8(ao_eeprom, 0);	/* checksum */ +			ao_eeprom_add_u16(ao_eeprom, tick); +			ao_eeprom_add_u16(ao_eeprom, a); +			ao_eeprom_add_u16(ao_eeprom, b); +		} +		else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { +			if (strcmp(words[1], "reserved:") == 0) +				ao_eeprom->ms5607_prom.reserved = strtoul(words[2], NULL, 10); +			else if (strcmp(words[1], "sens:") == 0) +				ao_eeprom->ms5607_prom.sens = strtoul(words[2], NULL, 10); +			else if (strcmp(words[1], "off:") == 0) +				ao_eeprom->ms5607_prom.off = strtoul(words[2], NULL, 10); +			else if (strcmp(words[1], "tcs:") == 0) +				ao_eeprom->ms5607_prom.tcs = strtoul(words[2], NULL, 10); +			else if (strcmp(words[1], "tco:") == 0) +				ao_eeprom->ms5607_prom.tco = strtoul(words[2], NULL, 10); +			else if (strcmp(words[1], "tref:") == 0) +				ao_eeprom->ms5607_prom.tref = strtoul(words[2], NULL, 10); +			else if (strcmp(words[1], "tempsens:") == 0) +				ao_eeprom->ms5607_prom.tempsens = strtoul(words[2], NULL, 10); +			else if (strcmp(words[1], "crc:") == 0) +				ao_eeprom->ms5607_prom.crc = strtoul(words[2], NULL, 10); +			continue; +		} +#if AO_NUM_PYRO +		else if (nword >= 3 && strcmp(words[0], "Pyro") == 0) { +			int	p = strtoul(words[1], NULL, 10); +			int	i, j; +			struct ao_pyro	*pyro = &ao_eeprom->config.pyro[p]; + +			for (i = 2; i < nword; i++) { +				for (j = 0; j < NUM_PYRO_VALUES; j++) +					if (!strcmp (words[i], ao_pyro_values[j].name)) +						break; +				if (j == NUM_PYRO_VALUES) +					continue; +				pyro->flags |= ao_pyro_values[j].flag; +				if (ao_pyro_values[j].offset != NO_VALUE && i + 1 < nword) { +					int16_t	val = strtoul(words[++i], NULL, 10); +					printf("pyro %d condition %s value %d\n", p, words[i-1], val); +					*((int16_t *) ((char *) pyro + ao_pyro_values[j].offset)) = val; +				} +			} +		} +#endif +		else if (nword == 2 && strcmp(words[0], "log-format") == 0) { +			ao_eeprom->log_format = strtoul(words[1], NULL, 10); +		} else if (nword == 2 && strcmp(words[0], "serial-number") == 0) { +			ao_eeprom->serial_number = strtoul(words[1], NULL, 10); +		} else if (nword >= 6 && strcmp(words[0], "Accel") == 0) { +			ao_eeprom->config.accel_plus_g = atoi(words[3]); +			ao_eeprom->config.accel_minus_g = atoi(words[5]); +#if HAS_GYRO +		} else if (nword >= 8 && strcmp(words[0], "IMU") == 0) { +			ao_eeprom->config.accel_zero_along = atoi(words[3]); +			ao_eeprom->config.accel_zero_across = atoi(words[5]); +			ao_eeprom->config.accel_zero_through = atoi(words[7]); +#endif +		} else if (nword >= 4 && strcmp(words[0], "Main") == 0) { +			ao_eeprom->config.main_deploy = atoi(words[2]); +		} else if (nword >= 3 && strcmp(words[0], "Apogee") == 0 && +			   strcmp(words[1], "lockout:") == 0) { +			ao_eeprom->config.apogee_lockout = atoi(words[2]); +		} else if (nword >= 3 && strcmp(words[0], "Pad") == 0 && +			   strcmp(words[1], "orientation:") == 0) { +			ao_eeprom->config.pad_orientation = atoi(words[2]); +		} +	} +	return ao_eeprom; +} + diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 55bfe410..298848d6 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -191,7 +191,7 @@ ao_distance_from_pad(void)  	double	dist, bearing;  	if (!ao_gps_count)  		return 0; -	 +  	cc_great_circle(ao_gps_first.latitude / 1e7,  			ao_gps_first.longitude / 1e7,  			ao_gps_static.latitude / 1e7, @@ -308,6 +308,9 @@ struct ao_task {  int	ao_flight_debug; +struct ao_eeprom	*eeprom; +uint32_t		eeprom_offset; +  FILE *emulator_in;  char *emulator_app;  char *emulator_name; @@ -341,14 +344,18 @@ struct ao_cmds {  #include <ao_ms5607.h>  struct ao_ms5607_prom	ao_ms5607_prom;  #include "ao_ms5607_convert.c" +#if TELEMEGA  #define AO_PYRO_NUM	4  #include <ao_pyro.h> +#endif  #else  #include "ao_convert.c"  #endif  #include <ao_config.h>  #include <ao_fake_flight.h> +#include <ao_eeprom_read.h> +#include <ao_log.h>  #define ao_config_get() @@ -401,12 +408,16 @@ ao_pyro_pin_set(uint8_t pin, uint8_t value)  #include "ao_pyro.c"  #endif +#include "ao_eeprom_read.c" +#include "ao_eeprom_read_old.c"  #define to_double(f)	((f) / 65536.0)  static int	ao_records_read = 0;  static int	ao_eof_read = 0; +#if !EASYMINI  static int	ao_flight_ground_accel; +#endif  static int	ao_flight_started = 0;  static int	ao_test_max_height;  static double	ao_test_max_height_time; @@ -418,11 +429,18 @@ static double	ao_test_landed_time;  static int	landed_set;  static double	landed_time;  static double	landed_height; +#if AO_PYRO_NUM +static uint16_t	pyros_fired; +#endif  #if HAS_MPU6000  static struct ao_mpu6000_sample	ao_ground_mpu6000;  #endif +#if HAS_ACCEL +int ao_error_h_sq_avg; +#endif +  void  ao_test_exit(void)  { @@ -567,7 +585,7 @@ ao_insert(void)  			ao_quaternion_normalize(&ao_mag, &ao_mag);  			ao_quaternion_rotate(&ao_mag_rot, &ao_mag, &ao_rotation); -			 +  			float				ao_dot;  			int				ao_mag_angle; @@ -722,17 +740,6 @@ void  ao_sleep(void *wchan)  {  	if (wchan == &ao_data_head) { -		char		type = 0; -		uint16_t	tick = 0; -		uint16_t	a = 0, b = 0; -		uint8_t		bytes[1024]; -		union ao_telemetry_all	telem; -		char		line[1024]; -		char		*saveptr; -		char		*l; -		char		*words[64]; -		int		nword; -  #if TELEMEGA  		if (ao_flight_state >= ao_flight_boost && ao_flight_state < ao_flight_landed)  			ao_pyro_check(); @@ -752,419 +759,183 @@ ao_sleep(void *wchan)  				return;  			} -			if (!fgets(line, sizeof (line), emulator_in)) { -				if (++ao_eof_read >= 1000) { -					if (!ao_summary) -						printf ("no more data, exiting simulation\n"); -					ao_test_exit(); -				} -				ao_data_static.tick += 10; -				ao_insert(); -				return; -			} -			l = line; -			for (nword = 0; nword < 64; nword++) { -				words[nword] = strtok_r(l, " \t\n", &saveptr); -				l = NULL; -				if (words[nword] == NULL) -					break; -			} +			if (eeprom) {  #if TELEMEGA -			if ((log_format == AO_LOG_FORMAT_TELEMEGA_OLD || log_format == AO_LOG_FORMAT_TELEMEGA) && nword == 30 && strlen(words[0]) == 1) { -				int	i; -				struct ao_ms5607_value	value; - -				type = words[0][0]; -				tick = strtoul(words[1], NULL, 16); -//				printf ("%c %04x", type, tick); -				for (i = 2; i < nword; i++) { -					bytes[i - 2] = strtoul(words[i], NULL, 16); -//					printf(" %02x", bytes[i-2]); -				} -//				printf ("\n"); -				switch (type) { -				case 'F': -					ao_flight_number = uint16(bytes, 0); -					ao_flight_ground_accel = int16(bytes, 2); -					ao_flight_started = 1; -					ao_ground_pres = int32(bytes, 4); -					ao_ground_height = ao_pa_to_altitude(ao_ground_pres); -					ao_ground_accel_along = int16(bytes, 8); -					ao_ground_accel_across = int16(bytes, 10); -					ao_ground_accel_through = int16(bytes, 12); -					ao_ground_roll = int16(bytes, 14); -					ao_ground_pitch = int16(bytes, 16); -					ao_ground_yaw = int16(bytes, 18); -					ao_ground_mpu6000.accel_x = ao_ground_accel_across; -					ao_ground_mpu6000.accel_y = ao_ground_accel_along; -					ao_ground_mpu6000.accel_z = ao_ground_accel_through; -					ao_ground_mpu6000.gyro_x = ao_ground_pitch >> 9; -					ao_ground_mpu6000.gyro_y = ao_ground_roll >> 9; -					ao_ground_mpu6000.gyro_z = ao_ground_yaw >> 9; -					break; -				case 'A': -					ao_data_static.tick = tick; -					ao_data_static.ms5607_raw.pres = int32(bytes, 0); -					ao_data_static.ms5607_raw.temp = int32(bytes, 4); -					ao_ms5607_convert(&ao_data_static.ms5607_raw, &value); -					ao_data_static.mpu6000.accel_x = int16(bytes, 8); -					ao_data_static.mpu6000.accel_y = int16(bytes, 10); -					ao_data_static.mpu6000.accel_z = int16(bytes, 12); -					ao_data_static.mpu6000.gyro_x = int16(bytes, 14); -					ao_data_static.mpu6000.gyro_y = int16(bytes, 16); -					ao_data_static.mpu6000.gyro_z = int16(bytes, 18); -					ao_data_static.hmc5883.x = int16(bytes, 20); -					ao_data_static.hmc5883.y = int16(bytes, 22); -					ao_data_static.hmc5883.z = int16(bytes, 24); -#if HAS_MMA655X -					ao_data_static.mma655x = int16(bytes, 26); -					if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) -						ao_data_static.mma655x = ao_data_accel_invert(ao_data_static.mma655x); +				struct ao_log_mega	*log_mega;  #endif -					ao_records_read++; -					ao_insert(); -					return; -				case 'G': -					ao_gps_prev = ao_gps_static; -					ao_gps_static.tick = tick; -					ao_gps_static.latitude = int32(bytes, 0); -					ao_gps_static.longitude = int32(bytes, 4); -					{ -						int32_t	altitude = int32(bytes, 8); -						AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_static, altitude); -					} -					ao_gps_static.flags = bytes[13]; -					if (!ao_gps_count) -						ao_gps_first = ao_gps_static; -					ao_gps_count++; -					break; -				} -				continue; -			} else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { -				if (strcmp(words[1], "reserved:") == 0) -					ao_ms5607_prom.reserved = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "sens:") == 0) -					ao_ms5607_prom.sens = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "off:") == 0) -					ao_ms5607_prom.off = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tcs:") == 0) -					ao_ms5607_prom.tcs = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tco:") == 0) -					ao_ms5607_prom.tco = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tref:") == 0) -					ao_ms5607_prom.tref = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tempsens:") == 0) -					ao_ms5607_prom.tempsens = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "crc:") == 0) -					ao_ms5607_prom.crc = strtoul(words[2], NULL, 10); -				continue; -			} else if (nword >= 3 && strcmp(words[0], "Pyro") == 0) { -				int	p = strtoul(words[1], NULL, 10); -				int	i, j; -				struct ao_pyro	*pyro = &ao_config.pyro[p]; - -				for (i = 2; i < nword; i++) { -					for (j = 0; j < NUM_PYRO_VALUES; j++) -						if (!strcmp (words[i], ao_pyro_values[j].name)) -							break; -					if (j == NUM_PYRO_VALUES) -						continue; -					pyro->flags |= ao_pyro_values[j].flag; -					if (ao_pyro_values[j].offset != NO_VALUE && i + 1 < nword) { -						int16_t	val = strtoul(words[++i], NULL, 10); -						printf("pyro %d condition %s value %d\n", p, words[i-1], val); -						*((int16_t *) ((char *) pyro + ao_pyro_values[j].offset)) = val; -					} -				} -			} +#if TELEMETRUM_V2 +				struct ao_log_metrum	*log_metrum;  #endif  #if EASYMINI -			if ((log_format == AO_LOG_FORMAT_EASYMINI1 || log_format == AO_LOG_FORMAT_EASYMINI2) && nword == 14 && strlen(words[0]) == 1) { -				int	i; -				struct ao_ms5607_value	value; - -				type = words[0][0]; -				tick = strtoul(words[1], NULL, 16); -//				printf ("%c %04x", type, tick); -				for (i = 2; i < nword; i++) { -					bytes[i - 2] = strtoul(words[i], NULL, 16); -//					printf(" %02x", bytes[i-2]); -				} -//				printf ("\n"); -				switch (type) { -				case 'F': -					ao_flight_started = 1; -					ao_flight_number = uint16(bytes, 0); -					ao_ground_pres = uint32(bytes, 4); -					ao_ground_height = ao_pa_to_altitude(ao_ground_pres); -#if 0 -					printf("ground pres %d height %d\n", ao_ground_pres, ao_ground_height); -					printf("sens %d off %d tcs %d tco %d tref %d tempsens %d crc %d\n", -					       ao_ms5607_prom.sens, -					       ao_ms5607_prom.off, -					       ao_ms5607_prom.tcs, -					       ao_ms5607_prom.tco, -					       ao_ms5607_prom.tref, -					       ao_ms5607_prom.tempsens, -					       ao_ms5607_prom.crc); +				struct ao_log_mini	*log_mini;  #endif -					break; -				case 'A': -					ao_data_static.tick = tick; -					ao_data_static.ms5607_raw.pres = int24(bytes, 0); -					ao_data_static.ms5607_raw.temp = int24(bytes, 3); -#if 0 -					printf("raw pres %d temp %d\n", -					       ao_data_static.ms5607_raw.pres, -					       ao_data_static.ms5607_raw.temp); +#if TELEMETRUM_V1 +				struct ao_log_record	*log_record;  #endif -					ao_ms5607_convert(&ao_data_static.ms5607_raw, &value); -//					printf("pres %d height %d\n", value.pres, ao_pa_to_altitude(value.pres)); -					ao_records_read++; + +				if (eeprom_offset >= eeprom->len) { +					if (++ao_eof_read >= 1000) +						if (!ao_summary) +							printf ("no more data, exiting simulation\n"); +					ao_test_exit(); +					ao_data_static.tick += 10;  					ao_insert();  					return;  				} -				continue; -			} else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { -				if (strcmp(words[1], "reserved:") == 0) -					ao_ms5607_prom.reserved = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "sens:") == 0) -					ao_ms5607_prom.sens = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "off:") == 0) -					ao_ms5607_prom.off = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tcs:") == 0) -					ao_ms5607_prom.tcs = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tco:") == 0) -					ao_ms5607_prom.tco = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tref:") == 0) -					ao_ms5607_prom.tref = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tempsens:") == 0) -					ao_ms5607_prom.tempsens = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "crc:") == 0) -					ao_ms5607_prom.crc = strtoul(words[2], NULL, 10); -				continue; -			} +				switch (eeprom->log_format) { +#if TELEMEGA +				case AO_LOG_FORMAT_TELEMEGA_OLD: +				case AO_LOG_FORMAT_TELEMEGA: +					log_mega = (struct ao_log_mega *) &eeprom->data[eeprom_offset]; +					eeprom_offset += sizeof (*log_mega); +					switch (log_mega->type) { +					case AO_LOG_FLIGHT: +						ao_flight_number = log_mega->u.flight.flight; +						ao_flight_ground_accel = log_mega->u.flight.ground_accel; +						ao_flight_started = 1; +						ao_ground_pres = log_mega->u.flight.ground_pres; +						ao_ground_height = ao_pa_to_altitude(ao_ground_pres); +						ao_ground_accel_along = log_mega->u.flight.ground_accel_along; +						ao_ground_accel_across = log_mega->u.flight.ground_accel_across; +						ao_ground_accel_through = log_mega->u.flight.ground_accel_through; +						ao_ground_roll = log_mega->u.flight.ground_roll; +						ao_ground_pitch = log_mega->u.flight.ground_pitch; +						ao_ground_yaw = log_mega->u.flight.ground_yaw; +						ao_ground_mpu6000.accel_x = ao_ground_accel_across; +						ao_ground_mpu6000.accel_y = ao_ground_accel_along; +						ao_ground_mpu6000.accel_z = ao_ground_accel_through; +						ao_ground_mpu6000.gyro_x = ao_ground_pitch >> 9; +						ao_ground_mpu6000.gyro_y = ao_ground_roll >> 9; +						ao_ground_mpu6000.gyro_z = ao_ground_yaw >> 9; +						break; +					case AO_LOG_STATE: +						break; +					case AO_LOG_SENSOR: +						ao_data_static.tick = log_mega->tick; +						ao_data_static.ms5607_raw.pres = log_mega->u.sensor.pres; +						ao_data_static.ms5607_raw.temp = log_mega->u.sensor.temp; +						ao_data_static.mpu6000.accel_x = log_mega->u.sensor.accel_x; +						ao_data_static.mpu6000.accel_y = log_mega->u.sensor.accel_y; +						ao_data_static.mpu6000.accel_z = log_mega->u.sensor.accel_z; +						ao_data_static.mpu6000.gyro_x = log_mega->u.sensor.gyro_x; +						ao_data_static.mpu6000.gyro_y = log_mega->u.sensor.gyro_y; +						ao_data_static.mpu6000.gyro_z = log_mega->u.sensor.gyro_z; +						ao_data_static.hmc5883.x = log_mega->u.sensor.mag_x; +						ao_data_static.hmc5883.y = log_mega->u.sensor.mag_y; +						ao_data_static.hmc5883.z = log_mega->u.sensor.mag_z; +						ao_data_static.mma655x = log_mega->u.sensor.accel; +						if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) +							ao_data_static.mma655x = ao_data_accel_invert(ao_data_static.mma655x); +						ao_records_read++; +						ao_insert(); +						return; +					case AO_LOG_TEMP_VOLT: +						if (pyros_fired != log_mega->u.volt.pyro) { +							printf("pyro changed %x -> %x\n", pyros_fired, log_mega->u.volt.pyro); +							pyros_fired = log_mega->u.volt.pyro; +						} +						break; +					case AO_LOG_GPS_TIME: +						ao_gps_prev = ao_gps_static; +						ao_gps_static.tick = log_mega->tick; +						ao_gps_static.latitude = log_mega->u.gps.latitude; +						ao_gps_static.longitude = log_mega->u.gps.longitude; +						{ +							int16_t	altitude_low = log_mega->u.gps.altitude_low; +							int16_t altitude_high = log_mega->u.gps.altitude_high; +							int32_t altitude = altitude_low | ((int32_t) altitude_high << 16); + +							AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_static, altitude); +						} +						ao_gps_static.flags = log_mega->u.gps.flags; +						if (!ao_gps_count) +							ao_gps_first = ao_gps_static; +						ao_gps_count++; +						break; +					case AO_LOG_GPS_SAT: +						break; +					} +					break;  #endif  #if TELEMETRUM_V2 -			if (log_format == AO_LOG_FORMAT_TELEMETRUM && nword == 14 && strlen(words[0]) == 1) { -				int	i; -				struct ao_ms5607_value	value; - -				type = words[0][0]; -				tick = strtoul(words[1], NULL, 16); -//				printf ("%c %04x", type, tick); -				for (i = 2; i < nword; i++) { -					bytes[i - 2] = strtoul(words[i], NULL, 16); -//					printf(" %02x", bytes[i-2]); -				} -//				printf ("\n"); -				switch (type) { -				case 'F': -					ao_flight_number = uint16(bytes, 0); -					ao_flight_ground_accel = int16(bytes, 2); -					ao_flight_started = 1; -					ao_ground_pres = int32(bytes, 4); -					ao_ground_height = ao_pa_to_altitude(ao_ground_pres); +				case AO_LOG_FORMAT_TELEMETRUM: +					log_metrum = (struct ao_log_metrum *) &eeprom->data[eeprom_offset]; +					eeprom_offset += sizeof (*log_metrum); +					switch (log_metrum->type) { +					case AO_LOG_FLIGHT: +						ao_flight_started = 1; +						ao_flight_number = log_metrum->u.flight.flight; +						ao_flight_ground_accel = log_metrum->u.flight.ground_accel; +						ao_ground_pres = log_metrum->u.flight.ground_pres; +						ao_ground_height = ao_pa_to_altitude(ao_ground_pres); +						break; +					case AO_LOG_SENSOR: +						ao_data_static.tick = log_metrum->tick; +						ao_data_static.ms5607_raw.pres = log_metrum->u.sensor.pres; +						ao_data_static.ms5607_raw.temp = log_metrum->u.sensor.temp; +						ao_data_static.mma655x = log_metrum->u.sensor.accel; +						ao_records_read++; +						ao_insert(); +						return; +					}  					break; -				case 'A': -					ao_data_static.tick = tick; -					ao_data_static.ms5607_raw.pres = int32(bytes, 0); -					ao_data_static.ms5607_raw.temp = int32(bytes, 4); -					ao_ms5607_convert(&ao_data_static.ms5607_raw, &value); -					ao_data_static.mma655x = int16(bytes, 8); -					ao_records_read++; -					ao_insert(); -					return; -				} -				continue; -			} else if (nword == 3 && strcmp(words[0], "ms5607") == 0) { -				if (strcmp(words[1], "reserved:") == 0) -					ao_ms5607_prom.reserved = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "sens:") == 0) -					ao_ms5607_prom.sens = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "off:") == 0) -					ao_ms5607_prom.off = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tcs:") == 0) -					ao_ms5607_prom.tcs = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tco:") == 0) -					ao_ms5607_prom.tco = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tref:") == 0) -					ao_ms5607_prom.tref = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "tempsens:") == 0) -					ao_ms5607_prom.tempsens = strtoul(words[2], NULL, 10); -				else if (strcmp(words[1], "crc:") == 0) -					ao_ms5607_prom.crc = strtoul(words[2], NULL, 10); -				continue; -			}  #endif -#if TELEMETRUM_V1 -			if (nword == 4 && log_format != AO_LOG_FORMAT_TELEMEGA) { -				type = words[0][0]; -				tick = strtoul(words[1], NULL, 16); -				a = strtoul(words[2], NULL, 16); -				b = strtoul(words[3], NULL, 16); -				if (type == 'P') -					type = 'A'; -			} -#endif -			else if (nword == 2 && strcmp(words[0], "log-format") == 0) { -				log_format = strtoul(words[1], NULL, 10); -			} else if (nword == 2 && strcmp(words[0], "serial-number") == 0) { -				ao_serial_number = strtoul(words[1], NULL, 10); -			} else if (nword >= 6 && strcmp(words[0], "Accel") == 0) { -				ao_config.accel_plus_g = atoi(words[3]); -				ao_config.accel_minus_g = atoi(words[5]); -#ifdef TELEMEGA -			} else if (nword >= 8 && strcmp(words[0], "IMU") == 0) { -				ao_config.accel_zero_along = atoi(words[3]); -				ao_config.accel_zero_across = atoi(words[5]); -				ao_config.accel_zero_through = atoi(words[7]); +#if EASYMINI +				case AO_LOG_FORMAT_EASYMINI1: +				case AO_LOG_FORMAT_EASYMINI2: +				case AO_LOG_FORMAT_TELEMINI3: +					log_mini = (struct ao_log_mini *) &eeprom->data[eeprom_offset]; +					eeprom_offset += sizeof (*log_mini); +					switch (log_mini->type) { +					case AO_LOG_FLIGHT: +						ao_flight_started = 1; +						ao_flight_number = log_mini->u.flight.flight; +						ao_ground_pres = log_mini->u.flight.ground_pres; +						ao_ground_height = ao_pa_to_altitude(ao_ground_pres); +						break; +					case AO_LOG_SENSOR: +						ao_data_static.tick = log_mini->tick; +						ao_data_static.ms5607_raw.pres = int24(log_mini->u.sensor.pres, 0); +						ao_data_static.ms5607_raw.temp = int24(log_mini->u.sensor.temp, 0); +						ao_records_read++; +						ao_insert(); +						return; +					} +					break;  #endif -			} else if (nword >= 4 && strcmp(words[0], "Main") == 0) { -				ao_config.main_deploy = atoi(words[2]); -			} else if (nword >= 3 && strcmp(words[0], "Apogee") == 0 && -				   strcmp(words[1], "lockout:") == 0) { -				ao_config.apogee_lockout = atoi(words[2]); -			} else if (nword >= 3 && strcmp(words[0], "Pad") == 0 && -				   strcmp(words[1], "orientation:") == 0) { -				ao_config.pad_orientation = atoi(words[2]); -			} else if (nword >= 36 && strcmp(words[0], "CALL") == 0) { -				tick = atoi(words[10]); -				if (!ao_flight_started) { -					type = 'F'; -					a = atoi(words[26]); -					ao_flight_started = 1; -				} else { -					type = 'A'; -					a = atoi(words[12]); -					b = atoi(words[14]); -				} -			} else if (nword == 3 && strcmp(words[0], "BARO") == 0) { -				tick = strtol(words[1], NULL, 16); -				a = 16384 - 328; -				b = strtol(words[2], NULL, 10); -				type = 'A'; -				if (!ao_flight_started) { -					ao_flight_ground_accel = 16384 - 328; -					ao_config.accel_plus_g = 16384 - 328; -					ao_config.accel_minus_g = 16384 + 328; -					ao_flight_started = 1; -				} -			} else if (nword == 2 && strcmp(words[0], "TELEM") == 0) { -				__xdata char	*hex = words[1]; -				char	elt[3]; -				int	i, len; -				uint8_t	sum; - -				len = strlen(hex); -				if (len > sizeof (bytes) * 2) { -					len = sizeof (bytes)*2; -					hex[len] = '\0'; -				} -				for (i = 0; i < len; i += 2) { -					elt[0] = hex[i]; -					elt[1] = hex[i+1]; -					elt[2] = '\0'; -					bytes[i/2] = (uint8_t) strtol(elt, NULL, 16); -				} -				len = i/2; -				if (bytes[0] != len - 2) { -					printf ("bad length %d != %d\n", bytes[0], len - 2); -					continue; -				} -				sum = 0x5a; -				for (i = 1; i < len-1; i++) -					sum += bytes[i]; -				if (sum != bytes[len-1]) { -					printf ("bad checksum\n"); -					continue; -				} -				if ((bytes[len-2] & 0x80) == 0) { -					continue; -				} -				if (len == 36) { -					ao_xmemcpy(&telem, bytes + 1, 32); -					tick = telem.generic.tick; -					switch (telem.generic.type) { -					case AO_TELEMETRY_SENSOR_TELEMETRUM: -					case AO_TELEMETRY_SENSOR_TELEMINI: -					case AO_TELEMETRY_SENSOR_TELENANO: -						if (!ao_flight_started) { -							ao_flight_ground_accel = telem.sensor.ground_accel; -							ao_config.accel_plus_g = telem.sensor.accel_plus_g; -							ao_config.accel_minus_g = telem.sensor.accel_minus_g; -							ao_flight_started = 1; -						} -						type = 'A'; -						a = telem.sensor.accel; -						b = telem.sensor.pres; +#if TELEMETRUM_V1 +				case AO_LOG_FORMAT_FULL: +				case AO_LOG_FORMAT_TINY: +					log_record = (struct ao_log_record *) &eeprom->data[eeprom_offset]; +					eeprom_offset += sizeof (*log_record); +					switch (log_record->type) { +					case AO_LOG_FLIGHT: +						ao_flight_started = 1; +						ao_flight_ground_accel = log_record->u.flight.ground_accel; +						ao_flight_number = log_record->u.flight.flight; +						break; +					case AO_LOG_SENSOR: +					case 'P':	/* ancient telemini */ +						ao_data_static.tick = log_record->tick; +						ao_data_static.adc.accel = log_record->u.sensor.accel; +						ao_data_static.adc.pres_real = log_record->u.sensor.pres; +						ao_data_static.adc.pres = log_record->u.sensor.pres; +						ao_records_read++; +						ao_insert(); +						return; +					case AO_LOG_TEMP_VOLT: +						ao_data_static.tick = log_record->tick;; +						ao_data_static.adc.temp = log_record->u.temp_volt.temp; +						ao_data_static.adc.v_batt = log_record->u.temp_volt.v_batt;  						break;  					} -				} else if (len == 99) { -					ao_flight_started = 1; -					tick = uint16(bytes+1, 21); -					ao_flight_ground_accel = int16(bytes+1, 7); -					ao_config.accel_plus_g = int16(bytes+1, 17); -					ao_config.accel_minus_g = int16(bytes+1, 19); -					type = 'A'; -					a = int16(bytes+1, 23); -					b = int16(bytes+1, 25); -				} else if (len == 98) { -					ao_flight_started = 1; -					tick = uint16(bytes+1, 20); -					ao_flight_ground_accel = int16(bytes+1, 6); -					ao_config.accel_plus_g = int16(bytes+1, 16); -					ao_config.accel_minus_g = int16(bytes+1, 18); -					type = 'A'; -					a = int16(bytes+1, 22); -					b = int16(bytes+1, 24); -				} else { -					printf("unknown len %d\n", len); -					continue; -				} -			} -			if (type != 'F' && !ao_flight_started) -				continue; - -#if TELEMEGA || TELEMETRUM_V2 || EASYMINI -			(void) a; -			(void) b; -#else -			switch (type) { -			case 'F': -				ao_flight_ground_accel = a; -				ao_flight_number = b; -				if (ao_config.accel_plus_g == 0) { -					ao_config.accel_plus_g = a; -					ao_config.accel_minus_g = a + 530; +					break; +#endif +				default: +					printf ("invalid log format %d\n", log_format); +					ao_test_exit();  				} -				if (ao_config.main_deploy == 0) -					ao_config.main_deploy = 250; -				ao_flight_started = 1; -				break; -			case 'S': -				break; -			case 'A': -				ao_data_static.tick = tick; -				ao_data_static.adc.accel = a; -				ao_data_static.adc.pres_real = b; -				ao_data_static.adc.pres = b; -				ao_records_read++; -				ao_insert(); -				return; -			case 'T': -				ao_data_static.tick = tick; -				ao_data_static.adc.temp = a; -				ao_data_static.adc.v_batt = b; -				break; -			case 'D': -			case 'G': -			case 'N': -			case 'W': -			case 'H': -				break;  			} -#endif  		}  	} @@ -1190,6 +961,26 @@ void run_flight_fixed(char *name, FILE *f, int summary, char *info)  	emulator_info = info;  	ao_summary = summary; +	if (strstr(name, ".eeprom") != NULL) { +		char	c; + +		c = getc(f); +		ungetc(c, f); +		if (c == '{') +			eeprom = ao_eeprom_read(f); +		else +			eeprom = ao_eeprom_read_old(f); + +		if (eeprom) { +#if HAS_MS5607 +			ao_ms5607_prom = eeprom->ms5607_prom; +#endif +			ao_config = eeprom->config; +			ao_serial_number = eeprom->serial_number; +			log_format = eeprom->log_format; +		} +	} +  	ao_flight_init();  	ao_flight();  } diff --git a/telegps/TeleGPSConfigUI.java b/telegps/TeleGPSConfigUI.java index 88ced192..87683c2b 100644 --- a/telegps/TeleGPSConfigUI.java +++ b/telegps/TeleGPSConfigUI.java @@ -619,7 +619,7 @@ public class TeleGPSConfigUI  		return true;  	} -	void set_dirty() { +	public void set_dirty() {  		dirty = true;  		save.setEnabled(true);  	} @@ -634,6 +634,17 @@ public class TeleGPSConfigUI  		super.dispose();  	} +	public int accel_cal_plus() { +		return AltosLib.MISSING; +	} + +	public int accel_cal_minus() { +		return AltosLib.MISSING; +	} + +	public void set_accel_cal(int accel_plus, int accel_minus) { +	} +  	/* Listen for events from our buttons */  	public void actionPerformed(ActionEvent e) {  		String	cmd = e.getActionCommand();  | 
