diff options
| -rw-r--r-- | altoslib/AltosConfigData.java | 38 | ||||
| -rw-r--r-- | altosui/AltosConfig.java | 24 | ||||
| -rw-r--r-- | altosui/AltosConfigUI.java | 72 | ||||
| -rw-r--r-- | telegps/Makefile.am | 3 | ||||
| -rw-r--r-- | telegps/TeleGPS.java | 4 | ||||
| -rw-r--r-- | telegps/TeleGPSConfig.java | 24 | ||||
| -rw-r--r-- | telegps/TeleGPSConfigUI.java | 64 | ||||
| -rw-r--r-- | telegps/TeleGPSDisplayThread.java | 209 | 
8 files changed, 345 insertions, 93 deletions
diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 9292a5a2..9462ae6f 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -29,6 +29,7 @@ public class AltosConfigData implements Iterable<String> {  	public int	serial;  	public int	flight;  	public int	log_format; +	public int	log_space;  	public String	version;  	/* Strings returned */ @@ -124,6 +125,22 @@ public class AltosConfigData implements Iterable<String> {  		return lines.iterator();  	} +	public int log_space() { +		if (log_space > 0) +			return log_space; + +		if (storage_size > 0) { +			int	space = storage_size; + +			if (storage_erase_unit > 0 && use_flash_for_config()) +				space -= storage_erase_unit; + +			if (space > 0) +				return space; +		} +		return 0; +	} +  	public int log_available() {  		switch (log_format) {  		case AltosLib.AO_LOG_FORMAT_TINY: @@ -137,7 +154,7 @@ public class AltosConfigData implements Iterable<String> {  			if (flight_log_max <= 0)  				return 1;  			int	log_max = flight_log_max * 1024; -			int	log_space = storage_size - storage_erase_unit; +			int	log_space = log_space();  			int	log_used;  			if (stored_flight <= 0) @@ -202,6 +219,7 @@ public class AltosConfigData implements Iterable<String> {  		serial = 0;  		flight = 0;  		log_format = AltosLib.AO_LOG_FORMAT_UNKNOWN; +		log_space = -1;  		version = "unknown";  		main_deploy = -1; @@ -247,6 +265,7 @@ public class AltosConfigData implements Iterable<String> {  		try { serial = get_int(line, "serial-number"); } catch (Exception e) {}  		try { flight = get_int(line, "current-flight"); } catch (Exception e) {}  		try { log_format = get_int(line, "log-format"); } catch (Exception e) {} +		try { log_space = get_int(line, "log-space"); } catch (Exception e) {}  		try { version = get_string(line, "software-version"); } catch (Exception e) {}  		/* Version also contains MS5607 info, which we ignore here */ @@ -390,19 +409,6 @@ public class AltosConfigData implements Iterable<String> {  	} -	public int log_limit() { -		if (storage_size > 0) { -			int	log_limit = storage_size; - -			if (storage_erase_unit > 0 && use_flash_for_config()) -				log_limit -= storage_erase_unit; - -			if (log_limit > 0) -				return log_limit / 1024; -		} -		return 1024; -	} -  	public void get_values(AltosConfigValues source) throws AltosConfigDataException {  		/* HAS_FLIGHT */ @@ -462,7 +468,7 @@ public class AltosConfigData implements Iterable<String> {  		dest.set_radio_frequency(frequency());  		boolean max_enabled = true; -		if (log_limit() == 0) +		if (log_space() == 0)  			max_enabled = false;  		switch (log_format) { @@ -477,7 +483,7 @@ public class AltosConfigData implements Iterable<String> {  		dest.set_flight_log_max_enabled(max_enabled);  		dest.set_radio_enable(radio_enable); -		dest.set_flight_log_max_limit(log_limit()); +		dest.set_flight_log_max_limit(log_space() / 1024);  		dest.set_flight_log_max(flight_log_max);  		dest.set_ignite_mode(ignite_mode);  		dest.set_pad_orientation(pad_orientation); diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 2cf69525..6eb7d40c 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -229,20 +229,20 @@ public class AltosConfig implements ActionListener {  	void save_data() { -		/* bounds check stuff */ -		if (config_ui.flight_log_max() > data.log_limit()) { -			JOptionPane.showMessageDialog(owner, -						      String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", -								    config_ui.flight_log_max(), -								    data.log_limit()), -						      "Maximum Flight Log Too Large", -						      JOptionPane.ERROR_MESSAGE); -			return; -		} +		try { +			/* bounds check stuff */ +			if (config_ui.flight_log_max() > data.log_space() / 1024) { +				JOptionPane.showMessageDialog(owner, +							      String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", +									    config_ui.flight_log_max(), +									    data.log_space() / 1024), +							      "Maximum Flight Log Too Large", +							      JOptionPane.ERROR_MESSAGE); +				return; +			} -		/* Pull data out of the UI and stuff back into our local data record */ +			/* Pull data out of the UI and stuff back into our local data record */ -		try {  			data.get_values(config_ui);  			run_serial_thread(serial_mode_save);  		} catch (AltosConfigDataException ae) { diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index bcb3e12c..f936d92c 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -99,12 +99,6 @@ public class AltosConfigUI  		"0", "5", "10", "15", "20"  	}; -	static String[] 	flight_log_max_values = { -		"64", "128", "192", "256", "320", -		"384", "448", "512", "576", "640", -		"704", "768", "832", "896", "960", -	}; -  	static String[] 	ignite_mode_values = {  		"Dual Deploy",  		"Redundant Apogee", @@ -546,7 +540,7 @@ public class AltosConfigUI  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = il;  		c.ipady = 5; -		flight_log_max_label = new JLabel("Maximum Flight Log Size:"); +		flight_log_max_label = new JLabel("Maximum Flight Log Size (kB):");  		pane.add(flight_log_max_label, c);  		c = new GridBagConstraints(); @@ -557,7 +551,7 @@ public class AltosConfigUI  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = ir;  		c.ipady = 5; -		flight_log_max_value = new JComboBox<String>(flight_log_max_values); +		flight_log_max_value = new JComboBox<String>();  		flight_log_max_value.setEditable(true);  		flight_log_max_value.addItemListener(this);  		pane.add(flight_log_max_value, c); @@ -918,8 +912,19 @@ public class AltosConfigUI  		apogee_delay_value.setEnabled(new_apogee_delay >= 0);  	} -	public int apogee_delay() { -		return Integer.parseInt(apogee_delay_value.getSelectedItem().toString()); +	private int parse_int(String name, String s, boolean split) throws AltosConfigDataException { +		String v = s; +		if (split) +			v = s.split("\\s+")[0]; +		try { +			return Integer.parseInt(v); +		} catch (NumberFormatException ne) { +			throw new AltosConfigDataException("Invalid %s \"%s\"", name, s); +		} +	} + +	public int apogee_delay() throws AltosConfigDataException { +		return parse_int("apogee delay", apogee_delay_value.getSelectedItem().toString(), false);  	}  	public void set_apogee_lockout(int new_apogee_lockout) { @@ -927,8 +932,8 @@ public class AltosConfigUI  		apogee_lockout_value.setEnabled(new_apogee_lockout >= 0);  	} -	public int apogee_lockout() { -		return Integer.parseInt(apogee_lockout_value.getSelectedItem().toString()); +	public int apogee_lockout() throws AltosConfigDataException { +		return parse_int("apogee lockout", apogee_lockout_value.getSelectedItem().toString(), false);  	}  	public void set_radio_frequency(double new_radio_frequency) { @@ -947,8 +952,8 @@ public class AltosConfigUI  			radio_calibration_value.setText(String.format("%d", new_radio_calibration));  	} -	public int radio_calibration() { -		return Integer.parseInt(radio_calibration_value.getText()); +	public int radio_calibration() throws AltosConfigDataException { +		return parse_int("radio calibration", radio_calibration_value.getText(), false);  	}  	public void set_radio_enable(int new_radio_enable) { @@ -979,8 +984,22 @@ public class AltosConfigUI  		return callsign_value.getText();  	} +	int	flight_log_max_limit; +	int	flight_log_max; + +	public String flight_log_max_label(int flight_log_max) { +		if (flight_log_max_limit != 0) { +			int	nflight = flight_log_max_limit / flight_log_max; +			String	plural = nflight > 1 ? "s" : ""; + +			return String.format("%d (%d flight%s)", flight_log_max, nflight, plural); +		} +		return String.format("%d", flight_log_max); +	} +  	public void set_flight_log_max(int new_flight_log_max) { -		flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max)); +		flight_log_max_value.setSelectedItem(flight_log_max_label(new_flight_log_max)); +		flight_log_max = new_flight_log_max;  		set_flight_log_max_tool_tip();  	} @@ -989,20 +1008,19 @@ public class AltosConfigUI  		set_flight_log_max_tool_tip();  	} -	public int flight_log_max() { -		return Integer.parseInt(flight_log_max_value.getSelectedItem().toString()); +	public int flight_log_max() throws AltosConfigDataException { +		return parse_int("flight log max", flight_log_max_value.getSelectedItem().toString(), true);  	} -	public void set_flight_log_max_limit(int flight_log_max_limit) { -		//boolean	any_added = false; +	public void set_flight_log_max_limit(int new_flight_log_max_limit) { +		flight_log_max_limit = new_flight_log_max_limit;  		flight_log_max_value.removeAllItems(); -		for (int i = 0; i < flight_log_max_values.length; i++) { -			if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){ -				flight_log_max_value.addItem(flight_log_max_values[i]); -				//any_added = true; -			} +		for (int i = 8; i >= 1; i--) { +			int	size = flight_log_max_limit / i; +			flight_log_max_value.addItem(String.format("%d (%d flights)", size, i));  		} -		flight_log_max_value.addItem(String.format("%d", flight_log_max_limit)); +		if (flight_log_max != 0) +			set_flight_log_max(flight_log_max);  	}  	public void set_ignite_mode(int new_ignite_mode) { @@ -1165,11 +1183,11 @@ public class AltosConfigUI  		set_aprs_interval_tool_tip();  	} -	public int aprs_interval() { +	public int aprs_interval() throws AltosConfigDataException {  		String	s = aprs_interval_value.getSelectedItem().toString();  		if (s.equals("Disabled"))  			return 0; -		return Integer.parseInt(s); +		return parse_int("aprs interval", s, false);  	}  } diff --git a/telegps/Makefile.am b/telegps/Makefile.am index 7e17b331..e0d596e7 100644 --- a/telegps/Makefile.am +++ b/telegps/Makefile.am @@ -19,7 +19,8 @@ telegps_JAVA= \  	TeleGPSConfig.java \  	TeleGPSConfigUI.java \  	TeleGPSPreferences.java \ -	TeleGPSGraphUI.java +	TeleGPSGraphUI.java \ +	TeleGPSDisplayThread.java  JFREECHART_CLASS= \      jfreechart.jar diff --git a/telegps/TeleGPS.java b/telegps/TeleGPS.java index 71174436..c61b245e 100644 --- a/telegps/TeleGPS.java +++ b/telegps/TeleGPS.java @@ -51,7 +51,7 @@ public class TeleGPS  	}  	AltosFlightReader	reader; -	AltosDisplayThread	thread; +	TeleGPSDisplayThread	thread;  	JMenuBar		menu_bar; @@ -349,7 +349,7 @@ public class TeleGPS  	public void set_reader(AltosFlightReader reader) {  		setTitle(String.format("TeleGPS %s", reader.name)); -		thread = new AltosDisplayThread(this, voice(), this, reader); +		thread = new TeleGPSDisplayThread(this, voice(), this, reader);  		thread.start();  	} diff --git a/telegps/TeleGPSConfig.java b/telegps/TeleGPSConfig.java index 22e6a3ac..3505b0bb 100644 --- a/telegps/TeleGPSConfig.java +++ b/telegps/TeleGPSConfig.java @@ -221,20 +221,20 @@ public class TeleGPSConfig implements ActionListener {  	void save_data() { -		/* bounds check stuff */ -		if (config_ui.flight_log_max() > data.log_limit()) { -			JOptionPane.showMessageDialog(owner, -						      String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", -								    config_ui.flight_log_max(), -								    data.log_limit()), -						      "Maximum Flight Log Too Large", -						      JOptionPane.ERROR_MESSAGE); -			return; -		} +		try { +			/* bounds check stuff */ +			if (config_ui.flight_log_max() > data.log_space()/1024) { +				JOptionPane.showMessageDialog(owner, +							      String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", +									    config_ui.flight_log_max(), +									    data.log_space()/1024), +							      "Maximum Flight Log Too Large", +							      JOptionPane.ERROR_MESSAGE); +				return; +			} -		/* Pull data out of the UI and stuff back into our local data record */ +			/* Pull data out of the UI and stuff back into our local data record */ -		try {  			data.get_values(config_ui);  			run_serial_thread(serial_mode_save);  		} catch (AltosConfigDataException ae) { diff --git a/telegps/TeleGPSConfigUI.java b/telegps/TeleGPSConfigUI.java index 863d61bb..03666036 100644 --- a/telegps/TeleGPSConfigUI.java +++ b/telegps/TeleGPSConfigUI.java @@ -65,12 +65,6 @@ public class TeleGPSConfigUI  	ActionListener		listener; -	static String[] 	flight_log_max_values = { -		"64", "128", "192", "256", "320", -		"384", "448", "512", "576", "640", -		"704", "768", "832", "896", "960", -	}; -  	static String[] 	aprs_interval_values = {  		"Disabled",  		"2", @@ -376,7 +370,7 @@ public class TeleGPSConfigUI  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = il;  		c.ipady = 5; -		flight_log_max_label = new JLabel("Maximum Flight Log Size:"); +		flight_log_max_label = new JLabel("Maximum Log Size (kB):");  		pane.add(flight_log_max_label, c);  		c = new GridBagConstraints(); @@ -387,7 +381,7 @@ public class TeleGPSConfigUI  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = ir;  		c.ipady = 5; -		flight_log_max_value = new JComboBox<String>(flight_log_max_values); +		flight_log_max_value = new JComboBox<String>();  		flight_log_max_value.setEditable(true);  		flight_log_max_value.addItemListener(this);  		pane.add(flight_log_max_value, c); @@ -636,8 +630,19 @@ public class TeleGPSConfigUI  			radio_calibration_value.setText(String.format("%d", new_radio_calibration));  	} -	public int radio_calibration() { -		return Integer.parseInt(radio_calibration_value.getText()); +	private int parse_int(String name, String s, boolean split) throws AltosConfigDataException { +		String v = s; +		if (split) +			v = s.split("\\s+")[0]; +		try { +			return Integer.parseInt(v); +		} catch (NumberFormatException ne) { +			throw new AltosConfigDataException("Invalid %s \"%s\"", name, s); +		} +	} + +	public int radio_calibration() throws AltosConfigDataException { +		return parse_int("radio calibration", radio_calibration_value.getText(), false);  	}  	public void set_radio_enable(int new_radio_enable) { @@ -668,8 +673,22 @@ public class TeleGPSConfigUI  		return callsign_value.getText();  	} +	int	flight_log_max_limit; +	int	flight_log_max; + +	public String flight_log_max_label(int flight_log_max) { +		if (flight_log_max_limit != 0) { +			int	nflight = flight_log_max_limit / flight_log_max; +			String	plural = nflight > 1 ? "s" : ""; + +			return String.format("%d (%d flight%s)", flight_log_max, nflight, plural); +		} +		return String.format("%d", flight_log_max); +	} +  	public void set_flight_log_max(int new_flight_log_max) { -		flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max)); +		flight_log_max_value.setSelectedItem(flight_log_max_label(new_flight_log_max)); +		flight_log_max = new_flight_log_max;  		set_flight_log_max_tool_tip();  	} @@ -678,20 +697,19 @@ public class TeleGPSConfigUI  		set_flight_log_max_tool_tip();  	} -	public int flight_log_max() { -		return Integer.parseInt(flight_log_max_value.getSelectedItem().toString()); +	public int flight_log_max() throws AltosConfigDataException { +		return parse_int("flight log max", flight_log_max_value.getSelectedItem().toString(), true);  	} -	public void set_flight_log_max_limit(int flight_log_max_limit) { -		//boolean	any_added = false; +	public void set_flight_log_max_limit(int new_flight_log_max_limit) { +		flight_log_max_limit = new_flight_log_max_limit;  		flight_log_max_value.removeAllItems(); -		for (int i = 0; i < flight_log_max_values.length; i++) { -			if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){ -				flight_log_max_value.addItem(flight_log_max_values[i]); -				//any_added = true; -			} +		for (int i = 8; i >= 1; i--) { +			int	size = flight_log_max_limit / i; +			flight_log_max_value.addItem(String.format("%d (%d flights)", size, i));  		} -		flight_log_max_value.addItem(String.format("%d", flight_log_max_limit)); +		if (flight_log_max != 0) +			set_flight_log_max(flight_log_max);  	}  	public void set_ignite_mode(int new_ignite_mode) { } @@ -791,11 +809,11 @@ public class TeleGPSConfigUI  		set_aprs_interval_tool_tip();  	} -	public int aprs_interval() { +	public int aprs_interval() throws AltosConfigDataException {  		String	s = aprs_interval_value.getSelectedItem().toString();  		if (s.equals("Disabled"))  			return 0; -		return Integer.parseInt(s); +		return parse_int("aprs interval", s, false);  	}  } diff --git a/telegps/TeleGPSDisplayThread.java b/telegps/TeleGPSDisplayThread.java new file mode 100644 index 00000000..9de33098 --- /dev/null +++ b/telegps/TeleGPSDisplayThread.java @@ -0,0 +1,209 @@ +/* + * 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.telegps; + +import java.awt.*; +import javax.swing.*; +import java.io.*; +import java.text.*; +import org.altusmetrum.altoslib_4.*; +import org.altusmetrum.altosuilib_2.*; + +public class TeleGPSDisplayThread extends Thread { + +	Frame			parent; +	IdleThread		idle_thread; +	AltosVoice		voice; +	AltosFlightReader	reader; +	AltosState		old_state, state; +	AltosListenerState	listener_state; +	AltosFlightDisplay	display; + +	synchronized void show_safely() { +		final AltosState my_state = state; +		final AltosListenerState my_listener_state = listener_state; +		Runnable r = new Runnable() { +				public void run() { +					try { +						display.show(my_state, my_listener_state); +					} catch (Exception ex) { +					} +				} +			}; +		SwingUtilities.invokeLater(r); +	} + +	void reading_error_internal() { +		JOptionPane.showMessageDialog(parent, +					      String.format("Error reading from \"%s\"", reader.name), +					      "Telemetry Read Error", +					      JOptionPane.ERROR_MESSAGE); +	} + +	void reading_error_safely() { +		Runnable r = new Runnable() { +				public void run() { +					try { +						reading_error_internal(); +					} catch (Exception ex) { +					} +				} +			}; +		SwingUtilities.invokeLater(r); +	} + +	class IdleThread extends Thread { + +		boolean	started; +		int	report_interval; +		long	report_time; + +		public synchronized void report(boolean last) { +			if (state == null) +				return; + +			if (state.height() != AltosLib.MISSING) { +				if (state.from_pad != null) { +					voice.speak("Height %s, bearing %s %d, elevation %d, range %s, .\n", +						    AltosConvert.height.say(state.gps_height()), +						    state.from_pad.bearing_words( +							    AltosGreatCircle.BEARING_VOICE), +						    (int) (state.from_pad.bearing + 0.5), +						    (int) (state.elevation + 0.5), +						    AltosConvert.distance.say(state.range)); +				} else { +					voice.speak("Height %s.\n", +						    AltosConvert.height.say(state.height())); +				} +			} else { +				voice.speak("Height is unknown.\n"); +			} +		} + +		long now () { +			return System.currentTimeMillis(); +		} + +		void set_report_time() { +			report_time = now() + report_interval; +		} + +		public void run () { +			try { +				for (;;) { +					if (reader.has_monitor_battery()) { +						listener_state.battery = reader.monitor_battery(); +						show_safely(); +					} +					set_report_time(); +					for (;;) { +						voice.drain(); +						synchronized (this) { +							long	sleep_time = report_time - now(); +							if (sleep_time <= 0) +								break; +							wait(sleep_time); +						} +					} + +					report(false); +				} +			} catch (InterruptedException ie) { +				try { +					voice.drain(); +				} catch (InterruptedException iie) { } +			} +		} + +		public synchronized void notice(boolean spoken) { +			if (old_state != null && old_state.state != state.state) { +				report_time = now(); +				this.notify(); +			} else if (spoken) +				set_report_time(); +		} + +		public IdleThread() { +			report_interval = 10000; +		} +	} + +	synchronized boolean tell() { +		boolean	ret = false; +		if (old_state == null || old_state.gps_ready != state.gps_ready) { +			if (state.gps_ready) { +				voice.speak("GPS ready"); +				ret = true; +			} +			else if (old_state != null) { +				voice.speak("GPS lost"); +				ret = true; +			} +		} +		old_state = state; +		return ret; +	} + +	public void run() { +		boolean		interrupted = false; +		boolean		told; + +		idle_thread = new IdleThread(); +		idle_thread.start(); + +		try { +			for (;;) { +				try { +					state = reader.read(); +					if (state == null) +						break; +					reader.update(state); +					show_safely(); +					told = tell(); +					idle_thread.notice(told); +				} catch (ParseException pp) { +					System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); +				} catch (AltosCRCException ce) { +					++listener_state.crc_errors; +					show_safely(); +				} +			} +		} catch (InterruptedException ee) { +			interrupted = true; +		} catch (IOException ie) { +			reading_error_safely(); +		} finally { +			if (!interrupted) +				idle_thread.report(true); +			reader.close(interrupted); +			idle_thread.interrupt(); +			try { +				idle_thread.join(); +			} catch (InterruptedException ie) {} +		} +	} + +	public TeleGPSDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) { +		listener_state = new AltosListenerState(); +		parent = in_parent; +		voice = in_voice; +		display = in_display; +		reader = in_reader; +		display.reset(); +	} +}  | 
