diff options
| author | Keith Packard <keithp@keithp.com> | 2011-08-02 17:41:53 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2011-08-02 18:03:37 -0700 | 
| commit | 11a2bb8e28df7ed87542f2ee726f877971f5d52a (patch) | |
| tree | 96be4771790576383c143213649b3eebc10e9697 | |
| parent | 3cc2eed6cdafe788a8617ab45c6664077e76411e (diff) | |
altosui: Add idle monitor dialog
This monitors a telemetrum device in idle mode, either directly or through a
teledongle, allowing the GPS status and batteries to be monitored
without resorting to placing the device in pad mode.
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | altosui/AltosIdleMonitorUI.java | 388 | ||||
| -rw-r--r-- | altosui/AltosState.java | 2 | ||||
| -rw-r--r-- | altosui/AltosUI.java | 14 | ||||
| -rw-r--r-- | altosui/Makefile.am | 1 | 
4 files changed, 404 insertions, 1 deletions
| diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java new file mode 100644 index 00000000..a4262cae --- /dev/null +++ b/altosui/AltosIdleMonitorUI.java @@ -0,0 +1,388 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosADC { +	int	tick; +	int	accel; +	int	pres; +	int	temp; +	int	batt; +	int	drogue; +	int	main; + +	public AltosADC(AltosSerial serial) throws InterruptedException, TimeoutException { +		serial.printf("a\n"); +		for (;;) { +			String line = serial.get_reply_no_dialog(5000); +			if (line == null) { +				throw new TimeoutException(); +			} +			if (!line.startsWith("tick:")) +				continue; +			String[] items = line.split("\\s+"); +			for (int i = 0; i < items.length;) { +				if (items[i].equals("tick:")) { +					tick = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("accel:")) { +					accel = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("pres:")) { +					pres = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("temp:")) { +					temp = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("batt:")) { +					batt = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("drogue:")) { +					drogue = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("main:")) { +					main = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +			} +			break; +		} +	} +} + +class AltosGPSQuery extends AltosGPS { +	public AltosGPSQuery (AltosSerial serial) throws TimeoutException, InterruptedException { +		serial.printf("g\n"); +		for (;;) { +			String line = serial.get_reply_no_dialog(5000); +			if (line == null) +				throw new TimeoutException(); +			String[] bits = line.split("\\s+"); +			if (bits.length == 0) +				continue; +			if (line.startsWith("Date:")) { +				if (bits.length < 2) +					continue; +				String[] d = bits[1].split(":"); +				if (d.length < 3) +					continue; +				year = Integer.parseInt(d[0]) + 2000; +				month = Integer.parseInt(d[1]); +				day = Integer.parseInt(d[2]); +				continue; +			} +			if (line.startsWith("Time:")) { +				if (bits.length < 2) +					continue; +				String[] d = bits[1].split("/"); +				if (d.length < 3) +					continue; +				hour = Integer.parseInt(d[0]); +				minute = Integer.parseInt(d[1]); +				second = Integer.parseInt(d[2]); +				continue; +			} +			if (line.startsWith("Lat/Lon:")) { +				if (bits.length < 3) +					continue; +				lat = Integer.parseInt(bits[1]) * 1.0e-7; +				lon = Integer.parseInt(bits[2]) * 1.0e-7; +				continue; +			} +			if (line.startsWith("Alt:")) { +				if (bits.length < 2) +					continue; +				alt = Integer.parseInt(bits[1]); +				continue; +			} +			if (line.startsWith("Flags:")) { +				if (bits.length < 2) +					continue; +				int status = Integer.decode(bits[1]); +				connected = (status & Altos.AO_GPS_RUNNING) != 0; +				locked = (status & Altos.AO_GPS_VALID) != 0; +				continue; +			} +			if (line.startsWith("Sats:")) { +				if (bits.length < 2) +					continue; +				nsat = Integer.parseInt(bits[1]); +				cc_gps_sat = new AltosGPSSat[nsat]; +				for (int i = 0; i < nsat; i++) { +					int	svid = Integer.parseInt(bits[2+i*2]); +					int	cc_n0 = Integer.parseInt(bits[3+i*2]); +					cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0); +				} +			} +			if (line.startsWith("done")) +				break; +			if (line.startsWith("Syntax error")) +				break; +		} +	} +} + +class AltosIdleMonitor extends Thread { +	AltosDevice		device; +	AltosSerial		serial; +	AltosIdleMonitorUI	ui; +	AltosState		state; +	boolean			remote; +	int			channel; +	AltosState		previous_state; +	AltosConfigData		config_data; +	AltosADC		adc; +	AltosGPS		gps; + +	void update_state() throws InterruptedException, TimeoutException { +		AltosRecord	record = new AltosRecord(); + +		try { +			if (remote) { +				set_channel(channel); +				serial.start_remote(); +			} else +				serial.flush_input(); +			config_data = new AltosConfigData(serial); +			adc = new AltosADC(serial); +			gps = new AltosGPSQuery(serial); +		} finally { +			if (remote) +				serial.stop_remote(); +		} + +		record.version = 0; +		record.callsign = config_data.callsign; +		record.serial = config_data.serial; +		record.flight = 0; +		record.rssi = 0; +		record.status = 0; +		record.state = Altos.ao_flight_idle; + +		record.tick = adc.tick; +		record.accel = adc.accel; +		record.pres = adc.pres; +		record.batt = adc.batt; +		record.temp = adc.temp; +		record.drogue = adc.drogue; +		record.main = adc.main; + +		record.ground_accel = record.accel; +		record.ground_pres = record.pres; +		record.accel_plus_g = config_data.accel_cal_plus; +		record.accel_minus_g = config_data.accel_cal_minus; +		record.acceleration = 0; +		record.speed = 0; +		record.height = 0; +		record.gps = gps; +		state = new AltosState (record, state); +	} + +	void set_channel(int in_channel) { +		channel = in_channel; +	} + +	public void post_state() { +		Runnable r = new Runnable() { +				public void run() { +					ui.update(state); +				} +			}; +		SwingUtilities.invokeLater(r); +	} + +	public void run() { +		try { +			for (;;) { +				try { +					update_state(); +					post_state(); +				} catch (TimeoutException te) { +				} +				Thread.sleep(1000); +			} +		} catch (InterruptedException ie) { +			serial.close(); +		} +	} + +	public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote) +		throws FileNotFoundException, AltosSerialInUseException { +		device = in_device; +		ui = in_ui; +		serial = new AltosSerial(device); +		remote = in_remote; +		state = null; +	} +} + +public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { +	AltosDevice		device; +	JTabbedPane		pane; +	AltosPad		pad; +	AltosInfoTable		flightInfo; +	AltosFlightStatus	flightStatus; +	AltosIdleMonitor	thread; +	int			serial; +	boolean			remote; + +	void stop_display() { +		if (thread != null && thread.isAlive()) { +			thread.interrupt(); +			try { +				thread.join(); +			} catch (InterruptedException ie) {} +		} +		thread = null; +	} + +	void disconnect() { +		stop_display(); +	} + +	public void reset() { +		pad.reset(); +		flightInfo.clear(); +	} + +	public void show(AltosState state, int crc_errors) { +		try { +			pad.show(state, crc_errors); +			flightStatus.show(state, crc_errors); +			flightInfo.show(state, crc_errors); +		} catch (Exception e) { +			System.out.print("Show exception" + e); +		} +	} + +	public void update(AltosState state) { +		show (state, 0); +	} + +	Container	bag; +	JComboBox	channels; + +	public AltosIdleMonitorUI(JFrame in_owner) throws FileNotFoundException, AltosSerialInUseException { + +		device = AltosDeviceDialog.show(in_owner, Altos.product_any); +		remote = false; +		if (!device.matchProduct(Altos.product_telemetrum)) +			remote = true; + +		serial = device.getSerial(); +		bag = getContentPane(); +		bag.setLayout(new GridBagLayout()); + +		GridBagConstraints c = new GridBagConstraints(); + +		java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg"); +		if (imgURL != null) +			setIconImage(new ImageIcon(imgURL).getImage()); + +		setTitle(String.format("AltOS %s", device.toShortString())); + +		/* Stick channel selector at top of table for telemetry monitoring */ +		if (remote && serial >= 0) { +			// Channel menu +			channels = new AltosChannelMenu(AltosPreferences.channel(serial)); +			channels.addActionListener(new ActionListener() { +				public void actionPerformed(ActionEvent e) { +					int channel = channels.getSelectedIndex(); +					thread.set_channel(channel); +				} +			}); +			c.gridx = 0; +			c.gridy = 0; +			c.insets = new Insets(3, 3, 3, 3); +			c.anchor = GridBagConstraints.WEST; +			bag.add (channels, c); +		} + + +		/* Flight status is always visible */ +		flightStatus = new AltosFlightStatus(); +		c.gridx = 0; +		c.gridy = 1; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.gridwidth = 2; +		bag.add(flightStatus, c); +		c.gridwidth = 1; + +		/* The rest of the window uses a tabbed pane to +		 * show one of the alternate data views +		 */ +		pane = new JTabbedPane(); + +		pad = new AltosPad(); +		pane.add("Launch Pad", pad); + +		flightInfo = new AltosInfoTable(); +		pane.add("Table", new JScrollPane(flightInfo)); + +		/* Make the tabbed pane use the rest of the window space */ +		c.gridx = 0; +		c.gridy = 2; +		c.fill = GridBagConstraints.BOTH; +		c.weightx = 1; +		c.weighty = 1; +		c.gridwidth = 2; +		bag.add(pane, c); + +		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); +		addWindowListener(new WindowAdapter() { +				@Override +				public void windowClosing(WindowEvent e) { +					disconnect(); +					setVisible(false); +					dispose(); +				} +			}); + +		pack(); +		setVisible(true); + +		thread = new AltosIdleMonitor(this, device, remote); + +		thread.start(); +	} +} diff --git a/altosui/AltosState.java b/altosui/AltosState.java index 0ff2479e..d374aed8 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -130,7 +130,7 @@ public class AltosState {  			time_change = 0;  		} -		if (state == Altos.ao_flight_pad) { +		if (state == Altos.ao_flight_pad || state == Altos.ao_flight_idle) {  			/* Track consecutive 'good' gps reports, waiting for 10 of them */  			if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index d8c8d61c..9b724fd7 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -187,6 +187,13 @@ public class AltosUI extends JFrame {  				}  			}); +		b = addButton(2, 2, "Monitor Idle"); +		b.addActionListener(new ActionListener() { +				public void actionPerformed(ActionEvent e) { +					IdleMonitor(); +				} +			}); +  		setTitle("AltOS");  		pane.doLayout(); @@ -300,6 +307,13 @@ public class AltosUI extends JFrame {  		new AltosConfigureUI(AltosUI.this, voice);  	} +	private void IdleMonitor() { +		try { +			new AltosIdleMonitorUI(this); +		} catch (Exception e) { +		} +	} +  	static AltosRecordIterable open_logfile(String filename) {  		File file = new File (filename);  		try { diff --git a/altosui/Makefile.am b/altosui/Makefile.am index e3075d41..008bd097 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -55,6 +55,7 @@ altosui_JAVA = \  	AltosGreatCircle.java \  	AltosHexfile.java \  	Altos.java \ +	AltosIdleMonitorUI.java \  	AltosIgnite.java \  	AltosIgniteUI.java \  	AltosInfoTable.java \ | 
