diff options
| -rw-r--r-- | altoslib/AltosEepromFile.java | 21 | ||||
| -rw-r--r-- | altoslib/AltosFile.java | 15 | ||||
| -rw-r--r-- | altoslib/AltosGPS.java | 40 | ||||
| -rw-r--r-- | altoslib/AltosLog.java | 23 | ||||
| -rw-r--r-- | altoslib/AltosState.java | 20 | ||||
| -rw-r--r-- | altoslib/AltosTelemetry.java | 337 | ||||
| -rw-r--r-- | altoslib/AltosTelemetryFile.java | 94 | ||||
| -rw-r--r-- | altoslib/AltosTelemetryIterable.java | 71 | ||||
| -rw-r--r-- | altoslib/AltosTelemetryLegacy.java | 556 | ||||
| -rw-r--r-- | altoslib/AltosTelemetryReader.java | 9 | ||||
| -rw-r--r-- | altoslib/Makefile.am | 14 | ||||
| -rw-r--r-- | altosui/AltosUI.java | 6 | 
12 files changed, 866 insertions, 340 deletions
| diff --git a/altoslib/AltosEepromFile.java b/altoslib/AltosEepromFile.java index bcc7171e..2f4c54d7 100644 --- a/altoslib/AltosEepromFile.java +++ b/altoslib/AltosEepromFile.java @@ -57,6 +57,7 @@ public class AltosEepromFile extends AltosStateIterable {  	AltosEepromIterable	headers;  	AltosEepromIterable	body; +	AltosState		start;  	public void write_comments(PrintStream out) {  		headers.write(out); @@ -70,9 +71,9 @@ public class AltosEepromFile extends AltosStateIterable {  	public AltosEepromFile(FileInputStream input) {  		headers = new AltosEepromIterable(AltosEepromHeader.read(input)); -		AltosState	state = headers.state(); +		start = headers.state(); -		switch (state.log_format) { +		switch (start.log_format) {  		case AltosLib.AO_LOG_FORMAT_FULL:  			body = new AltosEepromIterable(AltosEepromTM.read(input));  			break; @@ -86,26 +87,24 @@ public class AltosEepromFile extends AltosStateIterable {  			body = new AltosEepromIterable(AltosEepromMini.read(input));  			break;  		} -	} -	int boost_tick (AltosState start) { +		/* Find boost tick */  		AltosState	state = start.clone();  		for (AltosEeprom eeprom : body) {  			eeprom.update_state(state); -			if (state.state >= AltosLib.ao_flight_boost) -				return state.tick; +			if (state.state >= AltosLib.ao_flight_boost) { +				start.set_boost_tick(state.tick); +				break; +			}  		} -		return 0;  	}  	public Iterator<AltosState> iterator() { - -		AltosState		state = headers.state(); -		Iterator<AltosEeprom>  	i = body.iterator(); +		AltosState		state = start.clone(); +		Iterator<AltosEeprom>	i = body.iterator();  		while (i.hasNext() && !state.valid())  			i.next().update_state(state); -		state.set_boost_tick(boost_tick(state));  		return new AltosEepromIterator(state, i);  	}  }
\ No newline at end of file diff --git a/altoslib/AltosFile.java b/altoslib/AltosFile.java index 90dbc6db..54c54824 100644 --- a/altoslib/AltosFile.java +++ b/altoslib/AltosFile.java @@ -22,10 +22,17 @@ import java.util.*;  public class AltosFile extends File { +	static String number(int n) { +		if (n == AltosRecord.MISSING) +			return "unk"; +		else +			return String.format("%03d", n); +	} +  	public AltosFile(int year, int month, int day, int serial, int flight, String extension) {  		super (AltosPreferences.logdir(), -		       String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", -				     year, month, day, serial, flight, extension)); +		       String.format("%04d-%02d-%02d-serial-%s-flight-%s.%s", +				     year, month, day, number(serial), number(flight), extension));  	}  	public AltosFile(int serial, int flight, String extension) { @@ -37,7 +44,7 @@ public class AltosFile extends File {  		     extension);  	} -	public AltosFile(AltosRecord telem) { -		this(telem.serial, telem.flight, "telem"); +	public AltosFile(AltosState state) { +		this(state.serial, state.flight, "telem");  	}  } diff --git a/altoslib/AltosGPS.java b/altoslib/AltosGPS.java index eb384e4d..399e95b1 100644 --- a/altoslib/AltosGPS.java +++ b/altoslib/AltosGPS.java @@ -70,35 +70,35 @@ public class AltosGPS implements Cloneable {  	}  	public AltosGPS(AltosTelemetryMap map) throws ParseException { -		String	state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, -					       AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); +		String	state = map.get_string(AltosTelemetryLegacy.AO_TELEM_GPS_STATE, +					       AltosTelemetryLegacy.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)) { +		nsat = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_NUM_SAT, 0); +		if (state.equals(AltosTelemetryLegacy.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); +			lat = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); +			lon = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); +			alt = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_ALTITUDE, MISSING); +			year = map.get_int(AltosTelemetryLegacy.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); +			month = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MONTH, MISSING); +			day = map.get_int(AltosTelemetryLegacy.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); +			hour = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HOUR, 0); +			minute = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MINUTE, 0); +			second = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_SECOND, 0); -			ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, +			ground_speed = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HORIZONTAL_SPEED,  						      AltosRecord.MISSING, 1/100.0); -			course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, +			course = map.get_int(AltosTelemetryLegacy.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)) { +			hdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HDOP, MISSING, 1.0); +			vdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_VDOP, MISSING, 1.0); +			h_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HERROR, MISSING); +			v_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_VERROR, MISSING); +		} else if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_UNLOCKED)) {  			connected = true;  			locked = false;  		} else { diff --git a/altoslib/AltosLog.java b/altoslib/AltosLog.java index 974c9f0f..7f69bb65 100644 --- a/altoslib/AltosLog.java +++ b/altoslib/AltosLog.java @@ -57,8 +57,8 @@ public class AltosLog implements Runnable {  		return file;  	} -	boolean open (AltosRecord telem) throws IOException { -		AltosFile	a = new AltosFile(telem); +	boolean open (AltosState state) throws IOException { +		AltosFile	a = new AltosFile(state);  		log_file = new FileWriter(a, true);  		if (log_file != null) { @@ -78,22 +78,25 @@ public class AltosLog implements Runnable {  	public void run () {  		try { -			AltosRecord	previous = null; +			AltosState	state = null;  			for (;;) {  				AltosLine	line = input_queue.take();  				if (line.line == null)  					continue;  				try { -					AltosRecord	telem = AltosTelemetry.parse(line.line, previous); -					if ((telem.seen & AltosRecord.seen_flight) != 0 && -					    (telem.serial != serial || telem.flight != flight || log_file == null)) +					AltosTelemetry	telem = new AltosTelemetryLegacy(line.line); +					if (state != null) +						state = state.clone(); +					else +						state = new AltosState(); +					telem.update_state(state); +					if (state.serial != serial || state.flight != flight || log_file == null)  					{  						close_log_file(); -						serial = telem.serial; -						flight = telem.flight; -						open(telem); +						serial = state.serial; +						flight = state.flight; +						open(state);  					} -					previous = telem;  				} catch (ParseException pe) {  				} catch (AltosCRCException ce) {  				} diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index daf06c19..52650062 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -104,6 +104,7 @@ public class AltosState implements Cloneable {  	public double	accel_minus_g;  	public double	accel;  	public double	ground_accel; +	public double	ground_accel_avg;  	public int	log_format; @@ -201,6 +202,7 @@ public class AltosState implements Cloneable {  		accel_minus_g = AltosRecord.MISSING;  		accel = AltosRecord.MISSING;  		ground_accel = AltosRecord.MISSING; +		ground_accel_avg = AltosRecord.MISSING;  		log_format = AltosRecord.MISSING;  		serial = AltosRecord.MISSING; @@ -306,6 +308,7 @@ public class AltosState implements Cloneable {  		accel_minus_g = old.accel_minus_g;  		accel = old.accel;  		ground_accel = old.ground_accel; +		ground_accel_avg = old.ground_accel_avg;  		log_format = old.log_format;  		serial = old.serial; @@ -396,9 +399,13 @@ public class AltosState implements Cloneable {  	}  	void update_accel() { +		double	ground = ground_accel; + +		if (ground == AltosRecord.MISSING) +			ground = ground_accel_avg;  		if (accel == AltosRecord.MISSING)  			return; -		if (ground_accel == AltosRecord.MISSING) +		if (ground == AltosRecord.MISSING)  			return;  		if (accel_plus_g == AltosRecord.MISSING)  			return; @@ -408,7 +415,7 @@ public class AltosState implements Cloneable {  		double counts_per_g = (accel_minus_g - accel_plus_g) / 2.0;  		double counts_per_mss = counts_per_g / 9.80665; -		acceleration = (ground_accel - accel) / counts_per_mss; +		acceleration = (ground - accel) / counts_per_mss;  		/* Only look at accelerometer data under boost */  		if (boost && acceleration != AltosRecord.MISSING && (max_acceleration == AltosRecord.MISSING || acceleration > max_acceleration)) @@ -556,9 +563,6 @@ public class AltosState implements Cloneable {  	public void set_gps(AltosGPS gps, int sequence) {  		if (gps != null) { -			System.out.printf ("gps date: %d-%d-%d time %d:%d:%d\n", -					   gps.year, gps.month, gps.day, -					   gps.hour, gps.minute, gps.second);  			this.gps = gps.clone();  			gps_sequence = sequence;  			update_gps(); @@ -623,6 +627,12 @@ public class AltosState implements Cloneable {  	public void set_accel(double accel) {  		if (accel != AltosRecord.MISSING) {  			this.accel = accel; +			if (state == AltosLib.ao_flight_pad) { +				if (ground_accel_avg == AltosRecord.MISSING) +					ground_accel_avg = accel; +				else +					ground_accel_avg = (ground_accel_avg * 7 + accel) / 8; +			}  		}  		update_accel();  	} diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index e7322349..b84455d3 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -23,217 +23,136 @@ import java.text.*;   * Telemetry data contents   */ +public abstract class AltosTelemetry implements AltosStateUpdate { + +	/* All telemetry packets have these fields */ +	public int	tick; +	public int	serial; +	public int	rssi; +	public int	status; + +	/* Mark when we received the packet */ +	long		received_time; + +	static boolean cksum(int[] bytes) { +		int	sum = 0x5a; +		for (int i = 1; i < bytes.length - 1; i++) +			sum += bytes[i]; +		sum &= 0xff; +		return sum == bytes[bytes.length - 1]; +	} + +	public void update_state(AltosState state) { +	} +	final static int PKT_APPEND_STATUS_1_CRC_OK		= (1 << 7); +	final static int PKT_APPEND_STATUS_1_LQI_MASK		= (0x7f); +	final static int PKT_APPEND_STATUS_1_LQI_SHIFT		= 0; + +	final static int packet_type_TM_sensor = 0x01; +	final static int packet_type_Tm_sensor = 0x02; +	final static int packet_type_Tn_sensor = 0x03; +	final static int packet_type_configuration = 0x04; +	final static int packet_type_location = 0x05; +	final static int packet_type_satellite = 0x06; +	final static int packet_type_companion = 0x07; +	final static int packet_type_MM_sensor = 0x08; +	final static int packet_type_MM_data = 0x09; +	final static int packet_type_Mini = 0x10; +	 +	static AltosTelemetry parse_hex(String hex)  throws ParseException, AltosCRCException { +		AltosTelemetry	telem = null; + +		int[] bytes; +		try { +			bytes = AltosLib.hexbytes(hex); +		} catch (NumberFormatException ne) { +			throw new ParseException(ne.getMessage(), 0); +		} + +		/* one for length, one for checksum */ +		if (bytes[0] != bytes.length - 2) +			throw new ParseException(String.format("invalid length %d != %d\n", +							       bytes[0], +							       bytes.length - 2), 0); +		if (!cksum(bytes)) +			throw new ParseException(String.format("invalid line \"%s\"", hex), 0); + +		int	rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74; +		int	status = AltosLib.uint8(bytes, bytes.length - 2); + +		if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) +			throw new AltosCRCException(rssi); + +		/* length, data ..., rssi, status, checksum -- 4 bytes extra */ +		switch (bytes.length) { +		case AltosLib.ao_telemetry_standard_len + 4: +			int	type = AltosLib.uint8(bytes, 4 + 1);  /* - * The packet format is a simple hex dump of the raw telemetry frame. - * It starts with 'TELEM', then contains hex digits with a checksum as the last - * byte on the line. - * - * 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: - * - * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -68 STATUS ff STATE     pad  1001 \ - *    a: 16032 p: 21232 t: 20284 v: 25160 d:   204 m:   204 fa: 16038 ga: 16032 fv:       0 \ - *    fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS  0 sat unlocked SAT 1   15  30 - * - * GPS locked: - * - * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -71 STATUS ff STATE     pad  2504 \ - *     a: 16028 p: 21220 t: 20360 v: 25004 d:   208 m:   200 fa: 16031 ga: 16032 fv:     330 \ - *     fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ - *     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 - * - */ +			switch (type) { +			case packet_type_TM_sensor: +			case packet_type_Tm_sensor: +			case packet_type_Tn_sensor: +				telem = new AltosTelemetrySensor(bytes); +				break; +			case packet_type_configuration: +				telem = new AltosTelemetryConfiguration(bytes); +				break; +			case packet_type_location: +				telem = new AltosTelemetryLocation(bytes); +				break; +			case packet_type_satellite: +				telem = new AltosTelemetrySatellite(bytes); +				break; +			case packet_type_companion: +				telem = new AltosTelemetryCompanion(bytes); +				break; +			case packet_type_MM_sensor: +				telem = new AltosTelemetryMegaSensor(bytes); +				break; +			case packet_type_MM_data: +				telem = new AltosTelemetryMegaData(bytes); +				break; +			default: +				telem = new AltosTelemetryRaw(bytes); +				break; +			} +*/ +			break; +		case AltosLib.ao_telemetry_0_9_len + 4: +			telem = new AltosTelemetryLegacy(bytes); +			break; +		case AltosLib.ao_telemetry_0_8_len + 4: +			telem = new AltosTelemetryLegacy(bytes); +			break; +		default: +			throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); +		} +		if (telem != null) { +			telem.received_time = System.currentTimeMillis(); +			telem.rssi = rssi; +			telem.status = status; +		} +		return telem; +	} + +	public static AltosTelemetry parse(String line) throws ParseException, AltosCRCException { +		String[] word = line.split("\\s+"); +		int i =0; + +		if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { +			i += 2; +			AltosParse.word(word[i++], "RSSI"); +			throw new AltosCRCException(AltosParse.parse_int(word[i++])); +		} + +		AltosTelemetry telem; -public abstract class AltosTelemetry extends AltosRecord { - -	/* -	 * 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) -	 */ - -	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"; - -	static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { -		AltosTelemetryRecord	r = AltosTelemetryRecord.parse(line); - -		return r.update_state(previous); +		if (word[i].equals("TELEM")) { +			telem = parse_hex(word[i+1]); +		} else { +			telem = new AltosTelemetryLegacy(line); +		} +		return telem;  	}  } diff --git a/altoslib/AltosTelemetryFile.java b/altoslib/AltosTelemetryFile.java new file mode 100644 index 00000000..9e992576 --- /dev/null +++ b/altoslib/AltosTelemetryFile.java @@ -0,0 +1,94 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; +import java.util.*; +import java.text.*; + +class AltosTelemetryIterator implements Iterator<AltosState> { +	AltosState			state; +	Iterator<AltosTelemetry>	telems; +	AltosTelemetry			next; +	boolean				seen; + +	public boolean hasNext() { +		return !seen || telems.hasNext(); +	} + +	public AltosState next() { +		if (seen) { +			AltosState	n = state.clone(); +			AltosTelemetry	t = telems.next(); + +			t.update_state(n); +			state = n; +		} +		seen = true; +		return state; +	} + +	public void remove () { +	} + +	public AltosTelemetryIterator(AltosState start, Iterator<AltosTelemetry> telems) { +		this.state = start; +		this.telems = telems; +		this.seen = false; +	} +} + +public class AltosTelemetryFile extends AltosStateIterable { + +	AltosTelemetryIterable	telems; +	AltosState		start; + +	public void write_comments(PrintStream out) { +	} + +	public void write(PrintStream out) { +		 +	} + +	public AltosTelemetryFile(FileInputStream input) { +		telems = new AltosTelemetryIterable(input); +		start = new AltosState(); + +		/* Find boost tick */ +		AltosState	state = start.clone(); + +		for (AltosTelemetry telem : telems) { +			telem.update_state(state); +			if (state.state >= AltosLib.ao_flight_boost) { +				start.set_boost_tick(state.tick); +				break; +			} +		} +	} + +	public Iterator<AltosState> iterator() { +		AltosState			state = start.clone(); +		Iterator<AltosTelemetry>  	i = telems.iterator(); + +		while (i.hasNext() && !state.valid()) { +			AltosTelemetry	t = i.next(); +			t.update_state(state); +		} +		return new AltosTelemetryIterator(state, i); +	} +}
\ No newline at end of file diff --git a/altoslib/AltosTelemetryIterable.java b/altoslib/AltosTelemetryIterable.java index 57033638..b7489f77 100644 --- a/altoslib/AltosTelemetryIterable.java +++ b/altoslib/AltosTelemetryIterable.java @@ -21,27 +21,15 @@ import java.io.*;  import java.util.*;  import java.text.*; -public class AltosTelemetryIterable extends AltosRecordIterable { -	TreeSet<AltosRecord>	records; +public class AltosTelemetryIterable implements Iterable<AltosTelemetry> { +	LinkedList<AltosTelemetry>	telems; -	public Iterator<AltosRecord> iterator () { -		return records.iterator(); +	public Iterator<AltosTelemetry> iterator () { +		return telems.iterator();  	} -	boolean has_gps = false; -	boolean has_accel = false; -	boolean has_ignite = false; -	public boolean has_gps() { return has_gps; } -	public boolean has_accel() { return has_accel; } -	public boolean has_ignite() { return has_ignite; }; -  	public AltosTelemetryIterable (FileInputStream input) { -		boolean saw_boost = false; -		int	current_tick = 0; -		int	boost_tick = 0; - -		AltosRecord	previous = null; -		records = new TreeSet<AltosRecord> (); +		telems = new LinkedList<AltosTelemetry> ();  		try {  			for (;;) { @@ -50,32 +38,10 @@ public class AltosTelemetryIterable extends AltosRecordIterable {  					break;  				}  				try { -					AltosRecord record = AltosTelemetry.parse(line, previous); -					if (record == null) +					AltosTelemetry telem = AltosTelemetry.parse(line); +					if (telem == null)  						break; -					if (records.isEmpty()) { -						current_tick = record.tick; -					} else { -						int tick = record.tick; -						while (tick < current_tick - 0x1000) -							tick += 0x10000; -						current_tick = tick; -						record.tick = current_tick; -					} -					if (!saw_boost && record.state >= AltosLib.ao_flight_boost) -					{ -						saw_boost = true; -						boost_tick = record.tick; -					} -					if (record.acceleration() != AltosRecord.MISSING) -						has_accel = true; -					if (record.gps != null) -						has_gps = true; -					if (record.main_voltage() != AltosRecord.MISSING) -						has_ignite = true; -					if (previous != null && previous.tick != record.tick) -						records.add(previous); -					previous = record; +					telems.add(telem);  				} catch (ParseException pe) {  					System.out.printf("parse exception %s\n", pe.getMessage());  				} catch (AltosCRCException ce) { @@ -84,26 +50,5 @@ public class AltosTelemetryIterable extends AltosRecordIterable {  		} catch (IOException io) {  			System.out.printf("io exception\n");  		} - -		if (previous != null) -			records.add(previous); - -		/* Adjust all tick counts to match expected eeprom values, -		 * which starts with a 16-bit tick count 16 samples before boost -		 */ - -		int tick_adjust = (boost_tick - 16) & 0xffff0000; -		for (AltosRecord r : this) -			r.tick -= tick_adjust; -		boost_tick -= tick_adjust; - -		/* adjust all tick counts to be relative to boost time */ -		for (AltosRecord r : this) -			r.time = (r.tick - boost_tick) / 100.0; - -		try { -			input.close(); -		} catch (IOException ie) { -		}  	}  } diff --git a/altoslib/AltosTelemetryLegacy.java b/altoslib/AltosTelemetryLegacy.java new file mode 100644 index 00000000..45e5c315 --- /dev/null +++ b/altoslib/AltosTelemetryLegacy.java @@ -0,0 +1,556 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.text.*; + +/* + * Telemetry data contents + */ + + +/* + * The packet format is a simple hex dump of the raw telemetry frame. + * It starts with 'TELEM', then contains hex digits with a checksum as the last + * byte on the line. + * + * 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: + * + * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -68 STATUS ff STATE     pad  1001 \ + *    a: 16032 p: 21232 t: 20284 v: 25160 d:   204 m:   204 fa: 16038 ga: 16032 fv:       0 \ + *    fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS  0 sat unlocked SAT 1   15  30 + * + * GPS locked: + * + * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -71 STATUS ff STATE     pad  2504 \ + *     a: 16028 p: 21220 t: 20360 v: 25004 d:   208 m:   200 fa: 16031 ga: 16032 fv:     330 \ + *     fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ + *     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 AltosTelemetryLegacy extends AltosTelemetry { +	/* +	 * 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) +	 */ + +	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"; + +	public int	version; +	public String 	callsign; +	public int	flight; +	public int	state; + +	public AltosGPS	gps; +	public int	gps_sequence; + +	/* Telemetry sources have these values recorded from the flight computer */ +	public double	kalman_height; +	public double	kalman_speed; +	public double	kalman_acceleration; + +	/* Sensor values */ +	public int	accel; +	public int	pres; +	public int	temp; +	public int	batt; +	public int	apogee; +	public int	main; + +	public int      ground_accel; +	public int      ground_pres; +	public int      accel_plus_g; +	public int      accel_minus_g; + +	public int	flight_accel; +	public int	flight_vel; +	public int	flight_pres; + +	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, AltosRecord.MISSING); +		flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); +		rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); +		state = AltosLib.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, AltosRecord.MISSING); +		pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING); +		temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING); +		batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING); +		apogee = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING); +		main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING); + +		/* sensor calibration information */ +		ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING); +		ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING); +		accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING); +		accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING); + +		/* flight computer values */ +		kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); +		kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); +		kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); + +		flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING); +		flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); +		flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.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++]; + +		AltosParse.word (words[i++], "SERIAL"); +		serial = AltosParse.parse_int(words[i++]); + +		if (version >= 2) { +			AltosParse.word (words[i++], "FLIGHT"); +			flight = AltosParse.parse_int(words[i++]); +		} else +			flight = 0; + +		AltosParse.word(words[i++], "RSSI"); +		rssi = AltosParse.parse_int(words[i++]); + +		/* Older telemetry data had mis-computed RSSI value */ +		if (version <= 2) +			rssi = (rssi + 74) / 2 - 74; + +		AltosParse.word(words[i++], "STATUS"); +		status = AltosParse.parse_hex(words[i++]); + +		AltosParse.word(words[i++], "STATE"); +		state = AltosLib.state(words[i++]); + +		tick = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "a:"); +		accel = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "p:"); +		pres = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "t:"); +		temp = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "v:"); +		batt = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "d:"); +		apogee = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "m:"); +		main = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "fa:"); +		flight_accel = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "ga:"); +		ground_accel = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "fv:"); +		flight_vel = AltosParse.parse_int(words[i++]); + +		AltosParse.word(words[i++], "fp:"); +		flight_pres = AltosParse.parse_int(words[i++]); + +		/* Old TeleDongle code with kalman-reporting TeleMetrum code */ +		if ((flight_vel & 0xffff0000) == 0x80000000) { +			kalman_speed = ((short) flight_vel) / 16.0; +			kalman_acceleration = flight_accel / 16.0; +			kalman_height = flight_pres; +			flight_vel = AltosRecord.MISSING; +			flight_pres = AltosRecord.MISSING; +			flight_accel = AltosRecord.MISSING; +		} else { +			kalman_speed = AltosRecord.MISSING; +			kalman_acceleration = AltosRecord.MISSING; +			kalman_height = AltosRecord.MISSING; +		} + +		AltosParse.word(words[i++], "gp:"); +		ground_pres = AltosParse.parse_int(words[i++]); + +		if (version >= 1) { +			AltosParse.word(words[i++], "a+:"); +			accel_plus_g = AltosParse.parse_int(words[i++]); + +			AltosParse.word(words[i++], "a-:"); +			accel_minus_g = AltosParse.parse_int(words[i++]); +		} else { +			accel_plus_g = ground_accel; +			accel_minus_g = ground_accel + 530; +		} + +		gps = new AltosGPS(words, i, version); +		gps_sequence++; +	} + +	public AltosTelemetryLegacy(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); +	} + +	/* +	 * Given a hex dump of a legacy telemetry line, construct an AltosRecordTM from that +	 */ + +	int[]	bytes; +	int	adjust; + +	/* +	private int int8(int i) { +		return AltosLib.int8(bytes, i + 1 + adjust); +	} +	*/ +	private int uint8(int i) { +		return AltosLib.uint8(bytes, i + 1 + adjust); +	} +	private int int16(int i) { +		return AltosLib.int16(bytes, i + 1 + adjust); +	} +	private int uint16(int i) { +		return AltosLib.uint16(bytes, i + 1 + adjust); +	} +	private int uint32(int i) { +		return AltosLib.uint32(bytes, i + 1 + adjust); +	} +	private String string(int i, int l) { +		return AltosLib.string(bytes, i + 1 + adjust, l); +	} + +	static final int AO_GPS_NUM_SAT_MASK	= (0xf << 0); +	static final int AO_GPS_NUM_SAT_SHIFT	= (0); + +	static final int AO_GPS_VALID		= (1 << 4); +	static final int AO_GPS_RUNNING		= (1 << 5); +	static final int AO_GPS_DATE_VALID	= (1 << 6); +	static final int AO_GPS_COURSE_VALID	= (1 << 7); + +	public AltosTelemetryLegacy(int[] in_bytes) { +		bytes = in_bytes; +		version = 4; +		adjust = 0; + +		if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { +			serial = uint8(0); +			adjust = -1; +		} else +			serial = uint16(0); + +		callsign = string(62, 8); +		flight = uint16(2); +		state = uint8(4); +		tick = uint16(21); +		accel = int16(23); +		pres = int16(25); +		temp = int16(27); +		batt = int16(29); +		apogee = int16(31); +		main = int16(33); +		 +		ground_accel = int16(7); +		ground_pres = int16(15); +		accel_plus_g = int16(17); +		accel_minus_g = int16(19); + +		if (uint16(11) == 0x8000) { +			kalman_acceleration = int16(5); +			kalman_speed = int16(9); +			kalman_height = int16(13); +			flight_accel = AltosRecord.MISSING; +			flight_vel = AltosRecord.MISSING; +			flight_pres = AltosRecord.MISSING; +		} else { +			flight_accel = int16(5); +			flight_vel = uint32(9); +			flight_pres = int16(13); +			kalman_acceleration = AltosRecord.MISSING; +			kalman_speed = AltosRecord.MISSING; +			kalman_height = AltosRecord.MISSING; +		} + +		gps = null; + +		int gps_flags = uint8(41); + +		if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { +			gps = new AltosGPS(); +			gps_sequence++; + +			gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); +			gps.locked = (gps_flags & AO_GPS_VALID) != 0; +			gps.connected = true; +			gps.lat = uint32(42) / 1.0e7; +			gps.lon = uint32(46) / 1.0e7; +			gps.alt = int16(50); +			gps.ground_speed = uint16(52) / 100.0; +			gps.course = uint8(54) * 2; +			gps.hdop = uint8(55) / 5.0; +			gps.h_error = uint16(58); +			gps.v_error = uint16(60); + +			int	n_tracking_reported = uint8(70); +			if (n_tracking_reported > 12) +				n_tracking_reported = 12; +			int	n_tracking_actual = 0; +			for (int i = 0; i < n_tracking_reported; i++) { +				if (uint8(71 + i*2) != 0) +					n_tracking_actual++; +			} +			if (n_tracking_actual > 0) { +				gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; + +				n_tracking_actual = 0; +				for (int i = 0; i < n_tracking_reported; i++) { +					int	svid = uint8(71 + i*2); +					int	c_n0 = uint8(72 + i*2); +					if (svid != 0) +						gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); +				} +			} +		} +	} + +	public void update_state(AltosState state) { +		state.set_tick(tick); +		state.set_state(this.state); +		state.set_flight(flight); +		state.set_serial(serial); +		state.set_rssi(rssi, status); + +		state.set_pressure(AltosConvert.barometer_to_pressure(pres)); +		state.set_accel_g(accel_plus_g, accel_minus_g); +		state.set_accel(accel); +		if (kalman_height != AltosRecord.MISSING) +			state.set_kalman(kalman_height, kalman_speed, kalman_acceleration); +		state.set_temperature(AltosEepromTM.thermometer_to_temperature(temp)); +		state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(batt)); +		state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(apogee)); +		state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(main)); +		if (gps != null) +			state.set_gps(gps, gps_sequence); +	} +} diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 3915927c..b1cc009c 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -35,9 +35,12 @@ public class AltosTelemetryReader extends AltosFlightReader {  		AltosLine l = telem.take();  		if (l.line == null)  			throw new IOException("IO error"); -		AltosRecord	next = AltosTelemetry.parse(l.line, previous); -		previous = next; -		state = new AltosState (next, state); +		AltosTelemetry	telem = AltosTelemetryLegacy.parse(l.line); +		if (state == null) +			state = new AltosState(); +		else +			state = state.clone(); +		telem.update_state(state);  		return state;  	} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index bbcca906..59e0ec1c 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -72,21 +72,11 @@ altoslib_JAVA = \  	AltosStateIterable.java \  	AltosStateUpdate.java \  	AltosTelemetry.java \ +	AltosTelemetryFile.java \  	AltosTelemetryIterable.java \ +	AltosTelemetryLegacy.java \  	AltosTelemetryMap.java \  	AltosTelemetryReader.java \ -	AltosTelemetryRecordCompanion.java \ -	AltosTelemetryRecordConfiguration.java \ -	AltosTelemetryRecordGeneral.java \ -	AltosTelemetryRecord.java \ -	AltosTelemetryRecordLegacy.java \ -	AltosTelemetryRecordLocation.java \ -	AltosTelemetryRecordRaw.java \ -	AltosTelemetryRecordSatellite.java \ -	AltosTelemetryRecordSensor.java \ -	AltosTelemetryRecordMegaSensor.java \ -	AltosTelemetryRecordMegaData.java \ -	AltosTelemetryRecordMini.java \  	AltosUnitsListener.java \  	AltosMs5607.java \  	AltosIMU.java \ diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 6d5ce185..72b2c0d9 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -437,7 +437,7 @@ public class AltosUI extends AltosUIFrame {  		if (file.getName().endsWith("eeprom")) {  			return new AltosEepromFile(in);  		} else { -			return null; // new AltosTelemetryIterable(in); +			return new AltosTelemetryFile(in);  		}  	} @@ -517,9 +517,9 @@ public class AltosUI extends AltosUIFrame {  	static boolean process_cat(File file) {  		try { -			FileInputStream input = new FileInputStream(file); -			AltosEepromFile eef = new AltosEepromFile(input); +			AltosStateIterable eef = record_iterable(file); +			System.out.printf ("process cat\n");  			for (AltosState state : eef) {  				if ((state.set & AltosState.set_gps) != 0)  					System.out.printf ("time %g lat %g lon %g alt %g\n", | 
