diff options
Diffstat (limited to 'altoslib')
34 files changed, 743 insertions, 446 deletions
diff --git a/altoslib/AltosCSV.java b/altoslib/AltosCSV.java index f55b4785..a8de23f0 100644 --- a/altoslib/AltosCSV.java +++ b/altoslib/AltosCSV.java @@ -29,9 +29,11 @@ public class AltosCSV implements AltosWriter {  	int			boost_tick;  	boolean			has_basic; +	boolean			has_radio;  	boolean			has_battery;  	boolean			has_flight_state;  	boolean			has_advanced; +	boolean			has_igniter;  	boolean			has_gps;  	boolean			has_gps_sat;  	boolean			has_companion; @@ -39,7 +41,7 @@ public class AltosCSV implements AltosWriter {  	AltosFlightSeries	series;  	int[]			indices; -	static final int ALTOS_CSV_VERSION = 5; +	static final int ALTOS_CSV_VERSION = 6;  	/* Version 4 format:  	 * @@ -49,7 +51,8 @@ public class AltosCSV implements AltosWriter {  	 *	flight number  	 *	callsign  	 *	time (seconds since boost) -	 *	clock (tick count / 100) +	 * +	 * Radio info (if available)  	 *	rssi  	 *	link quality  	 * @@ -81,6 +84,14 @@ public class AltosCSV implements AltosWriter {  	 *	mag_x (g)  	 *	mag_y (g)  	 *	mag_z (g) +	 *	tilt (d) +	 * +	 * Extra igniter voltages (if available) +	 *	pyro (V) +	 *	igniter_a (V) +	 *	igniter_b (V) +	 *	igniter_c (V) +	 *	igniter_d (V)  	 *  	 * GPS data (if available)  	 *	connected (1/0) @@ -115,13 +126,26 @@ public class AltosCSV implements AltosWriter {  	 */  	void write_general_header() { -		out.printf("version,serial,flight,call,time,clock,rssi,lqi"); +		out.printf("version,serial,flight,call,time");  	}  	double time() {  		return series.time(indices);  	} +	void write_general() { +		out.printf("%s, %d, %d, %s, %8.2f", +			   ALTOS_CSV_VERSION, +			   series.cal_data().serial, +			   series.cal_data().flight, +			   series.cal_data().callsign, +			   time()); +	} + +	void write_radio_header() { +		out.printf("rssi,lqi"); +	} +  	int rssi() {  		return (int) series.value(AltosFlightSeries.rssi_name, indices);  	} @@ -130,12 +154,8 @@ public class AltosCSV implements AltosWriter {  		return (int) series.value(AltosFlightSeries.status_name, indices);  	} -	void write_general() { -		double time = time(); -		out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d", -			   ALTOS_CSV_VERSION, series.cal_data().serial, -			   series.cal_data().flight, series.cal_data().callsign, -			   time, time, +	void write_radio() { +		out.printf("%4d, %3d",  			   rssi(), status() & 0x7f);  	} @@ -149,7 +169,7 @@ public class AltosCSV implements AltosWriter {  	void write_flight() {  		int state = state(); -		out.printf("%d,%8s", state, AltosLib.state_name(state)); +		out.printf("%2d,%8s", state, AltosLib.state_name(state));  	}  	void write_basic_header() { @@ -189,7 +209,7 @@ public class AltosCSV implements AltosWriter {  	}  	void write_advanced_header() { -		out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z"); +		out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z,tilt");  	}  	double accel_along() { return series.value(AltosFlightSeries.accel_along_name, indices); } @@ -204,11 +224,30 @@ public class AltosCSV implements AltosWriter {  	double mag_across() { return series.value(AltosFlightSeries.mag_across_name, indices); }  	double mag_through() { return series.value(AltosFlightSeries.mag_through_name, indices); } +	double tilt() { return series.value(AltosFlightSeries.orient_name, indices); } +  	void write_advanced() { -		out.printf("%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f", +		out.printf("%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f",  			   accel_along(), accel_across(), accel_through(),  			   gyro_roll(), gyro_pitch(), gyro_yaw(), -			   mag_along(), mag_across(), mag_through()); +			   mag_along(), mag_across(), mag_through(), +			   tilt()); +	} + +	void write_igniter_header() { +		out.printf("pyro"); +		for (int i = 0; i < series.igniter_voltage.length; i++) +			out.printf(",%s", AltosLib.igniter_short_name(i)); +	} + +	double pyro() { return series.value(AltosFlightSeries.pyro_voltage_name, indices); } + +	double igniter_value(int channel) { return series.value(series.igniter_voltage_name(channel), indices);	} + +	void write_igniter() { +		out.printf("%5.2f", pyro()); +		for (int i = 0; i < series.igniter_voltage.length; i++) +			out.printf(",%5.2f", igniter_value(i));  	}  	void write_gps_header() { @@ -306,6 +345,10 @@ public class AltosCSV implements AltosWriter {  	void write_header() {  		out.printf("#"); write_general_header(); +		if (has_radio) { +			out.printf(","); +			write_radio_header(); +		}  		if (has_flight_state) {  			out.printf(",");  			write_flight_header(); @@ -322,6 +365,10 @@ public class AltosCSV implements AltosWriter {  			out.printf(",");  			write_advanced_header();  		} +		if (has_igniter) { +			out.printf(","); +			write_igniter_header(); +		}  		if (has_gps) {  			out.printf(",");  			write_gps_header(); @@ -339,6 +386,10 @@ public class AltosCSV implements AltosWriter {  	void write_one() {  		write_general(); +		if (has_radio) { +			out.printf(","); +			write_radio(); +		}  		if (has_flight_state) {  			out.printf(",");  			write_flight(); @@ -355,6 +406,10 @@ public class AltosCSV implements AltosWriter {  			out.printf(",");  			write_advanced();  		} +		if (has_igniter) { +			out.printf(","); +			write_igniter(); +		}  		if (has_gps) {  			out.printf(",");  			write_gps(); @@ -395,14 +450,18 @@ public class AltosCSV implements AltosWriter {  		series.finish(); +		has_radio = false;  		has_flight_state = false;  		has_basic = false;  		has_battery = false;  		has_advanced = false; +		has_igniter = false;  		has_gps = false;  		has_gps_sat = false;  		has_companion = false; +		if (series.has_series(AltosFlightSeries.rssi_name)) +			has_radio = true;  		if (series.has_series(AltosFlightSeries.state_name))  			has_flight_state = true;  		if (series.has_series(AltosFlightSeries.accel_name) || series.has_series(AltosFlightSeries.pressure_name)) @@ -411,6 +470,8 @@ public class AltosCSV implements AltosWriter {  			has_battery = true;  		if (series.has_series(AltosFlightSeries.accel_across_name))  			has_advanced = true; +		if (series.has_series(AltosFlightSeries.pyro_voltage_name)) +			has_igniter = true;  		if (series.gps_series != null)  			has_gps = true; diff --git a/altoslib/AltosCalData.java b/altoslib/AltosCalData.java index 6258c1a8..03e2cbd7 100644 --- a/altoslib/AltosCalData.java +++ b/altoslib/AltosCalData.java @@ -72,6 +72,13 @@ public class AltosCalData {  		}  	} +	public int		log_format = AltosLib.MISSING; + +	public void set_log_format(int log_format) { +		if (log_format != AltosLib.MISSING) +			this.log_format = log_format; +	} +  	public int		config_major = AltosLib.MISSING;  	public int		config_minor = AltosLib.MISSING;  	public int		flight_log_max = AltosLib.MISSING; @@ -192,7 +199,6 @@ public class AltosCalData {  		tick = AltosLib.MISSING;  		prev_tick = AltosLib.MISSING;  		temp_gps = null; -		prev_gps = null;  		temp_gps_sat_tick = AltosLib.MISSING;  		accel = AltosLib.MISSING;  	} @@ -235,13 +241,19 @@ public class AltosCalData {  	public AltosGPS		gps_pad = null; +	public AltosGPS		prev_gps = null; +  	public double		gps_pad_altitude = AltosLib.MISSING; -	public void set_gps(AltosGPS gps) { -		if ((state != AltosLib.MISSING && state < AltosLib.ao_flight_boost) || gps_pad == null) -			gps_pad = gps; -		if (gps_pad_altitude == AltosLib.MISSING && gps.alt != AltosLib.MISSING) -			gps_pad_altitude = gps.alt; +	public void set_cal_gps(AltosGPS gps) { +		if (gps.locked && gps.nsat >= 4) { +			if ((state != AltosLib.MISSING && state < AltosLib.ao_flight_boost) || gps_pad == null) +				gps_pad = gps; +			if (gps_pad_altitude == AltosLib.MISSING && gps.alt != AltosLib.MISSING) +				gps_pad_altitude = gps.alt; +		} +		temp_gps = null; +		prev_gps = gps;  	}  	/* @@ -249,33 +261,24 @@ public class AltosCalData {  	 * object and then deliver the result atomically to the listener  	 */  	AltosGPS		temp_gps = null; -	AltosGPS		prev_gps = null;  	int			temp_gps_sat_tick = AltosLib.MISSING; -	public AltosGPS temp_gps() { +	public AltosGPS temp_cal_gps() {  		return temp_gps;  	} -	public void reset_temp_gps() { -		if (temp_gps != null) { -			if (temp_gps.locked && temp_gps.nsat >= 4) -				set_gps(temp_gps); -			prev_gps = temp_gps; -			temp_gps = null; -		} +	public void reset_temp_cal_gps() { +		if (temp_gps != null) +			set_cal_gps(temp_gps);  	} -	public boolean gps_pending() { +	public boolean cal_gps_pending() {  		return temp_gps != null;  	} -	public AltosGPS make_temp_gps(int tick, boolean sats) { -		if (temp_gps == null) { -			if (prev_gps != null) -				temp_gps = prev_gps.clone(); -			else -				temp_gps = new AltosGPS(); -		} +	public AltosGPS make_temp_cal_gps(int tick, boolean sats) { +		if (temp_gps == null) +			temp_gps = new AltosGPS(prev_gps);  		if (sats) {  			if (tick != temp_gps_sat_tick)  				temp_gps.cc_gps_sat = null; diff --git a/altoslib/AltosDataListener.java b/altoslib/AltosDataListener.java index be6d840f..9a1e1465 100644 --- a/altoslib/AltosDataListener.java +++ b/altoslib/AltosDataListener.java @@ -19,10 +19,16 @@ public abstract class AltosDataListener {  	private AltosCalData	cal_data = null;  	public double		time = AltosLib.MISSING; -	public int		state = AltosLib.MISSING;  	public double		frequency = AltosLib.MISSING; +	public int		raw_tick = AltosLib.MISSING; + +	public int tick() { +		return raw_tick; +	} +  	public void set_tick(int tick) { +		raw_tick = tick;  		cal_data.set_tick(tick);  		set_time(cal_data.time());  	} @@ -42,14 +48,34 @@ public abstract class AltosDataListener {  		cal_data().set_serial(serial);  	} +	public void set_device_type(int device_type) { +		cal_data().set_device_type(device_type); +		switch (device_type) { +		case AltosLib.product_telegps: +			set_state(AltosLib.ao_flight_stateless); +			break; +		} +	} + +	public void set_log_format(int log_format) { +		cal_data().set_log_format(log_format); +		switch (log_format) { +		case AltosLib.AO_LOG_FORMAT_TELEGPS: +			set_state(AltosLib.ao_flight_stateless); +			break; +		} +	} +  	public double time() {  		return time;  	}  	public void set_state(int state) {  		cal_data().set_state(state); -		if (state != AltosLib.MISSING) -			this.state = state; +	} + +	public int state() { +		return cal_data().state;  	}  	public void set_flight(int flight) { @@ -64,6 +90,12 @@ public abstract class AltosDataListener {  	public void finish() {  	} +	public void init() { +		set_state(AltosLib.ao_flight_invalid); +		time = AltosLib.MISSING; +		frequency = AltosLib.MISSING; +	} +  	public abstract void set_rssi(int rssi, int status);  	public abstract void set_received_time(long received_time); @@ -79,7 +111,18 @@ public abstract class AltosDataListener {  	public abstract void set_apogee_voltage(double volts);  	public abstract void set_main_voltage(double volts); -	public abstract void set_gps(AltosGPS gps); +	public void set_gps(AltosGPS gps) { +		AltosCalData cal_data = cal_data(); +		cal_data.set_cal_gps(gps); +	} + +	public AltosGPS make_temp_gps(boolean sats) { +		return cal_data().make_temp_cal_gps(tick(), sats); +	} + +	public AltosGPS temp_gps() { +		return cal_data().temp_cal_gps(); +	}  	public abstract void set_orient(double orient);  	public abstract void set_gyro(double roll, double pitch, double yaw); diff --git a/altoslib/AltosEeprom.java b/altoslib/AltosEeprom.java index ad7bf881..124bd478 100644 --- a/altoslib/AltosEeprom.java +++ b/altoslib/AltosEeprom.java @@ -22,6 +22,7 @@ public class AltosEeprom {  	private AltosJson	config;  	ArrayList<Byte>		data;  	private AltosConfigData	config_data; +	int			errors = 0;  	/*  	 * Public accessor APIs diff --git a/altoslib/AltosEepromDownload.java b/altoslib/AltosEepromDownload.java index 33f0dd17..547b523f 100644 --- a/altoslib/AltosEepromDownload.java +++ b/altoslib/AltosEepromDownload.java @@ -40,6 +40,7 @@ class AltosEepromNameData extends AltosDataListener {  	public void set_main_voltage(double volts) { }  	public void set_gps(AltosGPS gps) { +		super.set_gps(gps);  		if (gps != null &&  		    gps.year != AltosLib.MISSING &&  		    gps.month != AltosLib.MISSING && @@ -199,25 +200,47 @@ public class AltosEepromDownload implements Runnable {  		AltosFile f = MakeFile(flights.config_data.serial, log.flight, name_data); -		monitor.set_filename(f.toString()); +		log.set_file(f); -		FileWriter w = new FileWriter(f); +		boolean do_write = true; -		eeprom.write(w); -		w.close(); +		if (f.exists()) +			do_write = monitor.check_overwrite(f); + +		if (do_write) { +			FileWriter w = new FileWriter(f); + +			eeprom.write(w); +			w.close(); +		} + +		if (eeprom.errors != 0) +			throw new ParseException(String.format("%d CRC Errors", eeprom.errors), 0); +	} + +	static String label(int flight) { +		if (flight < 0) +			return "Corrupt"; +		else +			return "Flight"; +	} + +	static int flight(int flight) { +		if (flight < 0) +			return -flight; +		return flight;  	}  	public void run () {  		boolean success = false;  		try { -			boolean	failed = false;  			if (remote)  				link.start_remote();  			for (AltosEepromLog log : flights) {  				parse_errors = null; -				if (log.selected) { +				if (log.download_selected) {  					monitor.reset();  					try {  						CaptureLog(log); @@ -225,16 +248,16 @@ public class AltosEepromDownload implements Runnable {  						LogError(e.getMessage());  					}  				} +				success = true;  				if (parse_errors != null) { -					failed = true; -					monitor.show_message(String.format("Flight %d download error. Valid log data saved\n%s", -									   log.flight, +					monitor.show_message(String.format("%s %d download error. Valid log data saved\n%s", +									   label(log.flight), +									   flight(log.flight),  									   parse_errors),  							     link.name,  							     AltosEepromMonitor.WARNING_MESSAGE);  				}  			} -			success = !failed;  		} catch (IOException ee) {  			monitor.show_message(ee.getLocalizedMessage(),  					     link.name, diff --git a/altoslib/AltosEepromList.java b/altoslib/AltosEepromList.java index 55d47e20..c55bcaaa 100644 --- a/altoslib/AltosEepromList.java +++ b/altoslib/AltosEepromList.java @@ -87,7 +87,7 @@ public class AltosEepromList extends ArrayList<AltosEepromLog> {  							start = AltosParse.parse_hex(tokens[3]);  						if (tokens[4].equals("end"))  							end = AltosParse.parse_hex(tokens[5]); -						if (flight > 0 && start >= 0 && end > 0) +						if (flight != 0 && start >= 0 && end > 0)  							flights.add(new AltosEepromFlight(flight, start, end));  					} catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); }  				} @@ -115,4 +115,4 @@ public class AltosEepromList extends ArrayList<AltosEepromLog> {  			link.flush_output();  		}  	} -}
\ No newline at end of file +} diff --git a/altoslib/AltosEepromLog.java b/altoslib/AltosEepromLog.java index 8d1f3fc4..ba722b89 100644 --- a/altoslib/AltosEepromLog.java +++ b/altoslib/AltosEepromLog.java @@ -18,6 +18,7 @@  package org.altusmetrum.altoslib_12; +import java.io.*;  import java.text.*;  import java.util.concurrent.*; @@ -32,7 +33,15 @@ public class AltosEepromLog {  	public int		start_block;  	public int		end_block; -	public boolean		selected; +	public boolean		download_selected; +	public boolean		delete_selected; +	public boolean		graph_selected; + +	public File		file; + +	public void set_file(File file) { +		this.file = file; +	}  	public AltosEepromLog(AltosConfigData config_data,  			      AltosLink link, @@ -50,8 +59,11 @@ public class AltosEepromLog {  		serial = config_data.serial;  		/* -		 * Select all flights for download +		 * Select all flights for download and graph, but not +		 * for delete  		 */ -		selected = true; +		download_selected = true; +		delete_selected = false; +		graph_selected = true;  	}  } diff --git a/altoslib/AltosEepromMonitor.java b/altoslib/AltosEepromMonitor.java index a99ec687..11144a3a 100644 --- a/altoslib/AltosEepromMonitor.java +++ b/altoslib/AltosEepromMonitor.java @@ -18,6 +18,8 @@  package org.altusmetrum.altoslib_12; +import java.io.*; +  public interface AltosEepromMonitor {  	public void set_block(int in_block); @@ -28,8 +30,6 @@ public interface AltosEepromMonitor {  	public void set_flight(int in_flight); -	public void set_filename(String in_file); -  	public void set_thread(Thread eeprom_thread);  	final static int INFO_MESSAGE = 0; @@ -38,6 +38,8 @@ public interface AltosEepromMonitor {  	public void show_message(String message, String title, int message_type); +	public Boolean check_overwrite(File file); +  	public void start();  	public void done(boolean success); diff --git a/altoslib/AltosEepromRecord.java b/altoslib/AltosEepromRecord.java index 094584fe..43e8ea4d 100644 --- a/altoslib/AltosEepromRecord.java +++ b/altoslib/AltosEepromRecord.java @@ -50,8 +50,22 @@ public abstract class AltosEepromRecord implements Comparable<AltosEepromRecord>  		return data8(i) | (data8(i+1) << 8) | (data8(i+2) << 16) | (data8(i+3) << 24);  	} +	public boolean empty(int s) { +		for (int i = 0; i < length; i++) +			if (eeprom.data8(s + i) != 0xff) +				return false; +		return true; +	} +  	public boolean valid(int s) { -		return AltosConvert.checksum(eeprom.data, s, length) == 0; +		int	ck = AltosConvert.checksum(eeprom.data, s, length); + +		if (ck != 0) { +			++eeprom.errors; +			System.out.printf("invalid checksum 0x%x at 0x%x\n", ck, s); +			return false; +		} +		return true;  	}  	public boolean valid() { @@ -83,18 +97,16 @@ public abstract class AltosEepromRecord implements Comparable<AltosEepromRecord>  	/* AltosDataProvider */  	public void provide_data(AltosDataListener listener, AltosCalData cal_data) { -		cal_data.set_tick(tick()); +		listener.set_tick(tick());  		if (cmd() == AltosLib.AO_LOG_FLIGHT)  			cal_data.set_boost_tick();  		listener.set_time(cal_data.time());  		/* Flush any pending GPS changes */  		if (!AltosLib.is_gps_cmd(cmd())) { -			AltosGPS gps = cal_data.temp_gps(); -			if (gps != null) { +			AltosGPS gps = listener.temp_gps(); +			if (gps != null)  				listener.set_gps(gps); -				cal_data.reset_temp_gps(); -			}  		}  	} @@ -102,25 +114,18 @@ public abstract class AltosEepromRecord implements Comparable<AltosEepromRecord>  		int	s = start + length;  		while (s + length <= eeprom.data.size()) { -			if (valid(s)) +			if (!empty(s) && valid(s))  				return s;  			s += length;  		}  		return -1;  	} -	public boolean hasNext() { -		return next_start() >= 0; -	} -  	public abstract AltosEepromRecord next();  	public AltosEepromRecord(AltosEeprom eeprom, int start, int length) {  		this.eeprom = eeprom;  		this.start = start;  		this.length = length; - -		while (start + length < eeprom.data.size() && !valid()) -			start += length;  	}  } diff --git a/altoslib/AltosEepromRecordFull.java b/altoslib/AltosEepromRecordFull.java index 32df9578..7e92d353 100644 --- a/altoslib/AltosEepromRecordFull.java +++ b/altoslib/AltosEepromRecordFull.java @@ -53,7 +53,7 @@ public class AltosEepromRecordFull extends AltosEepromRecord {  			listener.set_state(data16(0));  			break;  		case AltosLib.AO_LOG_GPS_TIME: -			gps = cal_data.make_temp_gps(tick(),false); +			gps = listener.make_temp_gps(false);  			gps.hour = data8(0);  			gps.minute = data8(1); @@ -67,29 +67,29 @@ public class AltosEepromRecordFull extends AltosEepromRecord {  				AltosLib.AO_GPS_NUM_SAT_SHIFT;  			break;  		case AltosLib.AO_LOG_GPS_LAT: -			gps = cal_data.make_temp_gps(tick(),false); +			gps = listener.make_temp_gps(false);  			int lat32 = data32(0);  			gps.lat = (double) lat32 / 1e7;  			break;  		case AltosLib.AO_LOG_GPS_LON: -			gps = cal_data.make_temp_gps(tick(),false); +			gps = listener.make_temp_gps(false);  			int lon32 = data32(0);  			gps.lon = (double) lon32 / 1e7;  			break;  		case AltosLib.AO_LOG_GPS_ALT: -			gps = cal_data.make_temp_gps(tick(),false); +			gps = listener.make_temp_gps(false);  			gps.alt = data16(0);  			break;  		case AltosLib.AO_LOG_GPS_SAT: -			gps = cal_data.make_temp_gps(tick(),true); +			gps = listener.make_temp_gps(true);  			int svid = data16(0);  			int c_n0 = data16(2);  			gps.add_sat(svid, c_n0);  			break;  		case AltosLib.AO_LOG_GPS_DATE: -			gps = cal_data.make_temp_gps(tick(),false); +			gps = listener.make_temp_gps(false);  			gps.year = data8(0) + 2000;  			gps.month = data8(1);  			gps.day = data8(2); diff --git a/altoslib/AltosEepromRecordMega.java b/altoslib/AltosEepromRecordMega.java index ad3e23fd..86343fe0 100644 --- a/altoslib/AltosEepromRecordMega.java +++ b/altoslib/AltosEepromRecordMega.java @@ -31,6 +31,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {  	private int ground_roll() {  		switch (log_format) {  		case AltosLib.AO_LOG_FORMAT_TELEMEGA: +		case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:  			return data32(16);  		case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:  			return data16(14); @@ -41,6 +42,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {  	private int ground_pitch() {  		switch (log_format) {  		case AltosLib.AO_LOG_FORMAT_TELEMEGA: +		case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:  			return data32(20);  		case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:  			return data16(16); @@ -51,6 +53,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {  	private int ground_yaw() {  		switch (log_format) {  		case AltosLib.AO_LOG_FORMAT_TELEMEGA: +		case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:  			return data32(24);  		case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:  			return data16(18); @@ -188,7 +191,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {  			listener.set_pyro_fired(pyro());  			break;  		case AltosLib.AO_LOG_GPS_TIME: -			gps = cal_data.make_temp_gps(tick(), false); +			gps = listener.make_temp_gps(false);  			gps.lat = latitude() / 1e7;  			gps.lon = longitude() / 1e7; @@ -231,7 +234,7 @@ public class AltosEepromRecordMega extends AltosEepromRecord {  			}  			break;  		case AltosLib.AO_LOG_GPS_SAT: -			gps = cal_data.make_temp_gps(tick(), true); +			gps = listener.make_temp_gps(true);  			int n = nsat();  			if (n > max_sat) diff --git a/altoslib/AltosEepromRecordMetrum.java b/altoslib/AltosEepromRecordMetrum.java index 3da50544..888a06cc 100644 --- a/altoslib/AltosEepromRecordMetrum.java +++ b/altoslib/AltosEepromRecordMetrum.java @@ -91,7 +91,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord {  			listener.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m()));  			break;  		case AltosLib.AO_LOG_GPS_POS: -			gps = cal_data.make_temp_gps(tick(), false); +			gps = listener.make_temp_gps(false);  			gps.lat = latitude() / 1e7;  			gps.lon = longitude() / 1e7;  			if (config_data().altitude_32()) @@ -100,7 +100,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord {  				gps.alt = altitude_low();  			break;  		case AltosLib.AO_LOG_GPS_TIME: -			gps = cal_data.make_temp_gps(tick(), false); +			gps = listener.make_temp_gps(false);  			gps.hour = hour();  			gps.minute = minute(); @@ -119,7 +119,7 @@ public class AltosEepromRecordMetrum extends AltosEepromRecord {  			gps.pdop = pdop() / 10.0;  			break;  		case AltosLib.AO_LOG_GPS_SAT: -			gps = cal_data.make_temp_gps(tick(), true); +			gps = listener.make_temp_gps(true);  			int n = nsat();  			for (int i = 0; i < n; i++) diff --git a/altoslib/AltosEepromRecordSet.java b/altoslib/AltosEepromRecordSet.java index 48e90c05..36075931 100644 --- a/altoslib/AltosEepromRecordSet.java +++ b/altoslib/AltosEepromRecordSet.java @@ -44,6 +44,8 @@ public class AltosEepromRecordSet implements AltosRecordSet {  		AltosCalData	cal_data = cal_data();  		cal_data.reset(); +		listener.set_log_format(config_data().log_format); +  		for (AltosEepromRecord record : ordered) {  			record.provide_data(listener, cal_data);  		} @@ -67,6 +69,7 @@ public class AltosEepromRecordSet implements AltosRecordSet {  		case AltosLib.AO_LOG_FORMAT_TELEMETRY:  		case AltosLib.AO_LOG_FORMAT_TELESCIENCE:  		case AltosLib.AO_LOG_FORMAT_TELEMEGA: +		case AltosLib.AO_LOG_FORMAT_TELEMEGA_3:  		case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:  			record = new AltosEepromRecordMega(eeprom);  			break; @@ -95,7 +98,7 @@ public class AltosEepromRecordSet implements AltosRecordSet {  		int	tick = 0;  		boolean first = true; -		for (;;) { +		do {  			int	t = record.tick();  			if (first) { @@ -108,10 +111,8 @@ public class AltosEepromRecordSet implements AltosRecordSet {  			}  			record.wide_tick = tick;  			ordered.add(record); -			if (!record.hasNext()) -				break;  			record = record.next(); -		} +		} while (record != null);  	}  	public AltosEepromRecordSet(InputStream input) throws IOException { diff --git a/altoslib/AltosFile.java b/altoslib/AltosFile.java index 69f779c1..6f98b87a 100644 --- a/altoslib/AltosFile.java +++ b/altoslib/AltosFile.java @@ -36,10 +36,23 @@ public class AltosFile extends File {  		return String.format("-via-%04d", receiver);  	} +	static private String label(int flight) { +		if (flight < 0) +			return "corrupt"; +		else +			return "flight"; +	} + +	static private int flight(int flight) { +		if (flight < 0) +			return -flight; +		return flight; +	} +  	public AltosFile(int year, int month, int day, int serial, int flight, int receiver, String extension) {  		super (AltosPreferences.logdir(), -		       String.format("%04d-%02d-%02d-serial-%s-flight-%s%s.%s", -				     year, month, day, number(serial), number(flight), receiver(receiver), extension)); +		       String.format("%04d-%02d-%02d-serial-%s-%s-%s%s.%s", +				     year, month, day, number(serial), label(flight), number(flight(flight)), receiver(receiver), extension));  	}  	public AltosFile(int year, int month, int day, int serial, int flight, String extension) { diff --git a/altoslib/AltosFilterListener.java b/altoslib/AltosFilterListener.java new file mode 100644 index 00000000..fe91100a --- /dev/null +++ b/altoslib/AltosFilterListener.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package org.altusmetrum.altoslib_12; + +public interface AltosFilterListener { +	void filter_changed(double speed_filter, double accel_filter); + +	double speed_filter(); +	double accel_filter(); +} diff --git a/altoslib/AltosFlightListener.java b/altoslib/AltosFlightListener.java deleted file mode 100644 index d61831a9..00000000 --- a/altoslib/AltosFlightListener.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - */ - -package org.altusmetrum.altoslib_12; - -public abstract class AltosFlightListener { - -	public int	flight; -	public int	serial; -	public int	tick; -	public int	boost_tick; -	public int	state; - -	public double	accel_plus_g; -	public double	accel_minus_g; -	public double	accel; - -	public double	ground_pressure; -	public double	ground_altitude; - -	AltosGPS	temp_gps; -	int		temp_gps_sat_tick; -	int		gps_sequence; - -	/* AltosEepromRecord */ -	public void set_boost_tick(int boost_tick) { -		if (boost_tick != AltosLib.MISSING) -			this.boost_tick = boost_tick; -	} - -	public void set_tick(int tick) { -		if (tick != AltosLib.MISSING) -			this.tick = tick; -	} - -	public double time() { -		if (tick == AltosLib.MISSING) -			return AltosLib.MISSING; -		if (boost_tick != AltosLib.MISSING) -			return (tick - boost_tick) / 100.0; -		else -			return tick / 100.0; -	} - -	public double boost_time() { -		if (boost_tick == AltosLib.MISSING) -			return AltosLib.MISSING; -		return boost_tick / 100.0; -	} - -	public abstract void set_rssi(int rssi, int status); -	public abstract void set_received_time(long received_time); - -	/* AltosEepromRecordFull */ - -	public void set_serial(int serial) { -		if (serial != AltosLib.MISSING) -			this.serial = serial; -	} - -	public void set_state(int state) { -		if (state != AltosLib.MISSING) -			this.state = state; -	} - -	public int state() { return state; } - -	public abstract void set_ground_accel(double ground_accel); -	public void set_flight(int flight) { -		if (flight != AltosLib.MISSING) -			this.flight = flight; -	} -	public int flight() { -		return flight; -	} - -	public abstract void set_accel(double accel); -	public abstract void set_acceleration(double accel); -	public abstract void set_accel_g(double accel_plus_g, double accel_minus_g); -	public abstract void set_pressure(double pa); -	public abstract void set_thrust(double N); - -	public abstract void set_temperature(double deg_c); -	public abstract void set_battery_voltage(double volts); - -	public abstract void set_apogee_voltage(double volts); -	public abstract void set_main_voltage(double volts); - -	public void set_temp_gps() { -		temp_gps = null; -	} - -	public boolean gps_pending() { -		return temp_gps != null; -	} - -	public AltosGPS make_temp_gps(boolean sats) { -		if (temp_gps == null) { -			temp_gps = new AltosGPS(); -		} -		if (sats) { -			if (tick != temp_gps_sat_tick) -				temp_gps.cc_gps_sat = null; -			temp_gps_sat_tick = tick; -		} -		return temp_gps; -	} - -	public void set_ground_pressure(double ground_pressure) { -		if (ground_pressure != AltosLib.MISSING) { -			this.ground_pressure = ground_pressure; -			this.ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure); -		} -	} - -	public abstract void set_accel_ground(double along, double across, double through); -	public abstract void set_gyro_zero(double roll, double pitch, double yaw); -	public abstract void check_imu_wrap(AltosIMU imu); -	public abstract void set_imu(AltosIMU imu); -	public abstract void set_mag(AltosMag mag); -	public abstract void set_pyro_voltage(double volts); -	public abstract void set_igniter_voltage(double[] voltage); -	public abstract void set_pyro_fired(int pyro_mask); - -	public void copy(AltosFlightListener old) { -		flight = old.flight; -		serial = old.serial; -		tick = old.tick; -		boost_tick = old.boost_tick; -		accel_plus_g = old.accel_plus_g; -		accel_minus_g = old.accel_minus_g; -		ground_pressure = old.ground_pressure; -		ground_altitude = old.ground_altitude; -		temp_gps = old.temp_gps; -		temp_gps_sat_tick = old.temp_gps_sat_tick; -	} - -	public void init() { -		flight = AltosLib.MISSING; -		serial = AltosLib.MISSING; -		tick = AltosLib.MISSING; -		boost_tick = AltosLib.MISSING; -		accel_plus_g = AltosLib.MISSING; -		accel_minus_g = AltosLib.MISSING; -		accel = AltosLib.MISSING; -		ground_pressure = AltosLib.MISSING; -		ground_altitude = AltosLib.MISSING; -		temp_gps = null; -		temp_gps_sat_tick = AltosLib.MISSING; -	} -} diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index 57f1a491..d130d3ad 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -21,7 +21,7 @@ public class AltosFlightSeries extends AltosDataListener {  	public ArrayList<AltosTimeSeries> series = new ArrayList<AltosTimeSeries>();  	public double	speed_filter_width = 4.0; -	public double	accel_filter_width = 4.0; +	public double	accel_filter_width = 1.0;  	public int[] indices() {  		int[] indices = new int[series.size()]; @@ -150,18 +150,17 @@ public class AltosFlightSeries extends AltosDataListener {  	public void set_state(int state) { -		if (state == AltosLib.ao_flight_pad) -			return; - -		if (state_series == null) -			state_series = add_series(state_name, AltosConvert.state_name); -		else if (this.state == state) -			return; -		this.state = state; -		state_series.add(time(), state); +		if (state != AltosLib.ao_flight_pad && state != AltosLib.MISSING && state != AltosLib.ao_flight_stateless) { +			if (state_series == null) +				state_series = add_series(state_name, AltosConvert.state_name); +			if (this.state() != state) +				state_series.add(time(), state); +		} +		super.set_state(state);  	}  	public AltosTimeSeries	accel_series; +	public boolean		accel_computed;  	public static final String accel_name = "Accel"; @@ -176,23 +175,61 @@ public class AltosFlightSeries extends AltosDataListener {  			accel_series = add_series(accel_name, AltosConvert.accel);  		accel_series.add(time(), acceleration); +		accel_computed = false;  	} -	private void compute_accel() { -		if (accel_series != null) -			return; +	private AltosTimeSeries compute_accel() { +		AltosTimeSeries	new_accel_series = null;  		if (speed_series != null) { -			AltosTimeSeries temp_series = make_series(speed_name, AltosConvert.speed); -			speed_series.filter(temp_series, accel_filter_width); -			accel_series = add_series(accel_name, AltosConvert.accel); -			temp_series.differentiate(accel_series); +			AltosTimeSeries temp_series; +			if (accel_filter_width > 0) { +				temp_series = make_series(speed_name, AltosConvert.speed); +				speed_series.filter(temp_series, accel_filter_width); +			} else +				temp_series = speed_series; + +			new_accel_series = make_series(accel_name, AltosConvert.accel); +			temp_series.differentiate(new_accel_series); +		} +		return new_accel_series; +	} + +	public void set_filter(double speed_filter, double accel_filter) { +		this.speed_filter_width = speed_filter; +		this.accel_filter_width = accel_filter; + +		AltosTimeSeries new_speed_series = compute_speed(); + +		if (new_speed_series != null) { +			speed_series.erase_values(); +			for (AltosTimeValue tv : new_speed_series) +				speed_series.add(tv); +		} +		if (accel_computed) { +			AltosTimeSeries new_accel_series = compute_accel(); +			if (new_accel_series != null) { +				accel_series.erase_values(); +				for (AltosTimeValue tv : new_accel_series) +					accel_series.add(tv); +			}  		}  	}  	public void set_received_time(long received_time) {  	} +	public AltosTimeSeries tick_series; + +	public static final String tick_name = "Tick"; + +	public void set_tick(int tick) { +		super.set_tick(tick); +		if (tick_series == null) +			tick_series = add_series(tick_name, null); +		tick_series.add(time(), tick); +	} +  	public AltosTimeSeries rssi_series;  	public static final String rssi_name = "RSSI"; @@ -259,21 +296,24 @@ public class AltosFlightSeries extends AltosDataListener {  	public static final String speed_name = "Speed"; -	private void compute_speed() { -		if (speed_series != null) -			return; - +	private AltosTimeSeries compute_speed() { +		AltosTimeSeries new_speed_series = null;  		AltosTimeSeries	alt_speed_series = null;  		AltosTimeSeries accel_speed_series = null;  		if (altitude_series != null) { -			AltosTimeSeries temp_series = make_series(altitude_name, AltosConvert.height); -			altitude_series.filter(temp_series, speed_filter_width); +			AltosTimeSeries temp_series; + +			if (speed_filter_width > 0) { +				temp_series = make_series(speed_name, AltosConvert.height); +				altitude_series.filter(temp_series, speed_filter_width); +			} else +				temp_series = altitude_series;  			alt_speed_series = make_series(speed_name, AltosConvert.speed);  			temp_series.differentiate(alt_speed_series);  		} -		if (accel_series != null) { +		if (accel_series != null && !accel_computed) {  			if (orient_series != null) {  				vert_accel_series = add_series(vert_accel_name, AltosConvert.accel); @@ -309,26 +349,25 @@ public class AltosFlightSeries extends AltosDataListener {  				}  			}  			if (apogee_time == AltosLib.MISSING) { -				speed_series = alt_speed_series; +				new_speed_series = alt_speed_series;  			} else { -				speed_series = make_series(speed_name, AltosConvert.speed); +				new_speed_series = make_series(speed_name, AltosConvert.speed);  				for (AltosTimeValue d : accel_speed_series) {  					if (d.time <= apogee_time) -						speed_series.add(d); +						new_speed_series.add(d);  				}  				for (AltosTimeValue d : alt_speed_series) {  					if (d.time > apogee_time) -						speed_series.add(d); +						new_speed_series.add(d);  				}  			}  		} else if (alt_speed_series != null) { -			speed_series = alt_speed_series; +			new_speed_series = alt_speed_series;  		} else if (accel_speed_series != null) { -			speed_series = accel_speed_series; +			new_speed_series = accel_speed_series;  		} -		if (speed_series != null) -			add_series(speed_series); +		return new_speed_series;  	}  	public AltosTimeSeries orient_series; @@ -450,13 +489,24 @@ public class AltosFlightSeries extends AltosDataListener {  	public ArrayList<AltosGPSTimeValue> gps_series;  	public AltosGPS gps_before(double time) { -		AltosGPS gps = null; -		for (AltosGPSTimeValue gtv : gps_series) -			if (gtv.time <= time) -				gps = gtv.gps; -			else -				break; -		return gps; +		AltosGPSTimeValue nearest = null; +		for (AltosGPSTimeValue gtv : gps_series) { +			if (nearest == null) +				nearest = gtv; +			else { +				if (gtv.time <= time) { +					if (nearest.time <= time && gtv.time > nearest.time) +						nearest = gtv; +				} else { +					if (nearest.time > time && gtv.time < nearest.time) +						nearest = gtv; +				} +			} +		} +		if (nearest != null) +			return nearest.gps; +		else +			return null;  	}  	public AltosTimeSeries	sats_in_view; @@ -482,6 +532,7 @@ public class AltosFlightSeries extends AltosDataListener {  	public static final String gps_hdop_name = "GPS Horizontal Dilution of Precision";  	public void set_gps(AltosGPS gps) { +		super.set_gps(gps);  		if (gps_series == null)  			gps_series = new ArrayList<AltosGPSTimeValue>();  		gps_series.add(new AltosGPSTimeValue(time(), gps)); @@ -643,7 +694,7 @@ public class AltosFlightSeries extends AltosDataListener {  	public  void set_igniter_voltage(double[] voltage) {  		int channels = voltage.length;  		if (igniter_voltage == null || igniter_voltage.length <= channels) { -			AltosTimeSeries[]	new_igniter_voltage = new AltosTimeSeries[channels + 1]; +			AltosTimeSeries[]	new_igniter_voltage = new AltosTimeSeries[channels];  			int			i = 0;  			if (igniter_voltage != null) { @@ -681,8 +732,18 @@ public class AltosFlightSeries extends AltosDataListener {  	public void finish() {  		compute_orient(); -		compute_speed(); -		compute_accel(); +		if (speed_series == null) { +			speed_series = compute_speed(); +			if (speed_series != null) +				add_series(speed_series); +		} +		if (accel_series == null) { +			accel_series = compute_accel(); +			if (accel_series != null) { +				add_series(accel_series); +				accel_computed = true; +			} +		}  		compute_height();  	} diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java index ea1a9675..6bb83581 100644 --- a/altoslib/AltosFlightStats.java +++ b/altoslib/AltosFlightStats.java @@ -27,6 +27,8 @@ public class AltosFlightStats {  	public double		max_acceleration;  	public double[]		state_speed = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_enter_speed = new double[AltosLib.ao_flight_invalid + 1]; +	public double[]		state_enter_height = new double[AltosLib.ao_flight_invalid + 1]; +	public double[]		state_enter_gps_height = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_accel = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_time = new double[AltosLib.ao_flight_invalid + 1];  	public String		product; @@ -134,6 +136,11 @@ public class AltosFlightStats {  		if (0 <= state && state <= AltosLib.ao_flight_invalid && delta_time > 0) {  			if (state_enter_speed[state] == AltosLib.MISSING)  				state_enter_speed[state] = series.speed_series.value(start_time); +			if (state_enter_height[state] == AltosLib.MISSING) +				state_enter_height[state] = series.height_series.value(start_time); +			if (state_enter_gps_height[state] == AltosLib.MISSING) +				if (series.gps_height != null) +					state_enter_gps_height[state] = series.gps_height.value(start_time);  			speeds[state].value += series.speed_series.average(start_time, end_time) * delta_time;  			speeds[state].time += delta_time;  			accels[state].value += series.accel_series.average(start_time, end_time) * delta_time; diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index dee28a92..ba6f1a82 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -83,9 +83,9 @@ public class AltosIMU implements Cloneable {  				listener.set_gyro(cal_data.gyro_roll(imu.gyro_y),  						  cal_data.gyro_pitch(imu.gyro_x),  						  cal_data.gyro_yaw(imu.gyro_z)); -				listener.set_accel_ground(cal_data.accel_along(imu.accel_y), -							  cal_data.accel_across(imu.accel_x), -							  cal_data.accel_through(imu.accel_z)); +				listener.set_accel_ground(imu.accel_y, +							  imu.accel_x, +							  imu.accel_z);  			}  		} catch (TimeoutException te) {  		} diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index fc5d4cc8..834d9aa5 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -33,6 +33,7 @@ public class AltosIdleMonitor extends Thread {  	double			frequency;  	String			callsign; +	AltosState		state;  	AltosListenerState	listener_state;  	AltosConfigData		config_data;  	AltosGPS		gps; @@ -52,20 +53,23 @@ public class AltosIdleMonitor extends Thread {  		return link.reply_abort;  	} -	boolean provide_data(AltosDataListener listener) throws InterruptedException, TimeoutException, AltosUnknownProduct { +	boolean provide_data() throws InterruptedException, TimeoutException, AltosUnknownProduct {  		boolean		worked = false;  		boolean		aborted = false;  		try {  			start_link(); -			fetch.provide_data(listener); +			link.config_data(); +			if (state == null) +				state = new AltosState(new AltosCalData(link.config_data())); +			fetch.provide_data(state);  			if (!link.has_error && !link.reply_abort)  				worked = true;  		} finally {  			aborted = stop_link();  			if (worked) {  				if (remote) -					listener.set_rssi(link.rssi(), 0); +					state.set_rssi(link.rssi(), 0);  				listener_state.battery = link.monitor_battery();  			}  		} @@ -92,14 +96,11 @@ public class AltosIdleMonitor extends Thread {  	}  	public void run() { -		AltosState state = null; +		state = null;  		try {  			for (;;) {  				try { -					link.config_data(); -					if (state == null) -						state = new AltosState(new AltosCalData(link.config_data())); -					provide_data(state); +					provide_data();  					listener.update(state, listener_state);  				} catch (TimeoutException te) {  				} catch (AltosUnknownProduct ae) { diff --git a/altoslib/AltosKML.java b/altoslib/AltosKML.java index 587b845b..d5248a17 100644 --- a/altoslib/AltosKML.java +++ b/altoslib/AltosKML.java @@ -38,16 +38,18 @@ public class AltosKML implements AltosWriter {  	int			flight_state = -1;  	AltosGPS		prev = null;  	double			gps_start_altitude = AltosLib.MISSING; +	AltosFlightSeries	series;  	AltosFlightStats	stats; +	AltosCalData		cal_data;  	static final String[] kml_state_colors = {  		"FF000000",	// startup  		"FF000000",	// idle  		"FF000000",	// pad  		"FF0000FF",	// boost +		"FF8040FF",	// coast  		"FF4080FF",	// fast -		"FF00FFFF",	// coast -		"FFFF0000",	// drogue +		"FF00FFFF",	// drogue  		"FF00FF00",	// main  		"FF000000",	// landed  		"FFFFFFFF",	// invalid @@ -60,85 +62,169 @@ public class AltosKML implements AltosWriter {  		return kml_state_colors[state];  	} +	static final String[] kml_style_colors = { +		"FF0000FF",	// baro +		"FFFF0000",	// gps +	}; + +	static String style_color(int style) { +		if (style < 0 || kml_style_colors.length <= style) +			return kml_style_colors[0]; +		return kml_style_colors[style]; +	} +  	static final String kml_header_start =  		"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +  		"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +  		"<Document>\n" +  		"  <name>AO Flight#%d S/N: %03d</name>\n" + -		"  <description>\n"; +		"  <Snippet maxLines=\"8\">\n"; +  	static final String kml_header_end = -		"  </description>\n" + -		"  <open>0</open>\n"; - -	static final String kml_style_start = -		"  <Style id=\"ao-flightstate-%s\">\n" + -		"    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" + -		"    <BalloonStyle>\n" + -		"      <text>\n"; - -	static final String kml_style_end = -		"      </text>\n" + -		"    </BalloonStyle>\n" + -		"  </Style>\n"; - -	static final String kml_placemark_start = -		"  <Placemark>\n" + -		"    <name>%s</name>\n" + -		"    <styleUrl>#ao-flightstate-%s</styleUrl>\n" + -		"    <LineString>\n" + -		"      <tessellate>1</tessellate>\n" + -		"      <altitudeMode>absolute</altitudeMode>\n" + -		"      <coordinates>\n"; +		"  </Snippet>\n" + +		"  <open>1</open>\n"; + +	static final String kml_folder_start = +		"  <Folder>\n" + +		"    <name>%s</name>\n"; + +	static final String kml_path_style_start = +		"    <Style id=\"ao-style-%s\">\n" + +		"      <LineStyle><color>%s</color><width>8</width></LineStyle>\n" + +		"      <BalloonStyle>\n" + +		"        <text>\n"; + +	static final String kml_path_style_end = +		"        </text>\n" + +		"      </BalloonStyle>\n" + +		"    </Style>\n"; + +	static final String kml_point_style_start = +		"    <Style id=\"ao-style-%s\">\n" + +		"      <LabelStyle><color>%s</color></LabelStyle>\n" + +		"      <IconStyle><color>%s</color></IconStyle>\n" + +		"      <BalloonStyle>\n" + +		"        <text>\n"; + +	static final String kml_point_style_end = +		"        </text>\n" + +		"      </BalloonStyle>\n" + +		"    </Style>\n"; + +	static final String kml_path_start = +		"    <Placemark>\n" + +		"      <name>%s</name>\n" + +		"      <styleUrl>#ao-style-%s</styleUrl>\n" + +		"      <LineString>\n" + +		"        <tessellate>1</tessellate>\n" + +		"        <altitudeMode>absolute</altitudeMode>\n" + +		"        <coordinates>\n";  	static final String kml_coord_fmt = -	"        %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n"; +	"          %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n"; -	static final String kml_placemark_end = -		"      </coordinates>\n" + -		"    </LineString>\n" + -		"  </Placemark>\n"; +	static final String kml_path_end = +		"        </coordinates>\n" + +		"      </LineString>\n" + +		"    </Placemark>\n"; + +	static final String kml_point_start = +		"    <Placemark>\n" + +		"      <name>%s</name>\n" + +		"      <styleUrl>#ao-style-%s</styleUrl>\n" + +		"      <Point>\n" + +		"        <tessellate>1</tessellate>\n" + +		"        <altitudeMode>absolute</altitudeMode>\n" + +		"        <coordinates>\n"; + +	static final String kml_point_end = +		"        </coordinates>\n" + +		"      </Point>\n" + +		"    </Placemark>\n"; + +	static final String kml_folder_end = +		"  </Folder>\n";  	static final String kml_footer =  		"</Document>\n" +  		"</kml>\n"; -	void start (AltosCalData cal_data) { +	void start () {  		AltosGPS gps = cal_data.gps_pad;  		gps_start_altitude = cal_data.gps_pad_altitude;  		out.printf(kml_header_start, cal_data.flight, cal_data.serial); -		out.printf("Date:   %04d-%02d-%02d\n", +		out.printf("Product: %s\n", stats.product); +		out.printf("Firmware: %s\n", stats.firmware_version); +		out.printf("Date: %04d-%02d-%02d\n",  			   gps.year, gps.month, gps.day); -		out.printf("Time:     %2d:%02d:%02d\n", +		out.printf("Time: %2d:%02d:%02d\n",  			   gps.hour, gps.minute, gps.second); +		if (stats.max_height != AltosLib.MISSING) +			out.printf("Max baro height: %s\n", AltosConvert.height.show(6, stats.max_height)); +		if (stats.max_gps_height != AltosLib.MISSING) +			out.printf("Max GPS Height: %s\n", AltosConvert.height.show(6, stats.max_gps_height)); +		if (stats.max_speed != AltosLib.MISSING) +			out.printf("Max speed: %s\n", AltosConvert.speed.show(6, stats.max_speed)); +		if (stats.max_acceleration != AltosLib.MISSING) +			out.printf("Max accel: %s\n", AltosConvert.accel.show(6, stats.max_acceleration));  		out.printf("%s", kml_header_end);  	} -	boolean	started = false; +	void folder_start(String folder_name) { +		out.printf(kml_folder_start, folder_name); +	} + +	void folder_end() { +		out.printf(kml_folder_end); +	} + +	void path_style_start(String style, String color) { +		out.printf(kml_path_style_start, style, color); +	} + +	void path_style_end() { +		out.printf(kml_path_style_end); +	} -	void state_start(int state) { -		String	state_name = AltosLib.state_name(state); -		String	state_color = state_color(state); -		out.printf(kml_style_start, state_name, state_color); -		out.printf("State: %s\n", state_name); -		out.printf("Time: %6.2f s\n", stats.state_time[state]); -		out.printf("Average speed: %s\n", AltosConvert.speed.show(6, stats.state_speed[state])); -		out.printf("Average accel: %s\n", AltosConvert.accel.show(6, stats.state_accel[state])); -		out.printf("%s", kml_style_end); -		out.printf(kml_placemark_start, state_name, state_name); +	void point_style_start(String style, String color) { +		out.printf(kml_point_style_start, style, color, color);  	} -	void state_end() { -		out.printf("%s", kml_placemark_end); +	void point_style_end() { +		out.printf(kml_point_style_end);  	} -	void coord(double time, AltosGPS gps, int state, double height) { -		double		altitude; +	void path_start(String name, String style) { +		out.printf(kml_path_start, name, style); +	} + +	void path_end() { +		out.printf(kml_path_end); +	} + +	void point_start(String name, String style) { +		out.printf(kml_point_start, name, style); +	} + +	void point_end() { +		out.printf(kml_point_end); +	} + +	boolean	started = false; + +	private double baro_altitude(AltosFlightSeries series, double time) { +		double height = series.value(AltosFlightSeries.height_name, time); + +		if (height == AltosLib.MISSING) +			return AltosLib.MISSING; +		if (cal_data.gps_pad_altitude == AltosLib.MISSING) +			return AltosLib.MISSING; -		if (height != AltosLib.MISSING) -			altitude = height + gps_start_altitude; -		else -			altitude = gps.alt; +		return height + cal_data.gps_pad_altitude; +	} + +	void coord(double time, AltosGPS gps, double altitude) {  		out.printf(kml_coord_fmt,  			   gps.lon, gps.lat,  			   altitude, (double) gps.alt, @@ -150,48 +236,111 @@ public class AltosKML implements AltosWriter {  	}  	public void close() { -		if (prev != null) { -			state_end(); -			end(); -			prev = null; -		}  		if (out != null) {  			out.close();  			out = null;  		}  	} -	public void write(AltosGPSTimeValue gtv, AltosCalData cal_data, int state, double height) { -		AltosGPS gps = gtv.gps; +	public void write(AltosGPS gps, double alt) +	{ +		if (gps == null) +			return;  		if (gps.lat == AltosLib.MISSING)  			return;  		if (gps.lon == AltosLib.MISSING)  			return; -		if (state != flight_state) { -			flight_state = state; -			if (prev != null) { -				coord(gtv.time, gps, state, height); -				state_end(); -			} -			state_start(state); +		if (alt == AltosLib.MISSING) { +			alt = cal_data.gps_pad_altitude; +			if (alt == AltosLib.MISSING) +				return;  		} -		coord(0, gps, state, height); +		coord(0, gps, alt);  		prev = gps;  	} -	private int state(AltosFlightSeries series, double time) { -		return (int) series.value_before(AltosFlightSeries.state_name, time); -	} +	public void write_point(AltosTimeValue tv, boolean is_gps) { +		int		state = (int) tv.value; +		String		style_prefix = is_gps ? "gps-" : "baro-"; +		String		state_name = AltosLib.state_name(state); +		String		state_label = AltosLib.state_name_capital(state); +		String		style_name = style_prefix + state_name; +		String		folder_name = is_gps ? "GPS" : "Baro"; +		String		full_name = state_label + " (" + folder_name + ")"; +		AltosGPS	gps = series.gps_before(tv.time); +		double		altitude = is_gps ? gps.alt : baro_altitude(series, tv.time); -	private double height(AltosFlightSeries series, double time) { -		return series.value(AltosFlightSeries.height_name, time); +		point_style_start(style_name, state_color(state)); +		out.printf("%s\n", full_name); +		switch (state) { +		case AltosLib.ao_flight_boost: +			out.printf("Max accel %s\n", AltosConvert.accel.show(6, stats.max_acceleration)); +			out.printf("Max speed %s\n", AltosConvert.speed.show(6, stats.max_speed)); +			break; +		case AltosLib.ao_flight_coast: +		case AltosLib.ao_flight_fast: +			out.printf("Entry speed %s\n", AltosConvert.speed.show(6, stats.state_enter_speed[state])); +			out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude)); +			break; +		case AltosLib.ao_flight_drogue: +			out.printf("Max height %s\n", AltosConvert.height.show(6, is_gps ? stats.max_gps_height : stats.max_height)); +			out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state])); +			break; +		case AltosLib.ao_flight_main: +			out.printf("Entry speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state])); +			out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude)); +			out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state])); +			break; +		case AltosLib.ao_flight_landed: +			out.printf("Landing speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state])); +			break; +		} +		point_style_end(); +		point_start(full_name, style_name); +		gps = series.gps_before(tv.time); +		write(gps, altitude); +		point_end();  	}  	public void write(AltosFlightSeries series) { +		this.series = series; +		series.finish();  		stats = new AltosFlightStats(series); -		start(series.cal_data()); +		cal_data = series.cal_data(); +		start(); +		if (series.height_series != null) { +			folder_start("Barometric Altitude"); +			path_style_start("baro", style_color(0)); +			out.printf("Barometric Altitude\n"); +			out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_height)); +			path_style_end(); +			path_start("Barometric Altitude", "baro"); +			for (AltosGPSTimeValue gtv : series.gps_series) +				write(gtv.gps, baro_altitude(series, gtv.time)); +			path_end(); +			if (series.state_series != null) { +				for (AltosTimeValue tv : series.state_series) { +					write_point(tv, false); +				} +			} +			folder_end(); +		} +		folder_start("GPS Altitude"); +		path_style_start("gps", style_color(1)); +		out.printf("GPS Altitude"); +		out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_gps_height)); +		path_style_end(); +		path_start("GPS Altitude", "gps");  		for (AltosGPSTimeValue gtv : series.gps_series) -			write(gtv, series.cal_data(), state(series, gtv.time), height(series, gtv.time)); +			write(gtv.gps, gtv.gps.alt); +		path_end(); +		if (series.state_series != null) { +			for (AltosTimeValue tv : series.state_series) { +				write_point(tv, true); +			} +		} +		folder_end(); +		end();  	}  	public AltosKML(File in_name) throws FileNotFoundException { diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index d1063509..c25a6273 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -363,6 +363,7 @@ public class AltosLib {  	public static final int AO_LOG_FORMAT_TELEMINI3 = 12;  	public static final int AO_LOG_FORMAT_TELEFIRETWO = 13;  	public static final int AO_LOG_FORMAT_EASYMINI2 = 14; +	public static final int AO_LOG_FORMAT_TELEMEGA_3 = 15;  	public static final int AO_LOG_FORMAT_NONE = 127;  	public static boolean isspace(int c) { @@ -587,7 +588,11 @@ public class AltosLib {  	}  	public static String igniter_name(int i) { -		return String.format("Ignitor %c", 'A' + i); +		return String.format("Igniter %c", 'A' + i); +	} + +	public static String igniter_short_name(int i) { +		return String.format("igniter_%c", 'a' + i);  	}  	public static AltosRecordSet record_set(File file) throws FileNotFoundException, IOException { diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 5413de9d..829a1a63 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -355,7 +355,8 @@ public abstract class AltosLink implements Runnable {  	public int telemetry_rate = -1;  	public double frequency;  	public String callsign; -	AltosConfigData	config_data; +	private AltosConfigData	config_data_local; +	private AltosConfigData config_data_remote;  	private Object config_data_lock = new Object(); @@ -390,7 +391,7 @@ public abstract class AltosLink implements Runnable {  	public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException {  		frequency = in_frequency; -		config_data(); +		AltosConfigData config_data = config_data();  		set_radio_frequency(frequency,  				    config_data.radio_frequency > 0,  				    config_data.radio_setting > 0, @@ -446,11 +447,24 @@ public abstract class AltosLink implements Runnable {   	public AltosConfigData config_data() throws InterruptedException, TimeoutException {  		synchronized(config_data_lock) { -			if (config_data == null) { -				printf("m 0\n"); -				config_data = new AltosConfigData(this); -				if (monitor_mode) -					set_monitor(true); +			AltosConfigData	config_data; + +			if (remote) { +				if (config_data_remote == null) { +					printf("m 0\n"); +					config_data_remote = new AltosConfigData(this); +					if (monitor_mode) +						set_monitor(true); +				} +				config_data = config_data_remote; +			} else { +				if (config_data_local == null) { +					printf("m 0\n"); +					config_data_local = new AltosConfigData(this); +					if (monitor_mode) +						set_monitor(true); +				} +				config_data = config_data_local;  			}  			return config_data;  		} @@ -551,14 +565,23 @@ public abstract class AltosLink implements Runnable {  	}  	public boolean has_monitor_battery() { -		return config_data.has_monitor_battery(); +		try { +			return config_data().has_monitor_battery(); +		} catch (InterruptedException ie) { +			return false; +		} catch (TimeoutException te) { +			return false; +		}  	}  	public double monitor_battery() throws InterruptedException { -		int monitor_batt = AltosLib.MISSING; +		double	volts = AltosLib.MISSING; -		if (config_data.has_monitor_battery()) { -			try { +		try { +			AltosConfigData config_data = config_data(); +			int monitor_batt = AltosLib.MISSING; + +			if (config_data.has_monitor_battery()) {  				String[] items = adc();  				for (int i = 0; i < items.length;) {  					if (items[i].equals("batt")) { @@ -568,19 +591,17 @@ public abstract class AltosLink implements Runnable {  					}  					i++;  				} -			} catch (TimeoutException te) {  			} -		} -		if (monitor_batt == AltosLib.MISSING) -			return AltosLib.MISSING; +			if (monitor_batt != AltosLib.MISSING) { +				if (config_data.product.startsWith("TeleBT-v3") || config_data.product.startsWith("TeleBT-v4")) { +					volts = AltosConvert.tele_bt_3_battery(monitor_batt); +				} else { +					volts = AltosConvert.cc_battery_to_voltage(monitor_batt); +				} +			} -		double	volts = AltosLib.MISSING; -		if (config_data.product.startsWith("TeleBT-v3") || config_data.product.startsWith("TeleBT-v4")) { -			volts = AltosConvert.tele_bt_3_battery(monitor_batt); -		} else { -			volts = AltosConvert.cc_battery_to_voltage(monitor_batt); +		} catch (TimeoutException te) {  		} -  		return volts;  	} diff --git a/altoslib/AltosReplayReader.java b/altoslib/AltosReplayReader.java index 24b425b7..fab28cac 100644 --- a/altoslib/AltosReplayReader.java +++ b/altoslib/AltosReplayReader.java @@ -31,7 +31,7 @@ class AltosReplay extends AltosDataListener implements Runnable {  	AltosState	state;  	AltosRecordSet	record_set;  	double		last_time = AltosLib.MISSING; -	Semaphore	semaphore = new Semaphore(1);; +	Semaphore	semaphore = new Semaphore(1);  	boolean		done = false;  	public void set_time(double time) { @@ -70,7 +70,7 @@ class AltosReplay extends AltosDataListener implements Runnable {  	public void set_apogee_voltage(double volts) { state.set_apogee_voltage(volts); }  	public void set_main_voltage(double volts) { state.set_main_voltage(volts); } -	public void set_gps(AltosGPS gps) { state.set_gps(gps); } +	public void set_gps(AltosGPS gps) { super.set_gps(gps); state.set_gps(gps); }  	public void set_orient(double orient) { state.set_orient(orient); }  	public void set_gyro(double roll, double pitch, double yaw) { state.set_gyro(roll, pitch, yaw); } diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 39ab10da..68097faf 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -480,7 +480,7 @@ public class AltosState extends AltosDataListener {  	class AltosPressure extends AltosValue {  		void set(double p, double time) {  			super.set(p, time); -			if (state == AltosLib.ao_flight_pad) +			if (state() == AltosLib.ao_flight_pad)  				ground_pressure.set_filtered(p, time);  			double a = pressure_to_altitude(p);  			altitude.set_computed(a, time); @@ -557,7 +557,7 @@ public class AltosState extends AltosDataListener {  	class AltosSpeed extends AltosCValue {  		boolean can_max() { -			return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless; +			return state() < AltosLib.ao_flight_fast || state() == AltosLib.ao_flight_stateless;  		}  		void set_accel() { @@ -615,7 +615,7 @@ public class AltosState extends AltosDataListener {  	class AltosAccel extends AltosCValue {  		boolean can_max() { -			return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless; +			return state() < AltosLib.ao_flight_fast || state() == AltosLib.ao_flight_stateless;  		}  		void set_measured(double a, double time) { @@ -712,11 +712,11 @@ public class AltosState extends AltosDataListener {  	}  	public void init() { +		super.init(); +  		set = 0;  		received_time = System.currentTimeMillis(); -		time = AltosLib.MISSING; -		state = AltosLib.ao_flight_invalid;  		landed = false;  		boost = false;  		rssi = AltosLib.MISSING; @@ -819,9 +819,9 @@ public class AltosState extends AltosDataListener {  		if (gps.locked && gps.nsat >= 4) {  			/* Track consecutive 'good' gps reports, waiting for 10 of them */ -			if (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_stateless) { +			if (state() == AltosLib.ao_flight_pad || state() == AltosLib.ao_flight_stateless) {  				set_npad(npad+1); -				if (pad_lat != AltosLib.MISSING && (npad < 10 || state == AltosLib.ao_flight_pad)) { +				if (pad_lat != AltosLib.MISSING && (npad < 10 || state() == AltosLib.ao_flight_pad)) {  					pad_lat = (pad_lat * 31 + gps.lat) / 32;  					pad_lon = (pad_lon * 31 + gps.lon) / 32;  					gps_ground_altitude.set_filtered(gps.alt, time); @@ -859,24 +859,14 @@ public class AltosState extends AltosDataListener {  	}  	public String state_name() { -		return AltosLib.state_name(state); +		return AltosLib.state_name(state());  	}  	public void set_state(int state) { -		if (state != AltosLib.ao_flight_invalid) { -			this.state = state; -			ascent = (AltosLib.ao_flight_boost <= state && -				  state <= AltosLib.ao_flight_coast); -			boost = (AltosLib.ao_flight_boost == state); -		} -	} - -	public int state() { -		return state; -	} - -	private void re_init() { -		init(); +		super.set_state(state); +		ascent = (AltosLib.ao_flight_boost <= state() && +			  state() <= AltosLib.ao_flight_coast); +		boost = (AltosLib.ao_flight_boost == state());  	}  	public int rssi() { @@ -897,6 +887,7 @@ public class AltosState extends AltosDataListener {  	}  	public void set_gps(AltosGPS gps) { +		super.set_gps(gps);  		if (gps != null) {  			this.gps = gps;  			update_gps(); diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index f17e1171..a374519d 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -28,8 +28,11 @@ public abstract class AltosTelemetry implements AltosDataProvider {  	int[]	bytes;  	/* All telemetry packets have these fields */ -	public int rssi() { return AltosConvert.telem_to_rssi(AltosLib.int8(bytes, bytes.length - 3)); } -	public int status() { return AltosLib.uint8(bytes, bytes.length - 2); } +	static public int rssi(int[] bytes) { return AltosConvert.telem_to_rssi(AltosLib.int8(bytes, bytes.length - 3)); } +	static public int status(int[] bytes) { return AltosLib.uint8(bytes, bytes.length - 2); } + +	public int rssi() { return rssi(bytes); } +	public int status() { return status(bytes); }  	/* All telemetry packets report these fields in some form */  	public abstract int serial(); @@ -51,7 +54,7 @@ public abstract class AltosTelemetry implements AltosDataProvider {  	public void provide_data(AltosDataListener listener) {  		listener.set_serial(serial()); -		if (listener.state == AltosLib.ao_flight_invalid) +		if (listener.state() == AltosLib.ao_flight_invalid)  			listener.set_state(AltosLib.ao_flight_startup);  		if (frequency != AltosLib.MISSING)  			listener.set_frequency(frequency); @@ -96,6 +99,9 @@ public abstract class AltosTelemetry implements AltosDataProvider {  		if (!cksum(bytes))  			throw new ParseException(String.format("invalid line \"%s\"", hex), 0); +		if ((status(bytes) & PKT_APPEND_STATUS_1_CRC_OK) == 0) +			throw new AltosCRCException(rssi(bytes)); +  		/* length, data ..., rssi, status, checksum -- 4 bytes extra */  		switch (bytes.length) {  		case AltosLib.ao_telemetry_standard_len + 4: diff --git a/altoslib/AltosTelemetryConfiguration.java b/altoslib/AltosTelemetryConfiguration.java index ea307442..c8026a83 100644 --- a/altoslib/AltosTelemetryConfiguration.java +++ b/altoslib/AltosTelemetryConfiguration.java @@ -40,7 +40,7 @@ public class AltosTelemetryConfiguration extends AltosTelemetryStandard {  		AltosCalData cal_data = listener.cal_data(); -		cal_data.set_device_type(device_type()); +		listener.set_device_type(device_type());  		cal_data.set_flight(flight());  		cal_data.set_config(config_major(), config_minor(), flight_log_max());  		if (device_type() == AltosLib.product_telegps) diff --git a/altoslib/AltosTelemetryFile.java b/altoslib/AltosTelemetryFile.java index 135b0284..e51455f8 100644 --- a/altoslib/AltosTelemetryFile.java +++ b/altoslib/AltosTelemetryFile.java @@ -128,7 +128,7 @@ public class AltosTelemetryFile implements AltosRecordSet {  			/* Try to pick up at least one pre-boost value */  			if (cal_data.time() >= -2)  				telem.provide_data(listener); -			if (listener.state == AltosLib.ao_flight_landed) +			if (listener.state() == AltosLib.ao_flight_landed)  				break;  		}  		listener.finish(); diff --git a/altoslib/AltosTelemetryLocation.java b/altoslib/AltosTelemetryLocation.java index f4366e33..e2925a58 100644 --- a/altoslib/AltosTelemetryLocation.java +++ b/altoslib/AltosTelemetryLocation.java @@ -54,7 +54,7 @@ public class AltosTelemetryLocation extends AltosTelemetryStandard {  		AltosCalData	cal_data = listener.cal_data(); -		AltosGPS	gps = cal_data.make_temp_gps(tick(), false); +		AltosGPS	gps = listener.make_temp_gps(false);  		int flags = flags();  		gps.nsat = flags & 0xf; @@ -77,12 +77,7 @@ public class AltosTelemetryLocation extends AltosTelemetryStandard {  			gps.ground_speed = ground_speed() * 1.0e-2;  			gps.course = course() * 2;  			gps.climb_rate = climb_rate() * 1.0e-2; - -			if (gps.nsat >= 4) -				cal_data.set_gps(gps);  		}  		listener.set_gps(gps); -		cal_data.set_gps(gps); -		cal_data.reset_temp_gps();  	}  } diff --git a/altoslib/AltosTelemetryMegaData.java b/altoslib/AltosTelemetryMegaData.java index 7ef9c637..f5961c8c 100644 --- a/altoslib/AltosTelemetryMegaData.java +++ b/altoslib/AltosTelemetryMegaData.java @@ -24,7 +24,9 @@ public class AltosTelemetryMegaData extends AltosTelemetryStandard {  	int	v_batt() { return int16(6); }  	int	v_pyro() { return int16(8); } -	int	sense(int i) { int v = uint8(10+i); return v << 4 | v >> 8; } + +	/* pyro sense values are sent in 8 bits, expand to 12 bits */ +	int	sense(int i) { int v = uint8(10+i); return (v << 4) | (v >> 4); }  	int	ground_pres() { return int32(16); }  	int	ground_accel() { return int16(20); } diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 26fe4f26..8fb61a4f 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -41,19 +41,15 @@ public class AltosTelemetryReader extends AltosFlightReader {  				throw new IOException("IO error");  		} while (!link.get_monitor());  		AltosTelemetry	telem = AltosTelemetry.parse(l.line); -		if (state == null) { -			System.out.printf("Make state\n"); +		if (state == null)  			state = new AltosState(cal_data()); -		}  		telem.provide_data(state);  		return state;  	}  	public AltosCalData cal_data() { -		if (cal_data == null) { -			System.out.printf("Make cal data\n"); +		if (cal_data == null)  			cal_data = new AltosCalData(); -		}  		return cal_data;  	} diff --git a/altoslib/AltosTelemetrySatellite.java b/altoslib/AltosTelemetrySatellite.java index 60bc4a51..0965df9f 100644 --- a/altoslib/AltosTelemetrySatellite.java +++ b/altoslib/AltosTelemetrySatellite.java @@ -49,10 +49,9 @@ public class AltosTelemetrySatellite extends AltosTelemetryStandard {  		AltosCalData	cal_data = listener.cal_data(); -		AltosGPS	gps = cal_data.make_temp_gps(tick(), true); +		AltosGPS	gps = listener.make_temp_gps(true);  		gps.cc_gps_sat = sats();  		listener.set_gps(gps); -		cal_data.reset_temp_gps();  	}  } diff --git a/altoslib/AltosTimeSeries.java b/altoslib/AltosTimeSeries.java index 9f3b4d80..c6a780a3 100644 --- a/altoslib/AltosTimeSeries.java +++ b/altoslib/AltosTimeSeries.java @@ -20,15 +20,30 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue>, Comparable<Alt  	public String			label;  	public AltosUnits		units;  	ArrayList<AltosTimeValue>	values; +	boolean				data_changed;  	public int compareTo(AltosTimeSeries other) {  		return label.compareTo(other.label);  	}  	public void add(AltosTimeValue tv) { +		data_changed = true;  		values.add(tv);  	} +	public void erase_values() { +		data_changed = true; +		this.values = new ArrayList<AltosTimeValue>(); +	} + +	public void clear_changed() { +		data_changed = false; +	} + +//	public boolean changed() { +//		return data_changed; +//	} +  	public void add(double time, double value) {  		add(new AltosTimeValue(time, value));  	} @@ -264,14 +279,35 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue>, Comparable<Alt  	} -	private double filter_coeff(double dist, double width) { -		double ratio = dist / (width / 2); +	private static double i0(double x) { +		double	ds = 1, d = 0, s = 0; -		return Math.cos(ratio * Math.PI / 2); +		do { +			d += 2; +			ds = ds * (x * x) / (d * d); +			s += ds; +		} while (ds - 0.2e-8 * s > 0); +		return s; +	} + +	private static double kaiser(double n, double m, double beta) { +		double alpha = m / 2; +		double t = (n - alpha) / alpha; + +		if (t > 1 || t < -1) +			t = 1; +		double k = i0 (beta * Math.sqrt (1 - t*t)) / i0(beta); +		return k; +	} + +	private double filter_coeff(double dist, double width) { +		return kaiser(dist + width/2.0, width, 2 * Math.PI);  	}  	public AltosTimeSeries filter(AltosTimeSeries f, double width) { +  		double	half_width = width/2; +		int half_point = values.size() / 2;  		for (int i = 0; i < values.size(); i++) {  			double	center_time = values.get(i).time;  			double	left_time = center_time - half_width; diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 08af9496..2a1cb8e4 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -55,6 +55,7 @@ altoslib_JAVA = \  	AltosEepromList.java \  	AltosEepromLog.java \  	AltosFile.java \ +	AltosFilterListener.java \  	AltosFlash.java \  	AltosFlashListener.java \  	AltosDataListener.java \  | 
