diff options
| author | Keith Packard <keithp@keithp.com> | 2014-05-25 20:55:11 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2014-05-25 20:56:48 -0700 | 
| commit | 0a6c76fc0525d6588a1d88127f0085f13a02f1af (patch) | |
| tree | d7cf76748c86522708b0826237eb031f371e349d /altosuilib/AltosDisplayThread.java | |
| parent | 4ac7797d3efb9cc2d9fae88519f55e40b1050224 (diff) | |
altosui/altosuilib/altoslib: Move more stuff out of autosui. Reduce site map memory
Prepare to share with TeleGPS application.
This also has the changes to the site map tile which cache only a few
images and regenerate the flight path on the fly, saving piles of memory
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'altosuilib/AltosDisplayThread.java')
| -rw-r--r-- | altosuilib/AltosDisplayThread.java | 259 | 
1 files changed, 259 insertions, 0 deletions
| diff --git a/altosuilib/AltosDisplayThread.java b/altosuilib/AltosDisplayThread.java new file mode 100644 index 00000000..e88a891e --- /dev/null +++ b/altosuilib/AltosDisplayThread.java @@ -0,0 +1,259 @@ +/* + * 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.altosuilib_2; + +import java.awt.*; +import javax.swing.*; +import java.io.*; +import java.text.*; +import org.altusmetrum.altoslib_4.*; + +public class AltosDisplayThread 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	reported_landing; +		int	report_interval; +		long	report_time; + +		public synchronized void report(boolean last) { +			if (state == null) +				return; + +			/* reset the landing count once we hear about a new flight */ +			if (state.state < AltosLib.ao_flight_drogue) +				reported_landing = 0; + +			/* Shut up once the rocket is on the ground */ +			if (reported_landing > 2) { +				return; +			} + +			/* If the rocket isn't on the pad, then report height */ +			if (AltosLib.ao_flight_drogue <= state.state && +			    state.state < AltosLib.ao_flight_landed && +			    state.from_pad != null && +			    state.range >= 0) +			{ +				voice.speak("Height %s, bearing %s %d, elevation %d, range %s.\n", +					    AltosConvert.height.say(state.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 if (state.state > AltosLib.ao_flight_pad) { +				voice.speak(AltosConvert.height.say_units(state.height())); +			} else { +				reported_landing = 0; +			} + +			/* If the rocket is coming down, check to see if it has landed; +			 * either we've got a landed report or we haven't heard from it in +			 * a long time +			 */ +			if (state.state >= AltosLib.ao_flight_drogue && +			    (last || +			     System.currentTimeMillis() - state.received_time >= 15000 || +			     state.state == AltosLib.ao_flight_landed)) +			{ +				if (Math.abs(state.speed()) < 20 && state.height() < 100) +					voice.speak("rocket landed safely"); +				else +					voice.speak("rocket may have crashed"); +				if (state.from_pad != null) +					voice.speak("Bearing %d degrees, range %s.", +						    (int) (state.from_pad.bearing + 0.5), +						    AltosConvert.distance.say_units(state.from_pad.distance)); +				++reported_landing; +				if (state.state != AltosLib.ao_flight_landed) { +					state.state = AltosLib.ao_flight_landed; +					show_safely(); +				} +			} +		} + +		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() { +			reported_landing = 0; +			report_interval = 10000; +		} +	} + +	synchronized boolean tell() { +		boolean	ret = false; +		if (old_state == null || old_state.state != state.state) { +			voice.speak(state.state_name()); +			if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) && +			    state.state > AltosLib.ao_flight_boost) { +				voice.speak("max speed: %s.", +					    AltosConvert.speed.say_units(state.max_speed() + 0.5)); +				ret = true; +			} else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) && +				   state.state >= AltosLib.ao_flight_drogue) { +				voice.speak("max height: %s.", +					    AltosConvert.height.say_units(state.max_height() + 0.5)); +				ret = true; +			} +		} +		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 AltosDisplayThread(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(); +	} +} | 
