diff options
| -rw-r--r-- | altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 191 | ||||
| -rw-r--r-- | altoslib/AltosIdleMonitor.java | 443 | ||||
| -rw-r--r-- | altoslib/AltosIdleMonitorListener.java | 28 | ||||
| -rw-r--r-- | altoslib/AltosIdleRecordTM.java | 268 | ||||
| -rw-r--r-- | altoslib/AltosRecordMM.java | 8 | ||||
| -rw-r--r-- | altoslib/AltosState.java | 11 | ||||
| -rw-r--r-- | altoslib/AltosTelemetryReader.java | 5 | ||||
| -rw-r--r-- | altoslib/Makefile.am | 2 | ||||
| -rw-r--r-- | altosui/AltosIdleMonitorUI.java | 266 | ||||
| -rw-r--r-- | altosui/AltosIgnite.java | 19 | ||||
| -rw-r--r-- | altosui/AltosScanUI.java | 42 | ||||
| -rw-r--r-- | src/core/ao_monitor.c | 2 | ||||
| -rw-r--r-- | src/core/ao_telemetry.c | 4 | ||||
| -rw-r--r-- | src/drivers/ao_cc1120_CC1120.h | 2 | 
14 files changed, 1008 insertions, 283 deletions
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java new file mode 100644 index 00000000..45438a6c --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -0,0 +1,191 @@ +/* + * Copyright © 2011 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.AltosDroid; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Method; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import org.altusmetrum.AltosLib.*; + +public class AltosBluetooth extends AltosLink { + +	// Debugging +	private static final String TAG = "AltosBluetooth"; +	private static final boolean D = true; + +	/** +	 * This thread runs while attempting to make an outgoing connection +	 * with a device. It runs straight through; the connection either +	 * succeeds or fails. +	 */ + +	private BluetoothAdapter	adapter; +	private ConnectThread		connect_thread; +	private BluetoothSocket		socket; +	private InputStream		input; +	private OutputStream		output; + +	private class ConnectThread extends Thread { +		private final BluetoothDevice mmDevice; +		private String mSocketType; +		BluetoothSocket tmp_socket; + +		public ConnectThread(BluetoothDevice device, boolean secure) { +			mmDevice = device; +			mSocketType = secure ? "Secure" : "Insecure"; + +			// Get a BluetoothSocket for a connection with the +			// given BluetoothDevice +			try { +				if (secure) { +					Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}); +					tmp_socket = (BluetoothSocket) m.invoke(device, 2); +					// tmp = device.createRfcommSocket(2); +				} else { +					Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class}); +					tmp_socket = (BluetoothSocket) m.invoke(device, 2); +					// tmp = device.createInsecureRfcommSocket(2); +				} +			} catch (Exception e) { +				Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e); +				e.printStackTrace(); +			} +		} + +		public void run() { +			Log.i(TAG, "BEGIN connect_thread SocketType:" + mSocketType); +			setName("ConnectThread" + mSocketType); + +			// Always cancel discovery because it will slow down a connection +			adapter.cancelDiscovery(); + +			// Make a connection to the BluetoothSocket +			try { +				// This is a blocking call and will only return on a +				// successful connection or an exception +				tmp_socket.connect(); +			} catch (IOException e) { +				// Close the socket +				try { +					tmp_socket.close(); +				} catch (IOException e2) { +					Log.e(TAG, "unable to close() " + mSocketType + +					      " socket during connection failure", e2); +				} +				connection_failed(); +				return; +			} + +			try { +				synchronized (AltosBluetooth.this) { +					input = tmp_socket.getInputStream(); +					output = tmp_socket.getOutputStream(); +					socket = tmp_socket; +					// Reset the ConnectThread because we're done +					AltosBluetooth.this.notify(); +					connect_thread = null; +				} +			} catch (Exception e) { +				Log.e(TAG, "Failed to finish connection", e); +				e.printStackTrace(); +			} +		} + +		public void cancel() { +			try { +				if (tmp_socket != null) +					tmp_socket.close(); +			} catch (IOException e) { +				Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e); +			} +		} +	} + +	private synchronized void wait_connected() throws InterruptedException { +		if (input == null) { +			wait(); +		} +	} + +	private void connection_failed() { +	} +	 +	public void print(String data) { +		byte[] bytes = data.getBytes(); +		try { +			wait_connected(); +			output.write(bytes); +		} catch (IOException e) { +			connection_failed(); +		} catch (InterruptedException e) { +			connection_failed(); +		} +	} + +	public int getchar() { +		try { +			wait_connected(); +			return input.read(); +		} catch (IOException e) { +			connection_failed(); +		} catch (java.lang.InterruptedException e) { +			connection_failed(); +		} +		return AltosLink.ERROR; +	} +			 +	public void close() { +		synchronized(this) { +			if (connect_thread != null) { +				connect_thread.cancel(); +				connect_thread = null; +			} +		} +	} + +	public void flush_output() { +		super.flush_output(); +		/* any local work needed to flush bluetooth? */ +	} + +	public boolean can_cancel_reply() { +		return false; +	} +	public boolean show_reply_timeout() { +		return true; +	} +		 +	public void hide_reply_timeout() { +	} + +	public AltosBluetooth(BluetoothDevice device) { +		adapter = BluetoothAdapter.getDefaultAdapter(); +		connect_thread = new ConnectThread(device, true); +		connect_thread.start(); +	} +}
\ No newline at end of file diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java new file mode 100644 index 00000000..57c4da71 --- /dev/null +++ b/altoslib/AltosIdleMonitor.java @@ -0,0 +1,443 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosSensorTM { +	int	tick; +	int	accel; +	int	pres; +	int	temp; +	int	batt; +	int	drogue; +	int	main; + +	public AltosSensorTM(AltosLink link) throws InterruptedException, TimeoutException { +		link.printf("a\n"); +		for (;;) { +			String line = link.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; +				} +				i++; +			} +			break; +		} +	} +} + +class AltosSensorMM { +	int		tick; +	int		sense[]; +	int		v_batt; +	int		v_pyro; +	int		accel; +	int		accel_ref; + +	public AltosSensorMM(AltosLink link) throws InterruptedException, TimeoutException { +		link.printf("a\n"); +		for (;;) { +			String line = link.get_reply_no_dialog(5000); +			if (line == null) { +				throw new TimeoutException(); +			} +			if (!line.startsWith("tick:")) +				continue; +			String[] items = line.split("\\s+"); +			sense = new int[6]; +			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("0:")) { +					sense[0] = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("1:")) { +					sense[1] = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("2:")) { +					sense[2] = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("3:")) { +					sense[3] = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("4:")) { +					sense[4] = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("5:")) { +					sense[5] = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("6:")) { +					v_batt = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("7:")) { +					v_pyro = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("8:")) { +					accel = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				if (items[i].equals("9:")) { +					accel_ref = Integer.parseInt(items[i+1]); +					i += 2; +					continue; +				} +				i++; +			} +			break; +		} +	} +} + +class AltosIMUQuery extends AltosIMU { + +	public AltosIMUQuery (AltosLink link) throws InterruptedException, TimeoutException { +		link.printf("I\n"); +		for (;;) { +			String line = link.get_reply_no_dialog(5000); +			if (line == null) { +				throw new TimeoutException(); +			} +			if (!line.startsWith("Accel:")) +				continue; +			String[] items = line.split("\\s+"); +			if (items.length >= 8) { +				accel_x = Integer.parseInt(items[1]); +				accel_y = Integer.parseInt(items[2]); +				accel_z = Integer.parseInt(items[3]); +				gyro_x = Integer.parseInt(items[5]); +				gyro_y = Integer.parseInt(items[6]); +				gyro_z = Integer.parseInt(items[7]); +			} +			break; +		} +	} +} + +class AltosMs5607Query extends AltosMs5607 { +	public AltosMs5607Query (AltosLink link) throws InterruptedException, TimeoutException { +		link.printf("v\nB\n"); +		for (;;) { +			String line = link.get_reply_no_dialog(5000); +			if (line == null) { +				throw new TimeoutException(); +			} +			String[] items = line.split("\\s+"); +			if (line.startsWith("Pressure:")) { +				if (items.length >= 2) +					raw_pres = Integer.parseInt(items[1]); +			} else if (line.startsWith("Temperature:")) { +				if (items.length >= 2) +					raw_temp = Integer.parseInt(items[1]); +			} else if (line.startsWith("ms5607 reserved:")) { +				if (items.length >= 3) +					reserved = Integer.parseInt(items[2]); +			} else if (line.startsWith("ms5607 sens:")) { +				if (items.length >= 3) +					sens = Integer.parseInt(items[2]); +			} else if (line.startsWith("ms5607 off:")) { +				if (items.length >= 3) +					off = Integer.parseInt(items[2]); +			} else if (line.startsWith("ms5607 tcs:")) { +				if (items.length >= 3) +					tcs = Integer.parseInt(items[2]); +			} else if (line.startsWith("ms5607 tco:")) { +				if (items.length >= 3) +					tco = Integer.parseInt(items[2]); +			} else if (line.startsWith("ms5607 tref:")) { +				if (items.length >= 3) +					tref = Integer.parseInt(items[2]); +			} else if (line.startsWith("ms5607 tempsens:")) { +				if (items.length >= 3) +					tempsens = Integer.parseInt(items[2]); +			} else if (line.startsWith("ms5607 crc:")) { +				if (items.length >= 3) +					crc = Integer.parseInt(items[2]); +			} else if (line.startsWith("Altitude")) +				break; +		} +		convert(); +	} +} + +class AltosGPSQuery extends AltosGPS { +	public AltosGPSQuery (AltosLink link, AltosConfigData config_data) +		throws TimeoutException, InterruptedException { +		boolean says_done = config_data.compare_version("1.0") >= 0; +		link.printf("g\n"); +		for (;;) { +			String line = link.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 & AltosLib.AO_GPS_RUNNING) != 0; +				locked = (status & AltosLib.AO_GPS_VALID) != 0; +				if (!says_done) +					break; +				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; +		} +	} +} + +public class AltosIdleMonitor extends Thread { +	AltosLink		link; +	AltosIdleMonitorListener	listener; +	AltosState		state; +	boolean			remote; +	double			frequency; +	AltosState		previous_state; +	AltosConfigData		config_data; +	AltosGPS		gps; + +	int AltosRSSI() throws TimeoutException, InterruptedException { +		link.printf("s\n"); +		String line = link.get_reply_no_dialog(5000); +		if (line == null) +			throw new TimeoutException(); +		String[] items = line.split("\\s+"); +		if (items.length < 2) +			return 0; +		if (!items[0].equals("RSSI:")) +			return 0; +		int rssi = Integer.parseInt(items[1]); +		return rssi; +	} + +	void update_state() throws InterruptedException, TimeoutException { +		AltosRecord	record; +		int		rssi; + +		try { +			if (remote) { +				link.set_radio_frequency(frequency); +				link.start_remote(); +			} else +				link.flush_input(); +			config_data = new AltosConfigData(link); +			if (config_data.product.startsWith("TeleMetrum")) { +				AltosRecordTM record_tm = new AltosRecordTM(); +				AltosSensorTM sensor = new AltosSensorTM(link); +				record_tm.accel = sensor.accel; +				record_tm.pres = sensor.pres; +				record_tm.batt = sensor.batt; +				record_tm.temp = sensor.temp; +				record_tm.drogue = sensor.drogue; +				record_tm.main = sensor.main; +				record_tm.ground_accel = record_tm.accel; +				record_tm.ground_pres = record_tm.pres; +				record_tm.accel_plus_g = config_data.accel_cal_plus; +				record_tm.accel_minus_g = config_data.accel_cal_minus; +				record_tm.tick = sensor.tick; +				record = record_tm; +			} else if (config_data.product.startsWith("MegaMetrum")) { +				AltosRecordMM record_mm = new AltosRecordMM(); +				AltosSensorMM sensor = new AltosSensorMM(link); +				AltosMs5607 ms5607 = new AltosMs5607Query(link); +				AltosIMU imu = new AltosIMUQuery(link); + +				record_mm.accel_plus_g = config_data.accel_cal_plus; +				record_mm.accel_minus_g = config_data.accel_cal_minus; + +				record_mm.ground_accel = sensor.accel; +				record_mm.accel = sensor.accel; +				record_mm.ground_pres = ms5607.pa; +				record_mm.pres = ms5607.pa; +				record_mm.temp = ms5607.cc; + +				record_mm.v_batt = sensor.v_batt; +				record_mm.v_pyro = sensor.v_pyro; +				record_mm.sense = sensor.sense; + +				record_mm.imu = imu; + +				record = record_mm; +			} else +				record = new AltosRecord(); + +			gps = new AltosGPSQuery(link, config_data); +		} finally { +			if (remote) { +				link.stop_remote(); +				rssi = AltosRSSI(); +			} else +				rssi = 0; +		} + +		record.version = 0; +		record.callsign = config_data.callsign; +		record.serial = config_data.serial; +		record.flight = config_data.log_available() > 0 ? 255 : 0; +		record.rssi = rssi; +		record.status = 0; +		record.state = AltosLib.ao_flight_idle; + +		record.gps = gps; +		state = new AltosState (record, state); +	} + +	public void set_frequency(double in_frequency) { +		frequency = in_frequency; +	} + +	public void post_state() { +		listener.update(state); +	} + +	public void run() { +		try { +			for (;;) { +				try { +					update_state(); +					post_state(); +				} catch (TimeoutException te) { +				} +				Thread.sleep(1000); +			} +		} catch (InterruptedException ie) { +			link.close(); +		} +	} + +	public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) +		throws FileNotFoundException, InterruptedException, TimeoutException { +		listener = in_listener; +		link = in_link; +		remote = in_remote; +		state = null; +	} +} diff --git a/altoslib/AltosIdleMonitorListener.java b/altoslib/AltosIdleMonitorListener.java new file mode 100644 index 00000000..3c18bfaa --- /dev/null +++ b/altoslib/AltosIdleMonitorListener.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public interface AltosIdleMonitorListener { +	public void update(AltosState state); +}
\ No newline at end of file diff --git a/altoslib/AltosIdleRecordTM.java b/altoslib/AltosIdleRecordTM.java new file mode 100644 index 00000000..112b847e --- /dev/null +++ b/altoslib/AltosIdleRecordTM.java @@ -0,0 +1,268 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosADCTM { +	int	tick; +	int	accel; +	int	pres; +	int	temp; +	int	batt; +	int	drogue; +	int	main; + +	public AltosADCTM(AltosLink link) throws InterruptedException, TimeoutException { +		link.printf("a\n"); +		for (;;) { +			String line = link.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; +				} +				i++; +			} +			break; +		} +	} +} + +class AltosGPSQuery extends AltosGPS { +	public AltosGPSQuery (AltosLink link, AltosConfigData config_data) +		throws TimeoutException, InterruptedException { +		boolean says_done = config_data.compare_version("1.0") >= 0; +		link.printf("g\n"); +		for (;;) { +			String line = link.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 & AltosLib.AO_GPS_RUNNING) != 0; +				locked = (status & AltosLib.AO_GPS_VALID) != 0; +				if (!says_done) +					break; +				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; +		} +	} +} + +public class AltosIdleMonitor extends Thread { +	AltosLink		link; +	AltosIdleMonitorListener	listener; +	AltosState		state; +	boolean			remote; +	double			frequency; +	AltosState		previous_state; +	AltosConfigData		config_data; +	AltosADC		adc; +	AltosGPS		gps; + +	int AltosRSSI() throws TimeoutException, InterruptedException { +		link.printf("s\n"); +		String line = link.get_reply_no_dialog(5000); +		if (line == null) +			throw new TimeoutException(); +		String[] items = line.split("\\s+"); +		if (items.length < 2) +			return 0; +		if (!items[0].equals("RSSI:")) +			return 0; +		int rssi = Integer.parseInt(items[1]); +		return rssi; +	} + +	void update_state() throws InterruptedException, TimeoutException { +		AltosRecordTM	record = new AltosRecordTM(); +		int		rssi; + +		try { +			if (remote) { +				link.set_radio_frequency(frequency); +				link.start_remote(); +			} else +				link.flush_input(); +			config_data = new AltosConfigData(link); +			adc = new AltosADC(link); +			gps = new AltosGPSQuery(link, config_data); +		} finally { +			if (remote) { +				link.stop_remote(); +				rssi = AltosRSSI(); +			} else +				rssi = 0; +		} + +		record.version = 0; +		record.callsign = config_data.callsign; +		record.serial = config_data.serial; +		record.flight = config_data.log_available() > 0 ? 255 : 0; +		record.rssi = rssi; +		record.status = 0; +		record.state = AltosLib.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); +	} + +	public void set_frequency(double in_frequency) { +		frequency = in_frequency; +	} + +	public void post_state() { +		listener.update(state); +	} + +	public void run() { +		try { +			for (;;) { +				try { +					update_state(); +					post_state(); +				} catch (TimeoutException te) { +				} +				Thread.sleep(1000); +			} +		} catch (InterruptedException ie) { +			link.close(); +		} +	} + +	public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) +		throws FileNotFoundException, InterruptedException, TimeoutException { +		listener = in_listener; +		link = in_link; +		remote = in_remote; +		state = null; +	} +} diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java index 055cf85f..5f952f7a 100644 --- a/altoslib/AltosRecordMM.java +++ b/altoslib/AltosRecordMM.java @@ -47,7 +47,7 @@ public class AltosRecordMM extends AltosRecord {  	public double raw_pressure() {  		if (pres != MISSING) -			return pres / 100.0; +			return pres;  		return MISSING;  	} @@ -57,19 +57,19 @@ public class AltosRecordMM extends AltosRecord {  	public double ground_pressure() {  		if (ground_pres != MISSING) -			return ground_pres / 100.0; +			return ground_pres;  		return MISSING;  	}  	public double battery_voltage() {  		if (v_batt != MISSING) -			return 3.3 * adc(v_batt) * 27.0 / (15.0 + 27.0); +			return 3.3 * adc(v_batt) * (15.0 + 27.0) / 27.0;  		return MISSING;  	}  	static double pyro(int raw) {  		if (raw != MISSING) -			return 3.3 * adc(raw) * 27.0 / (100.0 + 27.0); +			return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0;  		return MISSING;  	} diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 68c7611f..e20ec9a7 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -160,7 +160,8 @@ public class AltosState {  				}  				ngps++;  			} -		} +		} else +			pad_alt = ground_altitude;  		gps_waiting = MIN_PAD_SAMPLES - npad;  		if (gps_waiting < 0) @@ -173,14 +174,14 @@ public class AltosState {  		boost = (AltosLib.ao_flight_boost == state);  		/* Only look at accelerometer data under boost */ -		if (boost && acceleration > max_acceleration) +		if (boost && acceleration > max_acceleration && acceleration != AltosRecord.MISSING)  			max_acceleration = acceleration; -		if (boost && speed > max_speed) +		if (boost && speed > max_speed && speed != AltosRecord.MISSING)  			max_speed = speed; -		if (boost && baro_speed > max_baro_speed) +		if (boost && baro_speed > max_baro_speed && baro_speed != AltosRecord.MISSING)  			max_baro_speed = baro_speed; -		if (height > max_height) +		if (height > max_height && height != AltosRecord.MISSING)  			max_height = height;  		if (data.gps != null) {  			if (gps == null || !gps.locked || data.gps.locked) diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 911a099a..bdb44eef 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -44,6 +44,11 @@ public class AltosTelemetryReader extends AltosFlightReader {  		telem.clear();  	} +	public void reset() { +		previous = null; +		flush(); +	} +  	public void close(boolean interrupted) {  		link.remove_monitor(telem);  		log.close(); diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index ac97c9cb..a39623ee 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -27,6 +27,8 @@ AltosLib_JAVA = \  	$(SRC)/AltosGPS.java \  	$(SRC)/AltosGPSSat.java \  	$(SRC)/AltosGreatCircle.java \ +	$(SRC)/AltosIdleMonitor.java \ +	$(SRC)/AltosIdleMonitorListener.java \  	$(SRC)/AltosLine.java \  	$(SRC)/AltosLink.java \  	$(SRC)/AltosLog.java \ diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index ce608d2b..46ca3e5d 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -29,260 +29,7 @@ import java.util.prefs.*;  import java.util.concurrent.*;  import org.altusmetrum.AltosLib.*; -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; -				} -				i++; -			} -			break; -		} -	} -} - -class AltosGPSQuery extends AltosGPS { -	public AltosGPSQuery (AltosSerial serial, AltosConfigData config_data) -		throws TimeoutException, InterruptedException { -		boolean says_done = config_data.compare_version("1.0") >= 0; -		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; -				if (!says_done) -					break; -				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; -	double			frequency; -	AltosState		previous_state; -	AltosConfigData		config_data; -	AltosADC		adc; -	AltosGPS		gps; - -	int AltosRSSI() throws TimeoutException, InterruptedException { -		serial.printf("s\n"); -		String line = serial.get_reply_no_dialog(5000); -		if (line == null) -			throw new TimeoutException(); -		String[] items = line.split("\\s+"); -		if (items.length < 2) -			return 0; -		if (!items[0].equals("RSSI:")) -			return 0; -		int rssi = Integer.parseInt(items[1]); -		return rssi; -	} - -	void update_state() throws InterruptedException, TimeoutException { -		AltosRecordTM	record = new AltosRecordTM(); -		int		rssi; - -		try { -			if (remote) { -				serial.set_radio_frequency(frequency); -				serial.start_remote(); -			} else -				serial.flush_input(); -			config_data = new AltosConfigData(serial); -			adc = new AltosADC(serial); -			gps = new AltosGPSQuery(serial, config_data); -		} finally { -			if (remote) { -				serial.stop_remote(); -				rssi = AltosRSSI(); -			} else -				rssi = 0; -		} - -		record.version = 0; -		record.callsign = config_data.callsign; -		record.serial = config_data.serial; -		record.flight = config_data.log_available() > 0 ? 255 : 0; -		record.rssi = rssi; -		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_frequency(double in_frequency) { -		frequency = in_frequency; -	} - -	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) { -					if (AltosSerial.debug) -						System.out.printf ("monitor idle data timeout\n"); -				} -				Thread.sleep(1000); -			} -		} catch (InterruptedException ie) { -			serial.close(); -		} -	} - -	public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote) -		throws FileNotFoundException, AltosSerialInUseException, InterruptedException, TimeoutException { -		device = in_device; -		ui = in_ui; -		serial = new AltosSerial(device); -		remote = in_remote; -		state = null; -	} -} - -public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { +public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener, AltosIdleMonitorListener {  	AltosDevice		device;  	JTabbedPane		pane;  	AltosPad		pad; @@ -333,8 +80,13 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay  		}  	} -	public void update(AltosState state) { -		show (state, 0); +	public void update(final AltosState state) { +		Runnable r = new Runnable() { +				public void run() { +					show(state, 0); +				} +			}; +		SwingUtilities.invokeLater(r);  	}  	Container	bag; @@ -427,7 +179,7 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay  		pack();  		setVisible(true); -		thread = new AltosIdleMonitor(this, device, remote); +		thread = new AltosIdleMonitor((AltosIdleMonitorListener) this, (AltosLink) new AltosSerial (device), (boolean) remote);  		status_update = new AltosFlightStatusUpdate(flightStatus); diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index 45d37d16..f84db0b9 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -110,12 +110,23 @@ public class AltosIgnite {  				String line = serial.get_reply(5000);  				if (line == null)  					throw new TimeoutException(); -				if (get_string(line, "Igniter: drogue Status: ", status_name)) +				String[] items = line.split("\\s+"); + +				if (items.length < 4) +					continue; + +				if (!items[0].equals("Igniter:")) +					continue; + +				if (!items[2].equals("Status:")) +					continue; + +				if (items[1].equals("drogue")) {  					if (igniter == Apogee) -						status = status(status_name.get()); -				if (get_string(line, "Igniter:   main Status: ", status_name)) { +						status = status(items[3]); +				} else if (items[1].equals("main")) {  					if (igniter == Main) -						status = status(status_name.get()); +						status = status(items[3]);  					break;  				}  			} diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 44eeda6d..ef6389b6 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -59,29 +59,50 @@ class AltosScanResult {  	}  	public boolean equals(AltosScanResult other) { -		return (callsign.equals(other.callsign) && -			serial == other.serial && -			flight == other.flight && +		return (serial == other.serial &&  			frequency.frequency == other.frequency.frequency &&  			telemetry == other.telemetry);  	} + +	public boolean up_to_date(AltosScanResult other) { +		if (flight == 0 && other.flight != 0) { +			flight = other.flight; +			return false; +		} +		if (callsign.equals("N0CALL") && !other.callsign.equals("N0CALL")) { +			callsign = other.callsign; +			return false; +		} +		return true; +	}  }  class AltosScanResults extends LinkedList<AltosScanResult> implements ListModel {  	LinkedList<ListDataListener>	listeners = new LinkedList<ListDataListener>(); +	void changed(ListDataEvent de) { +		for (ListDataListener l : listeners) +			l.contentsChanged(de); +	} +  	public boolean add(AltosScanResult r) { -		for (AltosScanResult old : this) -			if (old.equals(r)) +		int i = 0; +		for (AltosScanResult old : this) { +			if (old.equals(r)) { +				if (!old.up_to_date(r)) +					changed (new ListDataEvent(this, +								   ListDataEvent.CONTENTS_CHANGED, +								   i, i));  				return true; +			} +			i++; +		}  		super.add(r); -		ListDataEvent	de = new ListDataEvent(this, -						       ListDataEvent.INTERVAL_ADDED, -						       this.size() - 2, this.size() - 1); -		for (ListDataListener l : listeners) -			l.contentsChanged(de); +		changed(new ListDataEvent(this, +					  ListDataEvent.INTERVAL_ADDED, +					  this.size() - 2, this.size() - 1));  		return true;  	} @@ -205,6 +226,7 @@ public class AltosScanUI  	void set_frequency() throws InterruptedException, TimeoutException {  		reader.set_frequency(frequencies[frequency_index].frequency); +		reader.reset();  	}  	void next() throws InterruptedException, TimeoutException { diff --git a/src/core/ao_monitor.c b/src/core/ao_monitor.c index d492e32a..5876bef7 100644 --- a/src/core/ao_monitor.c +++ b/src/core/ao_monitor.c @@ -132,6 +132,8 @@ ao_monitor_put(void)  			ao_sleep(DATA_TO_XDATA(&ao_external_monitoring));  		while (ao_monitor_tail == ao_monitor_head && ao_external_monitoring)  			ao_sleep(DATA_TO_XDATA(&ao_monitor_head)); +		if (!ao_external_monitoring) +			continue;  		m = &ao_monitor_ring[ao_monitor_tail];  		ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail);  		switch (ao_monitoring) { diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c index 583a6636..52ac9489 100644 --- a/src/core/ao_telemetry.c +++ b/src/core/ao_telemetry.c @@ -138,9 +138,9 @@ ao_send_mega_data(void)  		telemetry.mega_data.v_batt = packet->adc.v_batt;  		telemetry.mega_data.v_pyro = packet->adc.v_pbatt; -		/* XXX figure out right shift value; 4 might suffice */ +		/* ADC range is 0-4095, so shift by four to save the high 8 bits */  		for (i = 0; i < AO_ADC_NUM_SENSE; i++) -			telemetry.mega_data.sense[i] = packet->adc.sense[i] >> 8; +			telemetry.mega_data.sense[i] = packet->adc.sense[i] >> 4;  		telemetry.mega_data.ground_pres = ao_ground_pres;  		telemetry.mega_data.ground_accel = ao_ground_accel; diff --git a/src/drivers/ao_cc1120_CC1120.h b/src/drivers/ao_cc1120_CC1120.h index 5376afd5..44cca938 100644 --- a/src/drivers/ao_cc1120_CC1120.h +++ b/src/drivers/ao_cc1120_CC1120.h @@ -83,7 +83,7 @@          CC1120_RFEND_CFG1,                     0x0f,       /* RFEND Configuration, Reg 1 */
          CC1120_RFEND_CFG0,                     0x00,       /* RFEND Configuration, Reg 0 */
  	//        CC1120_PA_CFG2,                        0x3f,       /* Power Amplifier Configuration, Reg 2 */
 -	CC1120_PA_CFG2,                        0x04,       /* Power Amplifier Configuration, Reg 2 */
 +	CC1120_PA_CFG2,                        0x3f,       /* Power Amplifier Configuration, Reg 2 */
          CC1120_PA_CFG1,                        0x56,       /* Power Amplifier Configuration, Reg 1 */
          CC1120_PA_CFG0,                        0x7b,       /* Power Amplifier Configuration, Reg 0 */
          CC1120_PKT_LEN,                        0xff,       /* Packet Length Configuration */
  | 
