diff options
| author | Keith Packard <keithp@keithp.com> | 2011-03-24 05:27:57 +0900 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2011-03-24 05:27:57 +0900 | 
| commit | f3e68341f6f5daaf26dd162e4f9a06c29988986a (patch) | |
| tree | 2590305c2cc5677f190ae89f4d7ce61005d96544 | |
| parent | 1e976a105423f2da1842f70da531c9051ba88a7f (diff) | |
altosui: Add support for telemetry version 4
New telemetry format needed to support TeleNano and TeleMini
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | altosui/AltosAscent.java | 21 | ||||
| -rw-r--r-- | altosui/AltosCSV.java | 29 | ||||
| -rw-r--r-- | altosui/AltosDataPointReader.java | 2 | ||||
| -rw-r--r-- | altosui/AltosDescent.java | 57 | ||||
| -rw-r--r-- | altosui/AltosFlightUI.java | 23 | ||||
| -rw-r--r-- | altosui/AltosGPS.java | 47 | ||||
| -rw-r--r-- | altosui/AltosLanded.java | 31 | ||||
| -rw-r--r-- | altosui/AltosPad.java | 41 | ||||
| -rw-r--r-- | altosui/AltosRecord.java | 83 | ||||
| -rw-r--r-- | altosui/AltosSiteMap.java | 2 | ||||
| -rw-r--r-- | altosui/AltosState.java | 15 | ||||
| -rw-r--r-- | altosui/AltosTelemetry.java | 267 | ||||
| -rw-r--r-- | altosui/AltosTelemetryIterable.java | 1 | ||||
| -rw-r--r-- | altosui/AltosUI.java | 2 | ||||
| -rw-r--r-- | altosui/Makefile.am | 1 | ||||
| -rw-r--r-- | src/ao_telem.h | 8 | 
16 files changed, 550 insertions, 80 deletions
| diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index 64bdcf30..0fbc5de2 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -87,6 +87,16 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {  		void reset() {  			value.setText("");  		} + +		void show() { +			label.show(); +			value.show(); +		} + +		void hide() { +			label.hide(); +			value.hide(); +		}  		public AscentValue (GridBagLayout layout, int y, String text) {  			GridBagConstraints	c = new GridBagConstraints();  			c.weighty = 1; @@ -247,6 +257,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {  	class Lat extends AscentValue {  		void show (AltosState state, int crc_errors) { +			show();  			if (state.gps != null)  				value.setText(pos(state.gps.lat,"N", "S"));  			else @@ -261,6 +272,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {  	class Lon extends AscentValue {  		void show (AltosState state, int crc_errors) { +			show();  			if (state.gps != null)  				value.setText(pos(state.gps.lon,"E", "W"));  			else @@ -284,8 +296,13 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {  	}  	public void show(AltosState state, int crc_errors) { -		lat.show(state, crc_errors); -		lon.show(state, crc_errors); +		if (state.gps != null) { +			lat.show(state, crc_errors); +			lon.show(state, crc_errors); +		} else { +			lat.hide(); +			lon.hide(); +		}  		height.show(state, crc_errors);  		main.show(state, crc_errors);  		apogee.show(state, crc_errors); diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index df98b2b4..5277c160 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -60,7 +60,7 @@ public class AltosCSV implements AltosWriter {  	 *	drogue (V)  	 *	main (V)  	 * -	 * GPS data +	 * GPS data (if available)  	 *	connected (1/0)  	 *	locked (1/0)  	 *	nsat (used for solution) @@ -179,12 +179,14 @@ public class AltosCSV implements AltosWriter {  		}  	} -	void write_header() { +	void write_header(boolean gps) {  		out.printf("#"); write_general_header();  		out.printf(","); write_flight_header();  		out.printf(","); write_basic_header(); -		out.printf(","); write_gps_header(); -		out.printf(","); write_gps_sat_header(); +		if (gps) { +			out.printf(","); write_gps_header(); +			out.printf(","); write_gps_sat_header(); +		}  		out.printf ("\n");  	} @@ -192,9 +194,12 @@ public class AltosCSV implements AltosWriter {  		state = new AltosState(record, state);  		write_general(record); out.printf(",");  		write_flight(record); out.printf(","); -		write_basic(record); out.printf(","); -		write_gps(record); out.printf(","); -		write_gps_sat(record); +		write_basic(record); +		if (record.gps != null) { +			out.printf(","); +			write_gps(record); out.printf(","); +			write_gps_sat(record); +		}  		out.printf ("\n");  	} @@ -206,7 +211,7 @@ public class AltosCSV implements AltosWriter {  	public void write(AltosRecord record) {  		if (!header_written) { -			write_header(); +			write_header(record.gps != null);  			header_written = true;  		}  		if (!seen_boost) { @@ -240,12 +245,16 @@ public class AltosCSV implements AltosWriter {  			write(r);  	} -	public AltosCSV(File in_name) throws FileNotFoundException { +	public AltosCSV(PrintStream in_out, File in_name) {  		name = in_name; -		out = new PrintStream(name); +		out = in_out;  		pad_records = new LinkedList<AltosRecord>();  	} +	public AltosCSV(File in_name) throws FileNotFoundException { +		this(new PrintStream(in_name), in_name); +	} +  	public AltosCSV(String in_string) throws FileNotFoundException {  		this(new File(in_string));  	} diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index 7704310b..ee57d2ce 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -15,6 +15,8 @@ class AltosDataPointReader implements Iterable<AltosDataPoint> {      AltosState state;      AltosRecord record; +    final static int MISSING = AltosRecord.MISSING; +      public AltosDataPointReader(Iterable<AltosRecord> reader) {          this.iter = reader.iterator();          this.state = null; diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 16ccd458..594a7a09 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -37,6 +37,19 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {  		AltosLights	lights;  		abstract void show(AltosState state, int crc_errors); + +		void show() { +			label.show(); +			value.show(); +			lights.show(); +		} + +		void hide() { +			label.hide(); +			value.hide(); +			lights.hide(); +		} +  		void reset() {  			value.setText("");  			lights.set(false); @@ -90,6 +103,16 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {  		abstract void show(AltosState state, int crc_errors); +		void show() { +			label.show(); +			value.show(); +		} + +		void hide() { +			label.hide(); +			value.hide(); +		} +  		void show(String format, double v) {  			value.setText(String.format(format, v));  		} @@ -134,12 +157,27 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {  			value2.setText("");  		} +		void show() { +			label.show(); +			value1.show(); +			value2.show(); +		} + +		void hide() { +			label.hide(); +			value1.hide(); +			value2.hide(); +		} +  		abstract void show(AltosState state, int crc_errors); +  		void show(String v1, String v2) { +			show();  			value1.setText(v1);  			value2.setText(v2);  		}  		void show(String f1, double v1, String f2, double v2) { +			show();  			value1.setText(String.format(f1, v1));  			value2.setText(String.format(f2, v2));  		} @@ -260,6 +298,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {  	class Main extends DescentStatus {  		void show (AltosState state, int crc_errors) { +			show();  			value.setText(String.format("%4.2f V", state.main_sense));  			lights.set(state.main_sense > 3.2);  		} @@ -324,11 +363,19 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {  	public void show(AltosState state, int crc_errors) {  		height.show(state, crc_errors);  		speed.show(state, crc_errors); -		bearing.show(state, crc_errors); -		range.show(state, crc_errors); -		elevation.show(state, crc_errors); -		lat.show(state, crc_errors); -		lon.show(state, crc_errors); +		if (state.gps != null) { +			bearing.show(state, crc_errors); +			range.show(state, crc_errors); +			elevation.show(state, crc_errors); +			lat.show(state, crc_errors); +			lon.show(state, crc_errors); +		} else { +			bearing.hide(); +			range.hide(); +			elevation.hide(); +			lat.hide(); +			lon.hide(); +		}  		main.show(state, crc_errors);  		apogee.show(state, crc_errors);  	} diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 7fcfb8be..68e0ef87 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -29,9 +29,6 @@ import java.util.prefs.*;  import java.util.concurrent.LinkedBlockingQueue;  public class AltosFlightUI extends JFrame implements AltosFlightDisplay { -	String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" }; -	Object[][] statusData = { { "0", "pad", "-50", "0" } }; -  	AltosVoice		voice;  	AltosFlightReader	reader;  	AltosDisplayThread	thread; @@ -43,6 +40,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {  	AltosDescent	descent;  	AltosLanded	landed;  	AltosSiteMap    sitemap; +	boolean		has_map;  	private AltosFlightStatus flightStatus;  	private AltosInfoTable flightInfo; @@ -85,6 +83,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {  	public void show(AltosState state, int crc_errors) {  		JComponent tab = which_tab(state); +		try {  		pad.show(state, crc_errors);  		ascent.show(state, crc_errors);  		descent.show(state, crc_errors); @@ -97,7 +96,21 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {  		}  		flightStatus.show(state, crc_errors);  		flightInfo.show(state, crc_errors); -		sitemap.show(state, crc_errors); +		if (state.gps != null) { +			if (!has_map) { +				pane.add("Site Map", sitemap); +				has_map = true; +			} +			sitemap.show(state, crc_errors); +		} else { +			if (has_map) { +				pane.remove(sitemap); +				has_map = false; +			} +		} +		} catch (Exception e) { +			System.out.print("Show exception" + e); +		}  	}  	public void set_exit_on_close() { @@ -169,7 +182,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay {  		pane.add("Table", new JScrollPane(flightInfo));  		sitemap = new AltosSiteMap(); -		pane.add("Site Map", sitemap); +		has_map = false;  		/* Make the tabbed pane use the rest of the window space */  		c.gridx = 0; diff --git a/altosui/AltosGPS.java b/altosui/AltosGPS.java index 83821842..0dbc8364 100644 --- a/altosui/AltosGPS.java +++ b/altosui/AltosGPS.java @@ -26,10 +26,11 @@ public class AltosGPS {  		int	c_n0;  	} +	final static int MISSING = AltosRecord.MISSING; +  	int	nsat;  	boolean	locked;  	boolean	connected; -	boolean date_valid;  	double	lat;		/* degrees (+N -S) */  	double	lon;		/* degrees (+E -W) */  	int	alt;		/* m */ @@ -40,11 +41,11 @@ public class AltosGPS {  	int	minute;  	int	second; -	int	gps_extended;	/* has extra data */  	double	ground_speed;	/* m/s */  	int	course;		/* degrees */  	double	climb_rate;	/* m/s */ -	double	hdop;		/* unitless? */ +	double	hdop;		/* unitless */ +	double	vdop;		/* unitless */  	int	h_error;	/* m */  	int	v_error;	/* m */ @@ -73,6 +74,44 @@ public class AltosGPS {  		hour = minute = second = 0;  	} +	public AltosGPS(AltosTelemetryMap map) throws ParseException { +		String	state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, +					       AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); + +		nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0); +		if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) { +			connected = true; +			locked = true; +			lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); +			lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); +			alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING); +			year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING); +			if (year != MISSING) +				year += 2000; +			month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING); +			day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING); + +			hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0); +			minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0); +			second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0); + +			ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, +						      AltosRecord.MISSING, 1/100.0); +			course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, +					     AltosRecord.MISSING); +			hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0); +			vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0); +			h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING); +			v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING); +		} else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) { +			connected = true; +			locked = false; +		} else { +			connected = false; +			locked = false; +		} +	} +  	public AltosGPS(String[] words, int i, int version) throws ParseException {  		AltosParse.word(words[i++], "GPS");  		nsat = AltosParse.parse_int(words[i++]); @@ -184,7 +223,6 @@ public class AltosGPS {  		nsat = old.nsat;  		locked = old.locked;  		connected = old.connected; -		date_valid = old.date_valid;  		lat = old.lat;		/* degrees (+N -S) */  		lon = old.lon;		/* degrees (+E -W) */  		alt = old.alt;		/* m */ @@ -195,7 +233,6 @@ public class AltosGPS {  		minute = old.minute;  		second = old.second; -		gps_extended = old.gps_extended;	/* has extra data */  		ground_speed = old.ground_speed;	/* m/s */  		course = old.course;		/* degrees */  		climb_rate = old.climb_rate;	/* m/s */ diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index d34efe6d..0717ffe2 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -42,10 +42,22 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {  			value.setText("");  		} +		void show() { +			label.show(); +			value.show(); +		} + +		void hide() { +			label.hide(); +			value.hide(); +		} +  		void show(String format, double v) { +			show();  			value.setText(String.format(format, v));  		} +  		public LandedValue (GridBagLayout layout, int y, String text) {  			GridBagConstraints	c = new GridBagConstraints();  			c.weighty = 1; @@ -86,6 +98,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {  	class Lat extends LandedValue {  		void show (AltosState state, int crc_errors) { +			show();  			if (state.gps != null)  				value.setText(pos(state.gps.lat,"N", "S"));  			else @@ -100,6 +113,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {  	class Lon extends LandedValue {  		void show (AltosState state, int crc_errors) { +			show();  			if (state.gps != null)  				value.setText(pos(state.gps.lon,"E", "W"));  			else @@ -114,6 +128,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {  	class Bearing extends LandedValue {  		void show (AltosState state, int crc_errors) { +			show();  			if (state.from_pad != null)  				show("%3.0f°", state.from_pad.bearing);  			else @@ -128,6 +143,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {  	class Distance extends LandedValue {  		void show (AltosState state, int crc_errors) { +			show();  			if (state.from_pad != null)  				show("%6.0f m", state.from_pad.distance);  			else @@ -184,10 +200,17 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay {  	}  	public void show(AltosState state, int crc_errors) { -		bearing.show(state, crc_errors); -		distance.show(state, crc_errors); -		lat.show(state, crc_errors); -		lon.show(state, crc_errors); +		if (state.gps != null) { +			bearing.show(state, crc_errors); +			distance.show(state, crc_errors); +			lat.show(state, crc_errors); +			lon.show(state, crc_errors); +		} else { +			bearing.hide(); +			distance.hide(); +			lat.hide(); +			lon.hide(); +		}  		height.show(state, crc_errors);  		speed.show(state, crc_errors);  		accel.show(state, crc_errors); diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index e345e5da..2f59e879 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -42,6 +42,18 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {  			lights.set(false);  		} +		public void show() { +			label.show(); +			value.show(); +			lights.show(); +		} + +		public void hide() { +			label.hide(); +			value.hide(); +			lights.hide(); +		} +  		public LaunchStatus (GridBagLayout layout, int y, String text) {  			GridBagConstraints	c = new GridBagConstraints();  			c.weighty = 1; @@ -83,6 +95,16 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {  		JTextField	value;  		void show(AltosState state, int crc_errors) {} +		void show() { +			label.show(); +			value.show(); +		} + +		void hide() { +			label.hide(); +			value.hide(); +		} +  		void reset() {  			value.setText("");  		} @@ -151,6 +173,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {  	class GPSLocked extends LaunchStatus {  		void show (AltosState state, int crc_errors) { +			show();  			value.setText(String.format("%4d sats", state.gps.nsat));  			lights.set(state.gps.locked && state.gps.nsat >= 4);  		} @@ -163,6 +186,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {  	class GPSReady extends LaunchStatus {  		void show (AltosState state, int crc_errors) { +			show();  			if (state.gps_ready)  				value.setText("Ready");  			else @@ -189,6 +213,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {  	class PadLat extends LaunchValue {  		void show (AltosState state, int crc_errors) { +			show();  			value.setText(pos(state.pad_lat,"N", "S"));  		}  		public PadLat (GridBagLayout layout, int y) { @@ -200,6 +225,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {  	class PadLon extends LaunchValue {  		void show (AltosState state, int crc_errors) { +			show();  			value.setText(pos(state.pad_lon,"E", "W"));  		}  		public PadLon (GridBagLayout layout, int y) { @@ -235,11 +261,18 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {  		battery.show(state, crc_errors);  		apogee.show(state, crc_errors);  		main.show(state, crc_errors); -		gps_locked.show(state, crc_errors); -		gps_ready.show(state, crc_errors); -		pad_lat.show(state, crc_errors); -		pad_lon.show(state, crc_errors);  		pad_alt.show(state, crc_errors); +		if (state.gps != null) { +			gps_locked.show(state, crc_errors); +			gps_ready.show(state, crc_errors); +			pad_lat.show(state, crc_errors); +			pad_lon.show(state, crc_errors); +		} else { +			gps_locked.hide(); +			gps_ready.hide(); +			pad_lat.hide(); +			pad_lon.hide(); +		}  	}  	public AltosPad() { diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index 1160a273..46e96b95 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -23,6 +23,8 @@ import java.util.HashMap;  import java.io.*;  public class AltosRecord { +	final static int	MISSING = 0x7fffffff; +  	int	version;  	String 	callsign;  	int	serial; @@ -31,19 +33,27 @@ public class AltosRecord {  	int	status;  	int	state;  	int	tick; +  	int	accel;  	int	pres;  	int	temp;  	int	batt;  	int	drogue;  	int	main; -	int	flight_accel; +  	int	ground_accel; -	int	flight_vel; -	int	flight_pres;  	int	ground_pres;  	int	accel_plus_g;  	int	accel_minus_g; + +	double	acceleration; +	double	speed; +	double	height; + +	int	flight_accel; +	int	flight_vel; +	int	flight_pres; +  	AltosGPS	gps;  	double	time;	/* seconds since boost */ @@ -72,46 +82,82 @@ public class AltosRecord {  	}  	public double raw_pressure() { +		if (pres == MISSING) +			return MISSING;  		return barometer_to_pressure(pres);  	}  	public double filtered_pressure() { +		if (flight_pres == MISSING) +			return MISSING;  		return barometer_to_pressure(flight_pres);  	}  	public double ground_pressure() { +		if (ground_pres == MISSING) +			return MISSING;  		return barometer_to_pressure(ground_pres);  	} -	public double filtered_altitude() { -		return AltosConvert.pressure_to_altitude(filtered_pressure()); -	} -  	public double raw_altitude() { -		return AltosConvert.pressure_to_altitude(raw_pressure()); +		double p = raw_pressure(); +		if (p == MISSING) +			return MISSING; +		return AltosConvert.pressure_to_altitude(p);  	}  	public double ground_altitude() { -		return AltosConvert.pressure_to_altitude(ground_pressure()); +		double p = ground_pressure(); +		if (p == MISSING) +			return MISSING; +		return AltosConvert.pressure_to_altitude(p); +	} + +	public double filtered_altitude() { +		if (height != MISSING && ground_pres != MISSING) +			return height + ground_altitude(); + +		double	p = filtered_pressure(); +		if (p == MISSING) +			return MISSING; +		return AltosConvert.pressure_to_altitude(p);  	}  	public double filtered_height() { -		return filtered_altitude() - ground_altitude(); +		if (height != MISSING) +			return height; + +		double f = filtered_altitude(); +		double g = ground_altitude(); +		if (f == MISSING || g == MISSING) +			return MISSING; +		return f - g;  	}  	public double raw_height() { -		return raw_altitude() - ground_altitude(); +		double r = raw_altitude(); +		double g = ground_altitude(); + +		if (r == MISSING || g == MISSING) +			return MISSING; +		return r - g;  	}  	public double battery_voltage() { +		if (batt == MISSING) +			return MISSING;  		return AltosConvert.cc_battery_to_voltage(batt);  	}  	public double main_voltage() { +		if (main == MISSING) +			return MISSING;  		return AltosConvert.cc_ignitor_to_voltage(main);  	}  	public double drogue_voltage() { +		if (drogue == MISSING) +			return MISSING;  		return AltosConvert.cc_ignitor_to_voltage(drogue);  	} @@ -131,6 +177,8 @@ public class AltosRecord {  	}  	public double temperature() { +		if (temp == MISSING) +			return MISSING;  		return thermometer_to_temperature(temp);  	} @@ -139,13 +187,22 @@ public class AltosRecord {  		return counts_per_g / 9.80665;  	} +  	public double acceleration() { +		if (acceleration != MISSING) +			return acceleration; + +		if (ground_accel == MISSING || accel == MISSING) +			return MISSING;  		return (ground_accel - accel) / accel_counts_per_mss();  	}  	public double accel_speed() { -		double speed = flight_vel / (accel_counts_per_mss() * 100.0); -		return speed; +		if (speed != MISSING) +			return speed; +		if (flight_vel == MISSING) +			return MISSING; +		return flight_vel / (accel_counts_per_mss() * 100.0);  	}  	public String state() { diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index d6bd6d1f..f4b6b7e0 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -228,8 +228,6 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {  	int last_state = -1;  	public void show(final AltosState state, final int crc_errors) {  		// if insufficient gps data, nothing to update -		if (state.gps == null) -			return;  		if (!state.gps.locked && state.gps.nsat < 4)  			return; diff --git a/altosui/AltosState.java b/altosui/AltosState.java index ec499d5a..4e165f80 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -79,7 +79,8 @@ public class AltosState {  		data = cur;  		ground_altitude = data.ground_altitude(); -		height = data.filtered_altitude() - ground_altitude; +		height = data.filtered_height(); +		System.out.printf("height %g\n", height);  		report_time = System.currentTimeMillis(); @@ -114,10 +115,14 @@ public class AltosState {  			/* compute barometric speed */  			double height_change = height - prev_state.height; -			if (time_change > 0) -				baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; -			else -				baro_speed = prev_state.baro_speed; +			if (data.speed != AltosRecord.MISSING) +				baro_speed = data.speed; +			else { +				if (time_change > 0) +					baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; +				else +					baro_speed = prev_state.baro_speed; +			}  		} else {  			npad = 0;  			ngps = 0; diff --git a/altosui/AltosTelemetry.java b/altosui/AltosTelemetry.java index bdb6466a..3eb0efa8 100644 --- a/altosui/AltosTelemetry.java +++ b/altosui/AltosTelemetry.java @@ -27,10 +27,40 @@ import java.util.HashMap;  /* - * The telemetry data stream is a bit of a mess at present, with no consistent - * formatting. In particular, the GPS data is formatted for viewing instead of parsing. - * However, the key feature is that every telemetry line contains all of the information - * necessary to describe the current rocket state, including the calibration values + * Version 4 is a replacement with consistent syntax. Each telemetry line + * contains a sequence of space-separated names and values, the values are + * either integers or strings. The names are all unique. All values are + * optional + * + * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 + *   r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 + *   a_s 0 a_b 26439 g_s u g_n 0 s_n 0 + * + * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 + *   r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 + * + * General header fields + * + *	Name		Value + * + *	VERSION		Telemetry version number (4 or more). Must be first. + * 	c		Callsign (string, no spaces allowed) + *	n		Flight unit serial number (integer) + * 	f		Flight number (integer) + *	r		Packet RSSI value (integer) + * 	s		Flight computer state (string, no spaces allowed) + *	t		Flight computer clock (integer in centiseconds) + * + * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports + * in 1/2dB increments while this protocol provides only integers. So, + * the syntax didn't change just the interpretation of the RSSI + * values. + * + * Version 2 of the telemetry data stream is a bit of a mess, with no + * consistent formatting. In particular, the GPS data is formatted for + * viewing instead of parsing.  However, the key feature is that every + * telemetry line contains all of the information necessary to + * describe the current rocket state, including the calibration values   * for accelerometer and barometer.   *   * GPS unlocked: @@ -47,25 +77,201 @@ import java.util.HashMap;   *     GPS  9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W  1790m  \   *     0.00m/s(H) 0°     0.00m/s(V) 1.0(hdop)     0(herr)     0(verr) \   *     SAT 10   29  30  24  28   5  25  21  20  15  33   1  23  30  24  18  26  10  29   2  26 + *   */  public class AltosTelemetry extends AltosRecord { -	public AltosTelemetry(String line) throws ParseException, AltosCRCException { -		String[] words = line.split("\\s+"); -		int	i = 0; +	/* +	 * General header fields +	 * +	 *	Name		Value +	 * +	 *	VERSION		Telemetry version number (4 or more). Must be first. +	 * 	c		Callsign (string, no spaces allowed) +	 *	n		Flight unit serial number (integer) +	 * 	f		Flight number (integer) +	 *	r		Packet RSSI value (integer) +	 * 	s		Flight computer state (string, no spaces allowed) +	 *	t		Flight computer clock (integer in centiseconds) +	 */ -		if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { -			i += 2; -			AltosParse.word(words[i++], "RSSI"); -			rssi = AltosParse.parse_int(words[i++]); -			throw new AltosCRCException(rssi); -		} -		if (words[i].equals("CALL")) { -			version = 0; -		} else { -			AltosParse.word (words[i++], "VERSION"); -			version = AltosParse.parse_int(words[i++]); -		} +	final static String AO_TELEM_VERSION	= "VERSION"; +	final static String AO_TELEM_CALL	= "c"; +	final static String AO_TELEM_SERIAL	= "n"; +	final static String AO_TELEM_FLIGHT	= "f"; +	final static String AO_TELEM_RSSI	= "r"; +	final static String AO_TELEM_STATE	= "s"; +	final static String AO_TELEM_TICK	= "t"; + +	/* +	 * Raw sensor values +	 * +	 *	Name		Value +	 *	r_a		Accelerometer reading (integer) +	 *	r_b		Barometer reading (integer) +	 *	r_t		Thermometer reading (integer) +	 *	r_v		Battery reading (integer) +	 *	r_d		Drogue continuity (integer) +	 *	r_m		Main continuity (integer) +	 */ + +	final static String AO_TELEM_RAW_ACCEL	= "r_a"; +	final static String AO_TELEM_RAW_BARO	= "r_b"; +	final static String AO_TELEM_RAW_THERMO	= "r_t"; +	final static String AO_TELEM_RAW_BATT	= "r_v"; +	final static String AO_TELEM_RAW_DROGUE	= "r_d"; +	final static String AO_TELEM_RAW_MAIN	= "r_m"; + +	/* +	 * Sensor calibration values +	 * +	 *	Name		Value +	 *	c_a		Ground accelerometer reading (integer) +	 *	c_b		Ground barometer reading (integer) +	 *	c_p		Accelerometer reading for +1g +	 *	c_m		Accelerometer reading for -1g +	 */ + +	final static String AO_TELEM_CAL_ACCEL_GROUND	= "c_a"; +	final static String AO_TELEM_CAL_BARO_GROUND	= "c_b"; +	final static String AO_TELEM_CAL_ACCEL_PLUS	= "c_p"; +	final static String AO_TELEM_CAL_ACCEL_MINUS	= "c_m"; + +	/* +	 * Kalman state values +	 * +	 *	Name		Value +	 *	k_h		Height above pad (integer, meters) +	 *	k_s		Vertical speeed (integer, m/s * 16) +	 *	k_a		Vertical acceleration (integer, m/s² * 16) +	 */ + +	final static String AO_TELEM_KALMAN_HEIGHT	= "k_h"; +	final static String AO_TELEM_KALMAN_SPEED	= "k_s"; +	final static String AO_TELEM_KALMAN_ACCEL	= "k_a"; + +	/* +	 * Ad-hoc flight values +	 * +	 *	Name		Value +	 *	a_a		Acceleration (integer, sensor units) +	 *	a_s		Speed (integer, integrated acceleration value) +	 *	a_b		Barometer reading (integer, sensor units) +	 */ + +	final static String AO_TELEM_ADHOC_ACCEL	= "a_a"; +	final static String AO_TELEM_ADHOC_SPEED	= "a_s"; +	final static String AO_TELEM_ADHOC_BARO		= "a_b"; + +	/* +	 * GPS values +	 * +	 *	Name		Value +	 *	g_s		GPS state (string): +	 *				l	locked +	 *				u	unlocked +	 *				e	error (missing or broken) +	 *	g_n		Number of sats used in solution +	 *	g_ns		Latitude (degrees * 10e7) +	 *	g_ew		Longitude (degrees * 10e7) +	 *	g_a		Altitude (integer meters) +	 *	g_Y		GPS year (integer) +	 *	g_M		GPS month (integer - 1-12) +	 *	g_D		GPS day (integer - 1-31) +	 *	g_h		GPS hour (integer - 0-23) +	 *	g_m		GPS minute (integer - 0-59) +	 *	g_s		GPS second (integer - 0-59) +	 *	g_v		GPS vertical speed (integer, cm/sec) +	 *	g_s		GPS horizontal speed (integer, cm/sec) +	 *	g_c		GPS course (integer, 0-359) +	 *	g_hd		GPS hdop (integer * 10) +	 *	g_vd		GPS vdop (integer * 10) +	 *	g_he		GPS h error (integer) +	 *	g_ve		GPS v error (integer) +	 */ + +	final static String AO_TELEM_GPS_STATE	 		= "g"; +	final static String AO_TELEM_GPS_STATE_LOCKED		= "l"; +	final static String AO_TELEM_GPS_STATE_UNLOCKED		= "u"; +	final static String AO_TELEM_GPS_STATE_ERROR		= "e"; +	final static String AO_TELEM_GPS_NUM_SAT		= "g_n"; +	final static String AO_TELEM_GPS_LATITUDE		= "g_ns"; +	final static String AO_TELEM_GPS_LONGITUDE		= "g_ew"; +	final static String AO_TELEM_GPS_ALTITUDE		= "g_a"; +	final static String AO_TELEM_GPS_YEAR			= "g_Y"; +	final static String AO_TELEM_GPS_MONTH			= "g_M"; +	final static String AO_TELEM_GPS_DAY			= "g_D"; +	final static String AO_TELEM_GPS_HOUR			= "g_h"; +	final static String AO_TELEM_GPS_MINUTE			= "g_m"; +	final static String AO_TELEM_GPS_SECOND			= "g_s"; +	final static String AO_TELEM_GPS_VERTICAL_SPEED		= "g_v"; +	final static String AO_TELEM_GPS_HORIZONTAL_SPEED	= "g_g"; +	final static String AO_TELEM_GPS_COURSE			= "g_c"; +	final static String AO_TELEM_GPS_HDOP			= "g_hd"; +	final static String AO_TELEM_GPS_VDOP			= "g_vd"; +	final static String AO_TELEM_GPS_HERROR			= "g_he"; +	final static String AO_TELEM_GPS_VERROR			= "g_ve"; + +	/* +	 * GPS satellite values +	 * +	 *	Name		Value +	 *	s_n		Number of satellites reported (integer) +	 *	s_v0		Space vehicle ID (integer) for report 0 +	 *	s_c0		C/N0 number (integer) for report 0 +	 *	s_v1		Space vehicle ID (integer) for report 1 +	 *	s_c1		C/N0 number (integer) for report 1 +	 *	... +	 */ + +	final static String AO_TELEM_SAT_NUM	= "s_n"; +	final static String AO_TELEM_SAT_SVID	= "s_v"; +	final static String AO_TELEM_SAT_C_N_0	= "s_c"; + +	private void parse_v4(String[] words, int i) throws ParseException { +		AltosTelemetryMap	map = new AltosTelemetryMap(words, i); + +		callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); +		serial = map.get_int(AO_TELEM_SERIAL, MISSING); +		flight = map.get_int(AO_TELEM_FLIGHT, MISSING); +		rssi = map.get_int(AO_TELEM_RSSI, MISSING); +		state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); +		tick = map.get_int(AO_TELEM_TICK, 0); + +		/* raw sensor values */ +		accel = map.get_int(AO_TELEM_RAW_ACCEL, MISSING); +		pres = map.get_int(AO_TELEM_RAW_BARO, MISSING); +		temp = map.get_int(AO_TELEM_RAW_THERMO, MISSING); +		batt = map.get_int(AO_TELEM_RAW_BATT, MISSING); +		drogue = map.get_int(AO_TELEM_RAW_DROGUE, MISSING); +		main = map.get_int(AO_TELEM_RAW_MAIN, MISSING); + +		/* sensor calibration information */ +		ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, MISSING); +		ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, MISSING); +		accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, MISSING); +		accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, MISSING); + +		/* flight computer values */ +		acceleration = map.get_int(AO_TELEM_KALMAN_ACCEL, MISSING); +		if (acceleration != MISSING) +			acceleration /= 16.0; +		speed = map.get_int(AO_TELEM_KALMAN_SPEED, MISSING); +		if (speed != MISSING) +			speed /= 16.0; +		height = map.get_int(AO_TELEM_KALMAN_HEIGHT, MISSING); + +		flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, MISSING); +		flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, MISSING); +		flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, MISSING); + +		if (map.has(AO_TELEM_GPS_STATE)) +			gps = new AltosGPS(map); +		else +			gps = null; +	} + +	private void parse_legacy(String[] words, int i) throws ParseException {  		AltosParse.word (words[i++], "CALL");  		callsign = words[i++]; @@ -140,4 +346,27 @@ public class AltosTelemetry extends AltosRecord {  		gps = new AltosGPS(words, i, version);  	} + +	public AltosTelemetry(String line) throws ParseException, AltosCRCException { +		String[] words = line.split("\\s+"); +		int	i = 0; + +		if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { +			i += 2; +			AltosParse.word(words[i++], "RSSI"); +			rssi = AltosParse.parse_int(words[i++]); +			throw new AltosCRCException(rssi); +		} +		if (words[i].equals("CALL")) { +			version = 0; +		} else { +			AltosParse.word (words[i++], "VERSION"); +			version = AltosParse.parse_int(words[i++]); +		} + +		if (version < 4) +			parse_legacy(words, i); +		else +			parse_v4(words, i); +	}  } diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java index a71ab872..14b5f27f 100644 --- a/altosui/AltosTelemetryIterable.java +++ b/altosui/AltosTelemetryIterable.java @@ -63,7 +63,6 @@ public class AltosTelemetryIterable extends AltosRecordIterable {  				} catch (ParseException pe) {  					System.out.printf("parse exception %s\n", pe.getMessage());  				} catch (AltosCRCException ce) { -					System.out.printf("crc error\n");  				}  			}  		} catch (IOException io) { diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 90e3d7f0..4d17b0d2 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -328,7 +328,7 @@ public class AltosUI extends JFrame {  			if (input.equals(output)) {  				System.out.printf("Not processing '%s'\n", input);  			} else { -				AltosWriter writer = open_csv(output); +				AltosWriter writer = open_csv("/dev/stdout");  				if (writer != null) {  					writer.write(iterable);  					writer.close(); diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 288fca0e..49f34ce3 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -65,6 +65,7 @@ altosui_JAVA = \  	AltosRecord.java \  	AltosRecordIterable.java \  	AltosTelemetryReader.java \ +	AltosTelemetryMap.java \  	AltosReplayReader.java \  	AltosRomconfig.java \  	AltosRomconfigUI.java \ diff --git a/src/ao_telem.h b/src/ao_telem.h index b1624fe0..1a8da291 100644 --- a/src/ao_telem.h +++ b/src/ao_telem.h @@ -108,7 +108,7 @@   * GPS values   *   *	Name		Value - *	g_s		GPS state (string): + *	g		GPS state (string):   *				l	locked   *				u	unlocked   *				e	error (missing or broken) @@ -123,7 +123,7 @@   *	g_m		GPS minute (integer - 0-59)   *	g_s		GPS second (integer - 0-59)   *	g_v		GPS vertical speed (integer, cm/sec) - *	g_s		GPS horizontal speed (integer, cm/sec) + *	g_g		GPS horizontal speed (integer, cm/sec)   *	g_c		GPS course (integer, 0-359)   *	g_hd		GPS hdop (integer * 10)   *	g_vd		GPS vdop (integer * 10) @@ -131,7 +131,7 @@   *	g_ve		GPS v error (integer)   */ -#define AO_TELEM_GPS_STATE		"g_s" +#define AO_TELEM_GPS_STATE		"g"  #define AO_TELEM_GPS_STATE_LOCKED	'l'  #define AO_TELEM_GPS_STATE_UNLOCKED	'u'  #define AO_TELEM_GPS_STATE_ERROR	'e' @@ -146,7 +146,7 @@  #define AO_TELEM_GPS_MINUTE		"g_m"  #define AO_TELEM_GPS_SECOND		"g_s"  #define AO_TELEM_GPS_VERTICAL_SPEED	"g_v" -#define AO_TELEM_GPS_HORIZONTAL_SPEED	"g_s" +#define AO_TELEM_GPS_HORIZONTAL_SPEED	"g_g"  #define AO_TELEM_GPS_COURSE		"g_c"  #define AO_TELEM_GPS_HDOP		"g_hd"  #define AO_TELEM_GPS_VDOP		"g_vd" | 
