diff options
111 files changed, 3933 insertions, 721 deletions
| diff --git a/Makefile.am b/Makefile.am index aaa0ae14..59cddb9f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=src doc altoslib altosui ao-tools ao-utils altosdroid +SUBDIRS=src doc altoslib libaltos altosuilib altosui micropeak ao-tools ao-utils altosdroid  EXTRA_DIST = ChangeLog @@ -15,5 +15,8 @@ dist-hook: ChangeLog  fat:  	cd src && $(MAKE) all  	cd doc && $(MAKE) all -	cd altosui/libaltos && $(MAKE) all +	cd libaltos && $(MAKE) all +	cd altoslib && $(MAKE) all +	cd altosuilib && $(MAKE) all  	cd altosui && $(MAKE) fat +	cd micropeak && $(MAKE) fat diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index 47196d6e..e50b9b5c 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -367,6 +367,8 @@ public class AltosPreferences {  		set_common_frequencies(new_frequencies);  	} +	static LinkedList<AltosUnitsListener> units_listeners; +  	public static boolean imperial_units() {  		synchronized(backend) {  			return AltosConvert.imperial_units; @@ -379,5 +381,24 @@ public class AltosPreferences {  			backend.putBoolean(unitsPreference, imperial_units);  			flush_preferences();  		} +		if (units_listeners != null) { +			for (AltosUnitsListener l : units_listeners) { +				l.units_changed(imperial_units); +			} +		} +	} + +	public static void register_units_listener(AltosUnitsListener l) { +		synchronized(backend) { +			if (units_listeners == null) +				units_listeners = new LinkedList<AltosUnitsListener>(); +			units_listeners.add(l); +		} +	} + +	public static void unregister_units_listener(AltosUnitsListener l) { +		synchronized(backend) { +			units_listeners.remove(l); +		}  	}  } diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index 09169515..2c4b6fa5 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -126,6 +126,8 @@ public abstract class AltosRecord implements Comparable <AltosRecord>, Cloneable  		return tick - o.tick;  	} +	abstract public AltosRecord clone(); +  	public void copy(AltosRecord old) {  		seen = old.seen;  		version = old.version; @@ -144,16 +146,6 @@ public abstract class AltosRecord implements Comparable <AltosRecord>, Cloneable  		kalman_height = old.kalman_height;  	} -	public AltosRecord clone() { -		try { -			AltosRecord n = (AltosRecord) super.clone(); -			n.copy(this); -			return n; -		} catch (CloneNotSupportedException e) { -			return null; -		} -	} -  	public AltosRecord() {  		seen = 0;  		version = 0; diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java index 9f529234..546f3055 100644 --- a/altoslib/AltosRecordMM.java +++ b/altoslib/AltosRecordMM.java @@ -131,10 +131,10 @@ public class AltosRecordMM extends AltosRecord {  		mag = old.mag;  	} + +  	public AltosRecordMM clone() { -		AltosRecordMM n = (AltosRecordMM) super.clone(); -		n.copy(this); -		return n; +		return new AltosRecordMM(this);  	}  	void make_missing() { @@ -167,6 +167,10 @@ public class AltosRecordMM extends AltosRecord {  		make_missing();  	} +	public AltosRecordMM(AltosRecordMM old) { +		copy(old); +	} +  	public AltosRecordMM() {  		super();  		make_missing(); diff --git a/altoslib/AltosRecordNone.java b/altoslib/AltosRecordNone.java index ca0a5fe3..d4ea305f 100644 --- a/altoslib/AltosRecordNone.java +++ b/altoslib/AltosRecordNone.java @@ -28,6 +28,10 @@ public class AltosRecordNone extends AltosRecord {  		super.copy(old);  	} +	public AltosRecordNone clone() { +		return new AltosRecordNone(this); +	} +  	public AltosRecordNone() {  		super();  	} diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java index 9530be31..f6ed4966 100644 --- a/altoslib/AltosRecordTM.java +++ b/altoslib/AltosRecordTM.java @@ -149,9 +149,7 @@ public class AltosRecordTM extends AltosRecord {  	}  	public AltosRecordTM clone() { -		AltosRecordTM	n = (AltosRecordTM) super.clone(); -		n.copy(this); -		return n; +		return new AltosRecordTM(this);  	}  	void make_missing() { @@ -177,6 +175,10 @@ public class AltosRecordTM extends AltosRecord {  		make_missing();  	} +	public AltosRecordTM(AltosRecordTM old) { +		copy(old); +	} +	  	public AltosRecordTM() {  		super();  		make_missing(); diff --git a/altoslib/AltosSpeed.java b/altoslib/AltosSpeed.java index af63ed17..4e2daf5a 100644 --- a/altoslib/AltosSpeed.java +++ b/altoslib/AltosSpeed.java @@ -21,19 +21,19 @@ public class AltosSpeed extends AltosUnits {  	public double value(double v) {  		if (AltosConvert.imperial_units) -			return AltosConvert.meters_to_feet(v); +			return AltosConvert.meters_to_mph(v);  		return v;  	}  	public String show_units() {  		if (AltosConvert.imperial_units) -			return "ft/s"; +			return "mph";  		return "m/s";  	}  	public String say_units() {  		if (AltosConvert.imperial_units) -			return "feet per second"; +			return "miles per hour";  		return "meters per second";  	} diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 218c598a..4f59c840 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -200,10 +200,10 @@ public class AltosState {  				}  				ngps++;  			} -		} else -			pad_alt = ground_altitude; - -		data.new_gps = false; +		} else { +			if (ngps == 0) +				pad_alt = ground_altitude; +		}  		gps_waiting = MIN_PAD_SAMPLES - npad;  		if (gps_waiting < 0) diff --git a/altoslib/AltosUnitsListener.java b/altoslib/AltosUnitsListener.java new file mode 100644 index 00000000..50a00cdf --- /dev/null +++ b/altoslib/AltosUnitsListener.java @@ -0,0 +1,22 @@ +/* + * 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; + +public interface AltosUnitsListener { +	public void units_changed(boolean imperial_units); +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 0086bc65..1b03c925 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -69,6 +69,7 @@ AltosLib_JAVA = \  	$(SRC)/AltosTelemetryRecordSensor.java \  	$(SRC)/AltosTelemetryRecordMegaSensor.java \  	$(SRC)/AltosTelemetryRecordMegaData.java \ +	$(SRC)/AltosUnitsListener.java \  	$(SRC)/AltosMs5607.java \  	$(SRC)/AltosIMU.java \  	$(SRC)/AltosMag.java \ diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index 03e7cbec..222b3c97 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -17,6 +17,7 @@  package altosui;  import libaltosJNI.*; +import org.altusmetrum.altosuilib.*;  public class AltosBTDevice extends altos_bt_device implements AltosDevice { diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java index ae04ac8c..606c0349 100644 --- a/altosui/AltosBTKnown.java +++ b/altosui/AltosBTKnown.java @@ -18,6 +18,7 @@  package altosui;  import java.util.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosBTKnown implements Iterable<AltosBTDevice> {  	LinkedList<AltosBTDevice>	devices = new LinkedList<AltosBTDevice>(); diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index 9a28d72b..b7b632a7 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -23,8 +23,9 @@ import javax.swing.*;  import javax.swing.plaf.basic.*;  import java.util.*;  import java.util.concurrent.*; +import org.altusmetrum.altosuilib.*; -public class AltosBTManage extends AltosDialog implements ActionListener, Iterable<AltosBTDevice> { +public class AltosBTManage extends AltosUIDialog implements ActionListener, Iterable<AltosBTDevice> {  	LinkedBlockingQueue<AltosBTDevice> found_devices;  	Frame frame;  	LinkedList<ActionListener> listeners; diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java index 1d024086..83bf16a7 100644 --- a/altosui/AltosCSVUI.java +++ b/altosui/AltosCSVUI.java @@ -22,9 +22,10 @@ import java.awt.event.*;  import javax.swing.*;  import java.io.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosCSVUI -	extends AltosDialog +	extends AltosUIDialog  	implements ActionListener  {  	JFileChooser		csv_chooser; diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index e1ffebb4..1cd61a89 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -21,8 +21,9 @@ import java.awt.event.*;  import javax.swing.*;  import java.io.*;  import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*;  import java.text.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosConfig implements ActionListener { @@ -270,7 +271,7 @@ public class AltosConfig implements ActionListener {  	public AltosConfig(JFrame given_owner) {  		owner = given_owner; -		device = AltosDeviceDialog.show(owner, Altos.product_any); +		device = AltosDeviceUIDialog.show(owner, Altos.product_any);  		if (device != null) {  			try {  				serial_line = new AltosSerial(device); diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java index 918748f7..75101e3d 100644 --- a/altosui/AltosConfigFreqUI.java +++ b/altosui/AltosConfigFreqUI.java @@ -22,8 +22,9 @@ import java.awt.event.*;  import javax.swing.*;  import java.util.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; -class AltosEditFreqUI extends AltosDialog implements ActionListener { +class AltosEditFreqUI extends AltosUIDialog implements ActionListener {  	Frame		frame;  	JTextField	frequency;  	JTextField	description; @@ -158,7 +159,7 @@ class AltosEditFreqUI extends AltosDialog implements ActionListener {  	}  } -public class AltosConfigFreqUI extends AltosDialog implements ActionListener { +public class AltosConfigFreqUI extends AltosUIDialog implements ActionListener {  	Frame frame;  	LinkedList<ActionListener> listeners; diff --git a/altosui/AltosConfigPyroUI.java b/altosui/AltosConfigPyroUI.java index 17adb15f..5cdaf564 100644 --- a/altosui/AltosConfigPyroUI.java +++ b/altosui/AltosConfigPyroUI.java @@ -22,9 +22,10 @@ import java.awt.event.*;  import javax.swing.*;  import javax.swing.event.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosConfigPyroUI -	extends AltosDialog +	extends AltosUIDialog  	implements ItemListener, DocumentListener  {  	AltosConfigUI	owner; diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java index e7b9b81f..794f8103 100644 --- a/altosui/AltosConfigTD.java +++ b/altosui/AltosConfigTD.java @@ -21,8 +21,8 @@ import java.awt.event.*;  import javax.swing.*;  import java.io.*;  import java.util.concurrent.*; -  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosConfigTD implements ActionListener { @@ -315,7 +315,7 @@ public class AltosConfigTD implements ActionListener {  		version = new string_ref("unknown");  		product = new string_ref("unknown"); -		device = AltosDeviceDialog.show(owner, Altos.product_basestation); +		device = AltosDeviceUIDialog.show(owner, Altos.product_basestation);  		if (device != null) {  			try {  				serial_line = new AltosSerial(device); diff --git a/altosui/AltosConfigTDUI.java b/altosui/AltosConfigTDUI.java index 532a49fa..54073843 100644 --- a/altosui/AltosConfigTDUI.java +++ b/altosui/AltosConfigTDUI.java @@ -22,9 +22,10 @@ import java.awt.event.*;  import javax.swing.*;  import javax.swing.event.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosConfigTDUI -	extends AltosDialog +	extends AltosUIDialog  	implements ActionListener, ItemListener, DocumentListener  { diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 95780e2b..599ed051 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -22,9 +22,10 @@ import java.awt.event.*;  import javax.swing.*;  import javax.swing.event.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosConfigUI -	extends AltosDialog +	extends AltosUIDialog  	implements ActionListener, ItemListener, DocumentListener, AltosConfigValues  { diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index c576b052..0e411b03 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -22,86 +22,17 @@ import java.awt.event.*;  import java.beans.*;  import javax.swing.*;  import javax.swing.event.*; - -class DelegatingRenderer implements ListCellRenderer { - -	// ... -	public static void install(JComboBox comboBox) { -		DelegatingRenderer renderer = new DelegatingRenderer(comboBox); -		renderer.initialise(); -		comboBox.setRenderer(renderer); -	} - -	// ... -	private final JComboBox comboBox; - -	// ... -	private ListCellRenderer delegate; - -	// ... -	private DelegatingRenderer(JComboBox comboBox) { -		this.comboBox = comboBox; -	} - -	// ... -	private void initialise() { -		delegate = new JComboBox().getRenderer(); -		comboBox.addPropertyChangeListener("UI", new PropertyChangeListener() { - -				public void propertyChange(PropertyChangeEvent evt) { -					delegate = new JComboBox().getRenderer(); -				} -			}); -	} - -	// ... -	public Component getListCellRendererComponent(JList list, -						      Object value, int index, boolean isSelected, boolean cellHasFocus) { - -		return delegate.getListCellRendererComponent(list, -							     ((UIManager.LookAndFeelInfo) value).getName(), -							     index, isSelected, cellHasFocus); -	} -} +import org.altusmetrum.altosuilib.*;  public class AltosConfigureUI -	extends AltosDialog +	extends AltosUIConfigure  	implements DocumentListener  { -	JFrame		owner;  	AltosVoice	voice; -	Container	pane; - -	JRadioButton	enable_voice; -	JButton		test_voice; -	JButton		close; - -	JButton		configure_log; -	JTextField	log_directory; - -	JLabel		callsign_label; -	JTextField	callsign_value; - -	JRadioButton	imperial_units; - -	JLabel		font_size_label; -	JComboBox	font_size_value; -	JLabel		look_and_feel_label; -	JComboBox	look_and_feel_value; - -	JRadioButton	serial_debug; - -	JButton		manage_bluetooth; -	JButton		manage_frequencies; - -	final static String[] font_size_names = { "Small", "Medium", "Large" }; +	public JTextField	callsign_value;  	/* DocumentListener interface methods */ -	public void changedUpdate(DocumentEvent e) { -		AltosUIPreferences.set_callsign(callsign_value.getText()); -	} -  	public void insertUpdate(DocumentEvent e) {  		changedUpdate(e);  	} @@ -110,49 +41,17 @@ public class AltosConfigureUI  		changedUpdate(e);  	} -	public AltosConfigureUI(JFrame in_owner, AltosVoice in_voice) { -		super(in_owner, "Configure AltosUI", false); - -		GridBagConstraints	c; - -		Insets insets = new Insets(4, 4, 4, 4); - -		int row = 0; - -		owner = in_owner; -		voice = in_voice; -		pane = getContentPane(); -		pane.setLayout(new GridBagLayout()); - -		c = new GridBagConstraints(); -		c.insets = insets; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; - -		/* Nice label at the top */ -		c.gridx = 0; -		c.gridy = row++; -		c.gridwidth = 3; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.CENTER; -		pane.add(new JLabel ("Configure AltOS UI"), c); +	public void changedUpdate(DocumentEvent e) { +		if (callsign_value != null)  +			AltosUIPreferences.set_callsign(callsign_value.getText()); +	} -		c.gridx = 0; -		c.gridy = row++; -		c.gridwidth = 3; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.CENTER; -		pane.add(new JLabel (String.format("AltOS version %s", AltosVersion.version)), c); +	public void add_voice() {  		/* Voice settings */ -		c.gridx = 0; -		c.gridy = row; -		c.gridwidth = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(new JLabel("Voice"), c); +		pane.add(new JLabel("Voice"), constraints(0, 1)); -		enable_voice = new JRadioButton("Enable", AltosUIPreferences.voice()); +		JRadioButton enable_voice = new JRadioButton("Enable", AltosUIPreferences.voice());  		enable_voice.addActionListener(new ActionListener() {  				public void actionPerformed(ActionEvent e) {  					JRadioButton item = (JRadioButton) e.getSource(); @@ -164,246 +63,57 @@ public class AltosConfigureUI  						voice.speak_always("Disable voice.");  				}  			}); -		c.gridx = 1; -		c.gridy = row; -		c.gridwidth = 1; -		c.weightx = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(enable_voice, c); +		pane.add(enable_voice, constraints(1, 1));  		enable_voice.setToolTipText("Enable/Disable all audio in-flight announcements"); -		c.gridx = 2; -		c.gridy = row++; -		c.gridwidth = 1; -		c.weightx = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.EAST; -		test_voice = new JButton("Test Voice"); +		JButton test_voice = new JButton("Test Voice");  		test_voice.addActionListener(new ActionListener() {  				public void actionPerformed(ActionEvent e) {  					voice.speak("That's one small step for man; one giant leap for mankind.");  				}  			}); -		pane.add(test_voice, c); +		pane.add(test_voice, constraints(2, 1));  		test_voice.setToolTipText("Play a stock audio clip to check volume"); +		row++; +	} -		/* Log directory settings */ -		c.gridx = 0; -		c.gridy = row; -		c.gridwidth = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(new JLabel("Log Directory"), c); - -		configure_log = new JButton(AltosUIPreferences.logdir().getPath()); -		configure_log.addActionListener(new ActionListener() { -				public void actionPerformed(ActionEvent e) { -					AltosUIPreferences.ConfigureLog(); -					configure_log.setText(AltosUIPreferences.logdir().getPath()); -				} -			}); -		c.gridx = 1; -		c.gridy = row++; -		c.gridwidth = 2; -		c.fill = GridBagConstraints.BOTH; -		c.anchor = GridBagConstraints.WEST; -		pane.add(configure_log, c); -		configure_log.setToolTipText("Which directory flight logs are stored in"); - +	public void add_callsign() {  		/* Callsign setting */ -		c.gridx = 0; -		c.gridy = row; -		c.gridwidth = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(new JLabel("Callsign"), c); +		pane.add(new JLabel("Callsign"), constraints(0, 1)); -		callsign_value = new JTextField(AltosUIPreferences.callsign()); +		JTextField callsign_value = new JTextField(AltosUIPreferences.callsign());  		callsign_value.getDocument().addDocumentListener(this); -		c.gridx = 1; -		c.gridy = row++; -		c.gridwidth = 2; -		c.fill = GridBagConstraints.BOTH; -		c.anchor = GridBagConstraints.WEST; -		pane.add(callsign_value, c);  		callsign_value.setToolTipText("Callsign sent in packet mode"); +		pane.add(callsign_value, constraints(1, 2, GridBagConstraints.BOTH)); +		row++; +	} -		/* Imperial units setting */ -		c.gridx = 0; -		c.gridy = row; -		c.gridwidth = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(new JLabel("Imperial Units"), c); - -		imperial_units = new JRadioButton("Enable", AltosUIPreferences.imperial_units()); -		imperial_units.addActionListener(new ActionListener() { -				public void actionPerformed(ActionEvent e) { -					JRadioButton item = (JRadioButton) e.getSource(); -					boolean enabled = item.isSelected(); -					AltosUIPreferences.set_imperial_units(enabled); -				} -			}); -		imperial_units.setToolTipText("Use Imperial units instead of metric"); - -		c.gridx = 1; -		c.gridy = row++; -		c.gridwidth = 3; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(imperial_units, c); - -		/* Font size setting */ -		c.gridx = 0; -		c.gridy = row; -		c.gridwidth = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(new JLabel("Font size"), c); - -		font_size_value = new JComboBox(font_size_names); -		int font_size = AltosUIPreferences.font_size(); -		font_size_value.setSelectedIndex(font_size - Altos.font_size_small); -		font_size_value.addActionListener(new ActionListener() { -				public void actionPerformed(ActionEvent e) { -					int	size = font_size_value.getSelectedIndex() + Altos.font_size_small; - -					AltosUIPreferences.set_font_size(size); -				} -			}); -		c.gridx = 1; -		c.gridy = row++; -		c.gridwidth = 2; -		c.fill = GridBagConstraints.BOTH; -		c.anchor = GridBagConstraints.WEST; -		pane.add(font_size_value, c); -		font_size_value.setToolTipText("Font size used in telemetry window"); - -		/* Look & Feel setting */ -		c.gridx = 0; -		c.gridy = row; -		c.gridwidth = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(new JLabel("Look & feel"), c); - -		/* -		class LookAndFeelRenderer extends BasicComboBoxRenderer implements ListCellRenderer { - -			public LookAndFeelRenderer() { -				super(); -			} - -			public Component getListCellRendererComponent( -				JList list, -				Object value, -				int index, -				boolean isSelected, -				boolean cellHasFocus) -			{ -				super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); -				setText(((UIManager.LookAndFeelInfo) value).getName()); -				return this; -			} -		} -		*/ - -		final UIManager.LookAndFeelInfo[] look_and_feels = UIManager.getInstalledLookAndFeels(); - -		look_and_feel_value = new JComboBox(look_and_feels); - -		DelegatingRenderer.install(look_and_feel_value); - -		String look_and_feel  = AltosUIPreferences.look_and_feel(); -		for (int i = 0; i < look_and_feels.length; i++) -			if (look_and_feel.equals(look_and_feels[i].getClassName())) -				look_and_feel_value.setSelectedIndex(i); - -		look_and_feel_value.addActionListener(new ActionListener() { -				public void actionPerformed(ActionEvent e) { -					int	id = look_and_feel_value.getSelectedIndex(); - -					AltosUIPreferences.set_look_and_feel(look_and_feels[id].getClassName()); -				} -			}); -		c.gridx = 1; -		c.gridy = row++; -		c.gridwidth = 2; -		c.fill = GridBagConstraints.BOTH; -		c.anchor = GridBagConstraints.WEST; -		pane.add(look_and_feel_value, c); -		look_and_feel_value.setToolTipText("Look&feel used for new windows"); - -		/* Serial debug setting */ -		c.gridx = 0; -		c.gridy = row; -		c.gridwidth = 1; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(new JLabel("Serial Debug"), c); - -		serial_debug = new JRadioButton("Enable", AltosUIPreferences.serial_debug()); -		serial_debug.addActionListener(new ActionListener() { -				public void actionPerformed(ActionEvent e) { -					JRadioButton item = (JRadioButton) e.getSource(); -					boolean enabled = item.isSelected(); -					AltosUIPreferences.set_serial_debug(enabled); -				} -			}); -		serial_debug.setToolTipText("Enable/Disable USB I/O getting sent to the console"); - -		c.gridx = 1; -		c.gridy = row++; -		c.gridwidth = 3; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(serial_debug, c); - -		manage_bluetooth = new JButton("Manage Bluetooth"); +	public void add_bluetooth() { +		JButton manage_bluetooth = new JButton("Manage Bluetooth");  		manage_bluetooth.addActionListener(new ActionListener() {  				public void actionPerformed(ActionEvent e) {  					AltosBTManage.show(owner, AltosBTKnown.bt_known());  				}  			}); -		c.gridx = 0; -		c.gridy = row; -		c.gridwidth = 2; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(manage_bluetooth, c); +		pane.add(manage_bluetooth, constraints(0, 2)); +		/* in the same row as add_frequencies, so don't bump row */ +	} -		manage_frequencies = new JButton("Manage Frequencies"); +	public void add_frequencies() { +		JButton manage_frequencies = new JButton("Manage Frequencies");  		manage_frequencies.addActionListener(new ActionListener() {  				public void actionPerformed(ActionEvent e) {  					AltosConfigFreqUI.show(owner);  				}  			});  		manage_frequencies.setToolTipText("Configure which values are shown in frequency menus"); -		c.gridx = 2; -		c.gridx = 2; -		c.gridy = row++; -		c.gridwidth = 2; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.WEST; -		pane.add(manage_frequencies, c); +		pane.add(manage_frequencies, constraints(2, 1)); +		row++; +	} -		/* And a close button at the bottom */ -		close = new JButton("Close"); -		close.addActionListener(new ActionListener() { -				public void actionPerformed(ActionEvent e) { -					setVisible(false); -				} -			}); -		c.gridx = 0; -		c.gridy = row++; -		c.gridwidth = 3; -		c.fill = GridBagConstraints.NONE; -		c.anchor = GridBagConstraints.CENTER; -		pane.add(close, c); +	public AltosConfigureUI(JFrame owner, AltosVoice voice) { +		super(owner); -		pack(); -		setLocationRelativeTo(owner); -		setVisible(true); +		this.voice = voice;  	}  } diff --git a/altosui/AltosDebug.java b/altosui/AltosDebug.java index 16b10c3a..482f4c36 100644 --- a/altosui/AltosDebug.java +++ b/altosui/AltosDebug.java @@ -18,6 +18,7 @@  package altosui;  import java.io.*; +import org.altusmetrum.altosuilib.*;  public class AltosDebug extends AltosSerial { diff --git a/altosui/AltosDeviceUIDialog.java b/altosui/AltosDeviceUIDialog.java new file mode 100644 index 00000000..7ed599a3 --- /dev/null +++ b/altosui/AltosDeviceUIDialog.java @@ -0,0 +1,70 @@ +/* + * 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 javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import org.altusmetrum.altosuilib.*; + +public class AltosDeviceUIDialog extends AltosDeviceDialog { + +	public AltosDevice[] devices() { +		java.util.List<AltosDevice>	usb_devices = AltosUSBDevice.list(product); +		int				num_devices = usb_devices.size(); +		java.util.List<AltosDevice>	bt_devices = AltosBTKnown.bt_known().list(product); +		num_devices += bt_devices.size(); +		AltosDevice[]			devices = new AltosDevice[num_devices]; + +		for (int i = 0; i < usb_devices.size(); i++) +			devices[i] = usb_devices.get(i); +		int off = usb_devices.size(); +		for (int j = 0; j < bt_devices.size(); j++) +			devices[off + j] = bt_devices.get(j); +		return devices; +	} + +	public void add_bluetooth() { +		JButton manage_bluetooth_button = new JButton("Manage Bluetooth"); +		manage_bluetooth_button.setActionCommand("manage"); +		manage_bluetooth_button.addActionListener(this); +		buttonPane.add(manage_bluetooth_button); +		buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); +	} +	 +	public void actionPerformed(ActionEvent e) { +		super.actionPerformed(e); +		if ("manage".equals(e.getActionCommand())) { +			AltosBTManage.show(frame, AltosBTKnown.bt_known()); +			update_devices(); +		} +	} + +	public AltosDeviceUIDialog (Frame in_frame, Component location, int in_product) { +		super(in_frame, location, in_product); +	} + +	public static AltosDevice show (Component frameComp, int product) { +		Frame			frame = JOptionPane.getFrameForComponent(frameComp); +		AltosDeviceUIDialog	dialog; + +		dialog = new AltosDeviceUIDialog(frame, frameComp, product); +		dialog.setVisible(true); +		return dialog.getValue(); +	} +} diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index b8de77da..cc9adb0c 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -22,6 +22,7 @@ import javax.swing.*;  import java.io.*;  import java.util.concurrent.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosEepromManage implements ActionListener { @@ -197,7 +198,7 @@ public class AltosEepromManage implements ActionListener {  		//boolean	running = false;  		frame = given_frame; -		device = AltosDeviceDialog.show(frame, Altos.product_any); +		device = AltosDeviceUIDialog.show(frame, Altos.product_any);  		remote = false; diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java index 251344e9..8eae5eb8 100644 --- a/altosui/AltosEepromMonitor.java +++ b/altosui/AltosEepromMonitor.java @@ -20,8 +20,9 @@ package altosui;  import java.awt.*;  import java.awt.event.*;  import javax.swing.*; +import org.altusmetrum.altosuilib.*; -public class AltosEepromMonitor extends AltosDialog { +public class AltosEepromMonitor extends AltosUIDialog {  	Container	pane;  	Box		box; diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index d8b8693d..c0886212 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -22,6 +22,7 @@ import javax.swing.border.*;  import java.awt.*;  import java.awt.event.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  class AltosEepromItem implements ActionListener {  	AltosEepromLog	log; @@ -50,7 +51,7 @@ class AltosEepromItem implements ActionListener {  	}  } -public class AltosEepromSelect extends AltosDialog implements ActionListener { +public class AltosEepromSelect extends AltosUIDialog implements ActionListener {  	//private JList			list;  	private JFrame			frame;  	JButton				ok; diff --git a/altosui/AltosFlash.java b/altosui/AltosFlash.java index 313af70b..7a98ee14 100644 --- a/altosui/AltosFlash.java +++ b/altosui/AltosFlash.java @@ -20,6 +20,7 @@ package altosui;  import java.awt.event.*;  import javax.swing.*;  import java.io.*; +import org.altusmetrum.altosuilib.*;  public class AltosFlash {  	File		file; diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 3ccfa76c..921207bc 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -23,9 +23,10 @@ import javax.swing.*;  import javax.swing.filechooser.FileNameExtensionFilter;  import java.io.*;  import java.util.concurrent.*; +import org.altusmetrum.altosuilib.*;  public class AltosFlashUI -	extends AltosDialog +	extends AltosUIDialog  	implements ActionListener  {  	Container	pane; @@ -175,7 +176,7 @@ public class AltosFlashUI  	}  	boolean select_debug_dongle() { -		debug_dongle = AltosDeviceDialog.show(frame, Altos.product_any); +		debug_dongle = AltosDeviceUIDialog.show(frame, Altos.product_any);  		if (debug_dongle == null)  			return false; diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 43df705e..e2dc06bd 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -22,8 +22,9 @@ import java.awt.event.*;  import javax.swing.*;  import java.util.concurrent.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; -public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { +public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener {  	AltosVoice		voice;  	AltosFlightReader	reader;  	AltosDisplayThread	thread; diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index b7c2e92e..d6891ffa 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -10,12 +10,13 @@ import java.util.ArrayList;  import java.awt.*;  import javax.swing.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  import org.jfree.chart.ChartPanel;  import org.jfree.chart.JFreeChart;  import org.jfree.ui.RefineryUtilities; -public class AltosGraphUI extends AltosFrame  +public class AltosGraphUI extends AltosUIFrame   {      JTabbedPane	pane; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 6f696009..1b3dd547 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -23,8 +23,9 @@ import javax.swing.*;  import java.io.*;  import java.util.concurrent.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; -public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener, AltosIdleMonitorListener { +public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener, AltosIdleMonitorListener {  	AltosDevice		device;  	JTabbedPane		pane;  	AltosPad		pad; @@ -90,7 +91,7 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay  	public AltosIdleMonitorUI(JFrame in_owner)  		throws FileNotFoundException, AltosSerialInUseException, TimeoutException, InterruptedException { -		device = AltosDeviceDialog.show(in_owner, Altos.product_any); +		device = AltosDeviceUIDialog.show(in_owner, Altos.product_any);  		remote = false;  		if (!device.matchProduct(Altos.product_altimeter))  			remote = true; diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index ec331259..c1378eb9 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -24,9 +24,10 @@ import java.io.*;  import java.text.*;  import java.util.concurrent.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosIgniteUI -	extends AltosDialog +	extends AltosUIDialog  	implements ActionListener  {  	AltosDevice	device; @@ -304,7 +305,7 @@ public class AltosIgniteUI  	private boolean open() {  		command_queue = new LinkedBlockingQueue<String>(); -		device = AltosDeviceDialog.show(owner, Altos.product_any); +		device = AltosDeviceUIDialog.show(owner, Altos.product_any);  		if (device != null) {  				IgniteHandler	handler = new IgniteHandler(owner);  				Thread		t = new Thread(handler); diff --git a/altosui/AltosLaunch.java b/altosui/AltosLaunch.java index de19221e..0bad80aa 100644 --- a/altosui/AltosLaunch.java +++ b/altosui/AltosLaunch.java @@ -20,6 +20,7 @@ package altosui;  import java.io.*;  import java.util.concurrent.*;  import java.awt.*; +import org.altusmetrum.altosuilib.*;  public class AltosLaunch {  	AltosDevice	device; diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index 39b986c0..7e7ed010 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -23,6 +23,7 @@ import javax.swing.*;  import java.io.*;  import java.text.*;  import java.util.concurrent.*; +import org.altusmetrum.altosuilib.*;  class FireButton extends JButton {  	protected void processMouseEvent(MouseEvent e) { @@ -45,7 +46,7 @@ class FireButton extends JButton {  }  public class AltosLaunchUI -	extends AltosDialog +	extends AltosUIDialog  	implements ActionListener  {  	AltosDevice	device; @@ -370,7 +371,7 @@ public class AltosLaunchUI  	private boolean open() {  		command_queue = new LinkedBlockingQueue<String>(); -		device = AltosDeviceDialog.show(owner, Altos.product_any); +		device = AltosDeviceUIDialog.show(owner, Altos.product_any);  		if (device != null) {  				LaunchHandler	handler = new LaunchHandler(owner);  				Thread		t = new Thread(handler); diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java index d4a5ef6d..5fc786e2 100644 --- a/altosui/AltosRomconfigUI.java +++ b/altosui/AltosRomconfigUI.java @@ -20,9 +20,10 @@ package altosui;  import java.awt.*;  import java.awt.event.*;  import javax.swing.*; +import org.altusmetrum.altosuilib.*;  public class AltosRomconfigUI -	extends AltosDialog +	extends AltosUIDialog  	implements ActionListener  {  	Container	pane; diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 2a6e140a..14b52310 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -26,6 +26,7 @@ import java.util.*;  import java.text.*;  import java.util.concurrent.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  class AltosScanResult {  	String		callsign; @@ -121,7 +122,7 @@ class AltosScanResults extends LinkedList<AltosScanResult> implements ListModel  }  public class AltosScanUI -	extends AltosDialog +	extends AltosUIDialog  	implements ActionListener  {  	AltosUI				owner; @@ -327,7 +328,7 @@ public class AltosScanUI  	}  	private boolean open() { -		device = AltosDeviceDialog.show(owner, Altos.product_basestation); +		device = AltosDeviceUIDialog.show(owner, Altos.product_basestation);  		if (device == null)  			return false;  		try { diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 771fdd5d..78d862d0 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -26,6 +26,7 @@ import java.util.*;  import java.awt.*;  import javax.swing.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  import libaltosJNI.*; diff --git a/altosui/AltosSerialInUseException.java b/altosui/AltosSerialInUseException.java index 7380f331..932a3684 100644 --- a/altosui/AltosSerialInUseException.java +++ b/altosui/AltosSerialInUseException.java @@ -16,6 +16,7 @@   */  package altosui; +import org.altusmetrum.altosuilib.*;  public class AltosSerialInUseException extends Exception {  	public AltosDevice	device; diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 33849c66..f4dcc903 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -26,6 +26,7 @@ import java.text.*;  import java.lang.Math;  import java.net.URL;  import java.net.URLConnection; +import org.altusmetrum.altosuilib.*;  class AltosMapPos extends Box {  	AltosUI		owner; @@ -205,7 +206,7 @@ class AltosSites extends Thread {  	}  } -public class AltosSiteMapPreload extends AltosDialog implements ActionListener, ItemListener { +public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener, ItemListener {  	AltosUI		owner;  	AltosSiteMap	map; diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index dcc0de60..70142a93 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -23,8 +23,9 @@ import javax.swing.*;  import java.io.*;  import java.util.concurrent.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; -public class AltosUI extends AltosFrame { +public class AltosUI extends AltosUIFrame {  	public AltosVoice voice = new AltosVoice();  	public static boolean load_library(Frame frame) { @@ -241,7 +242,7 @@ public class AltosUI extends AltosFrame {  	}  	private void ConnectToDevice() { -		AltosDevice	device = AltosDeviceDialog.show(AltosUI.this, +		AltosDevice	device = AltosDeviceUIDialog.show(AltosUI.this,  								Altos.product_basestation);  		if (device != null) diff --git a/altosui/AltosUIPreferences.java b/altosui/AltosUIPreferences.java index f6ee7e06..9c56d031 100644 --- a/altosui/AltosUIPreferences.java +++ b/altosui/AltosUIPreferences.java @@ -22,6 +22,7 @@ import java.util.*;  import java.awt.Component;  import javax.swing.*;  import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*;  public class AltosUIPreferences extends AltosPreferences { diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 306a396e..7d000f7b 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=libaltos +  JAVAROOT=classes  AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation @@ -6,7 +6,7 @@ man_MANS=altosui.1  altoslibdir=$(libdir)/altos -CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar:$(FREETTS)/freetts.jar" +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="$(JAVAROOT):../altoslib/*:../altosuilib/*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar:$(FREETTS)/freetts.jar"  bin_SCRIPTS=altosui @@ -32,9 +32,7 @@ altosui_JAVA = \  	AltosCSVUI.java \  	AltosDebug.java \  	AltosDescent.java \ -	AltosDeviceDialog.java \ -	AltosDevice.java \ -	AltosUSBDevice.java \ +	AltosDeviceUIDialog.java \  	AltosDisplayThread.java \  	AltosEepromDelete.java \  	AltosEepromDownload.java \ @@ -51,7 +49,6 @@ altosui_JAVA = \  	AltosFlightStatus.java \  	AltosFlightStatusUpdate.java \  	AltosFlightUI.java \ -	AltosFontListener.java \  	AltosFreqList.java \  	AltosHexfile.java \  	Altos.java \ @@ -77,9 +74,6 @@ altosui_JAVA = \  	AltosSiteMapCache.java \  	AltosSiteMapTile.java \  	AltosUI.java \ -	AltosUIListener.java \ -	AltosFrame.java \ -	AltosDialog.java \  	AltosWriter.java \  	AltosDataPointReader.java \  	AltosDataPoint.java \ @@ -87,7 +81,6 @@ altosui_JAVA = \  	AltosGraphTime.java \  	AltosGraphUI.java \  	AltosDataChooser.java \ -	AltosVersion.java \  	AltosVoice.java \  	$(altosui_BT) @@ -109,6 +102,9 @@ FREETTS_CLASS= \  ALTOSLIB_CLASS=\  	AltosLib.jar +ALTOSUILIB_CLASS=\ +	altosuilib.jar +  LIBALTOS= \  	libaltos.so \  	libaltos.dylib \ @@ -169,16 +165,16 @@ DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TELEMETRY_DOC) $(TEMPLATE_DOC)  # Distribution targets  LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2 -MACOSX_DIST=Altos-Mac-$(VERSION).zip +MACOSX_DIST=Altos-Mac-$(VERSION).dmg  WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe -FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) +FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS)  LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC)  LINUX_EXTRA=altosui-fat  MACOSX_INFO_PLIST=Info.plist -MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) +MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) ReadMe-Mac.rtf  MACOSX_EXTRA=$(FIRMWARE)  WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON) @@ -187,7 +183,7 @@ all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb  clean-local:  	-rm -rf classes $(JAR) $(FATJAR) \ -		$(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(ALTOSLIB_CLASS) $(FREETTS_CLASS) \ +		$(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) \  		$(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log \  		altosui altosui-test altosui-jdb macosx linux @@ -229,75 +225,79 @@ install-altosuiJAVA: altosui.jar  classes/altosui:  	mkdir -p classes/altosui -$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICONS) $(ALTOSLIB_CLASS) +$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICONS) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)  	jar cfm $@ Manifest.txt \  		$(ICONJAR) \  		-C classes altosui \ -		-C libaltos libaltosJNI +		-C ../libaltos libaltosJNI -$(FATJAR): classaltosui.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICONS) +$(FATJAR): classaltosui.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICONS)  	jar cfm $@ Manifest-fat.txt \  		$(ICONJAR) \  		-C classes altosui \ -		-C libaltos libaltosJNI +		-C ../libaltos libaltosJNI  Manifest.txt: Makefile  	echo 'Main-Class: altosui.AltosUI' > $@ -	echo "Class-Path: AltosLib.jar $(FREETTS)/freetts.jar $(JCOMMON)/jcommon.jar $(JFREECHART)/jfreechart.jar" >> $@ +	echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS)/freetts.jar $(JCOMMON)/jcommon.jar $(JFREECHART)/jfreechart.jar" >> $@  Manifest-fat.txt:  	echo 'Main-Class: altosui.AltosUI' > $@ -	echo "Class-Path: AltosLib.jar freetts.jar jcommon.jar jfreechart.jar" >> $@ +	echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) freetts.jar jcommon.jar jfreechart.jar" >> $@  altosui: Makefile  	echo "#!/bin/sh" > $@ -	echo 'exec java  -cp "$(FREETTS)/freetts.jar:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/altosui.jar" "$$@"' >> $@ +	echo 'exec java -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/altosui.jar" "$$@"' >> $@  	chmod +x $@  altosui-test: Makefile  	echo "#!/bin/sh" > $@ -	echo 'exec java -cp "./*:$(FREETTS)/freetts.jar:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@ +	echo 'exec java -Djava.library.path="../libaltos/.libs" -jar altosui.jar "$$@"' >> $@  	chmod +x $@  altosui-jdb: Makefile  	echo "#!/bin/sh" > $@ -	echo 'exec jdb -classpath "classes:libaltos:$(FREETTS)/freetts.jar:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="libaltos/.libs" altosui/AltosUI "$$@"' >> $@ +	echo 'exec jdb -classpath "classes:./*:../libaltos:$(FREETTS)/freetts.jar:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="../libaltos/.libs" altosui/AltosUI "$$@"' >> $@  	chmod +x $@  libaltos.so: build-libaltos  	-rm -f "$@" -	$(LN_S) libaltos/.libs/"$@" . +	$(LN_S) ../libaltos/.libs/"$@" .  libaltos.dylib:  	-rm -f "$@" -	$(LN_S) libaltos/"$@" . +	$(LN_S) ../libaltos/"$@" . -altos.dll: libaltos/altos.dll +altos.dll: ../libaltos/altos.dll  	-rm -f "$@" -	$(LN_S) libaltos/"$@" . +	$(LN_S) ../libaltos/"$@" . -altos64.dll: libaltos/altos64.dll +altos64.dll: ../libaltos/altos64.dll  	-rm -f "$@" -	$(LN_S) libaltos/"$@" . +	$(LN_S) ../libaltos/"$@" . -libaltos/.libs/libaltos.so: build-libaltos +../libaltos/.libs/libaltos.so: build-libaltos -libaltos/altos.dll: build-altos-dll +../libaltos/altos.dll: build-altos-dll -libaltos/altos64.dll: build-altos64-dll +../libaltos/altos64.dll: build-altos64-dll  build-libaltos: -	+cd libaltos && make libaltos.la +	+cd ../libaltos && make libaltos.la  build-altos-dll: -	+cd libaltos && make altos.dll +	+cd ../libaltos && make altos.dll  build-altos64-dll: -	+cd libaltos && make altos64.dll +	+cd ../libaltos && make altos64.dll  $(ALTOSLIB_CLASS):  	-rm -f "$@"  	$(LN_S) ../altoslib/"$@" . +$(ALTOSUILIB_CLASS): +	-rm -f "$@" +	$(LN_S) ../altosuilib/"$@" . +  $(FREETTS_CLASS):  	-rm -f "$@"  	$(LN_S) "$(FREETTS)"/"$@" . @@ -319,21 +319,23 @@ $(LINUX_DIST): $(LINUX_FILES) $(LINUX_EXTRA)  	chmod +x linux/AltOS/altosui  	tar cjf $@ -C linux AltOS -$(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) +$(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) Makefile  	-rm -f $@  	-rm -rf macosx  	mkdir macosx  	cp -a AltosUI.app macosx/ +	cp -a ReadMe-Mac.rtf macosx/ReadMe.rtf  	cp -p Info.plist macosx/AltosUI.app/Contents -	mkdir -p macosx/AltOS macosx/AltosUI.app/Contents/Resources/Java +	mkdir -p macosx/AltOS-$(VERSION) macosx/AltosUI.app/Contents/Resources/Java  	cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar  	cp -p libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java  	cp -p $(ALTOSLIB_CLASS) macosx/AltosUI.app/Contents/Resources/Java +	cp -p $(ALTOSUILIB_CLASS) macosx/AltosUI.app/Contents/Resources/Java  	cp -p $(FREETTS_CLASS) macosx/AltosUI.app/Contents/Resources/Java  	cp -p $(JFREECHART_CLASS) macosx/AltosUI.app/Contents/Resources/Java  	cp -p $(JCOMMON_CLASS) macosx/AltosUI.app/Contents/Resources/Java -	cp -p $(MACOSX_EXTRA) macosx/AltOS -	cd macosx && zip -r ../$@ AltosUI.app AltOS +	cp -p $(MACOSX_EXTRA) macosx/AltOS-$(VERSION) +	genisoimage -D -V AltOS-$(VERSION) -no-pad -r -apple -o $@ macosx  $(WINDOWS_DIST): $(WINDOWS_FILES) altos-windows.nsi  	-rm -f $@ diff --git a/altosui/ReadMe-Mac.rtf b/altosui/ReadMe-Mac.rtf new file mode 100644 index 00000000..8a95262c --- /dev/null +++ b/altosui/ReadMe-Mac.rtf @@ -0,0 +1,56 @@ +{\rtf1\ansi\deff3\adeflang1025 +{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset128 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset128 Arial;}{\f5\fnil\fprq2\fcharset128 SimSun;}{\f6\fnil\fprq2\fcharset128 Raghindi;}{\f7\fnil\fprq0\fcharset128 Raghindi;}} +{\colortbl;\red0\green0\blue0;\red128\green128\blue128;} +{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033 Normal;} +{\*\cs15\snext15 Numbering Symbols;} +{\s16\sbasedon0\snext17\sb240\sa120\keepn\hich\af5\dbch\af6\afs28\loch\f4\fs28 Heading;} +{\s17\sbasedon0\snext17\sb0\sa120 Text body;} +{\s18\sbasedon17\snext18\sb0\sa120\dbch\af7 List;} +{\s19\sbasedon0\snext19\sb120\sa120\noline\i\dbch\af7\afs24\ai\fs24 Caption;} +{\s20\sbasedon0\snext20\noline\dbch\af7 Index;} +}{\*\listtable{\list\listtemplateid1 +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'00);}{\levelnumbers\'01;}\fi-360\li720} +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'01.;}{\levelnumbers\'01;}\fi-360\li1080} +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'02.;}{\levelnumbers\'01;}\fi-360\li1440} +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'03.;}{\levelnumbers\'01;}\fi-360\li1800} +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'04.;}{\levelnumbers\'01;}\fi-360\li2160} +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'05.;}{\levelnumbers\'01;}\fi-360\li2520} +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'06.;}{\levelnumbers\'01;}\fi-360\li2880} +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'07.;}{\levelnumbers\'01;}\fi-360\li3240} +{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'08.;}{\levelnumbers\'01;}\fi-360\li3600}\listid1} +{\list\listtemplateid2 +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-432\li432} +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-576\li576} +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-720\li720} +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-864\li864} +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-1008\li1008} +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-1152\li1152} +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-1296\li1296} +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-1440\li1440} +{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow0{\leveltext \'00;}{\levelnumbers;}\fi-1584\li1584}\listid2} +}{\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}}{\info{\creatim\yr2013\mo1\dy6\hr13\min7}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern3500}}\deftab709 + +{\*\pgdsctbl +{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Default;}} +\formshade\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc +\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\rtlch \ltrch\loch +Installing AltOS software for Mac OS X Computers} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\rtlch \ltrch\loch +} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\rtlch \ltrch\loch +The AltOS distribution for Mac OS X consists of:} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\rtlch \ltrch\loch +} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\listtext\pard\plain  1)\tab}\ilvl0\ls1 \li720\ri0\lin720\rin0\fi-360{\rtlch \ltrch\loch +The AltosUI application} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\listtext\pard\plain  2)\tab}\ilvl0\ls1 \li720\ri0\lin720\rin0\fi-360{\rtlch \ltrch\loch +Current AltOS firmware for Altus Metrum products} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\rtlch \ltrch\loch +} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\rtlch \ltrch\loch +Install the AltosUI application by dragging it to your Applications folder (or wherever else you want to install it).} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\rtlch \ltrch\loch +} +\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af5\langfe2052\dbch\af6\afs24\alang1081\loch\f3\fs24\lang1033{\rtlch \ltrch\loch +The AltOS firmware can be used to update your Altus Metrum products to the latest firmware version, you can copy it to your disk if you like, or simply use it directly from the installation disk image.} +\par }
\ No newline at end of file diff --git a/altosui/libaltos/libaltos.dylib b/altosui/libaltos/libaltos.dylibBinary files differ deleted file mode 100755 index 1038817d..00000000 --- a/altosui/libaltos/libaltos.dylib +++ /dev/null diff --git a/altosuilib/AltosDevice.java b/altosuilib/AltosDevice.java new file mode 100644 index 00000000..69b025ba --- /dev/null +++ b/altosuilib/AltosDevice.java @@ -0,0 +1,30 @@ +/* + * 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.altosuilib; + +import libaltosJNI.*; + +public interface AltosDevice { +	public abstract String toString(); +	public abstract String toShortString(); +	public abstract int getSerial(); +	public abstract String getPath(); +	public abstract boolean matchProduct(int product); +	public abstract String getErrorString(); +	public SWIGTYPE_p_altos_file open(); +} diff --git a/altosui/AltosDeviceDialog.java b/altosuilib/AltosDeviceDialog.java index 0aeadae6..cde545a7 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosuilib/AltosDeviceDialog.java @@ -15,48 +15,37 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altosuilib;  import javax.swing.*;  import java.awt.*;  import java.awt.event.*; -public class AltosDeviceDialog extends AltosDialog implements ActionListener { +public abstract class AltosDeviceDialog extends AltosUIDialog implements ActionListener {  	private AltosDevice	value;  	private JList		list;  	private JButton		cancel_button;  	private JButton		select_button; -	private JButton		manage_bluetooth_button; -	private Frame		frame; -	private int		product; - -	private AltosDevice getValue() { +	public Frame		frame; +	public int		product; +	public JPanel		buttonPane; +	 +	public AltosDevice getValue() {  		return value;  	} -	private AltosDevice[] devices() { -		java.util.List<AltosDevice>	usb_devices = AltosUSBDevice.list(product); -		int				num_devices = usb_devices.size(); -		java.util.List<AltosDevice>	bt_devices = AltosBTKnown.bt_known().list(product); -		num_devices += bt_devices.size(); -		AltosDevice[]			devices = new AltosDevice[num_devices]; - -		for (int i = 0; i < usb_devices.size(); i++) -			devices[i] = usb_devices.get(i); -		int off = usb_devices.size(); -		for (int j = 0; j < bt_devices.size(); j++) -			devices[off + j] = bt_devices.get(j); -		return devices; -	} +	public abstract AltosDevice[] devices(); -	private void update_devices() { +	public void update_devices() {  		AltosDevice[] devices = devices();  		list.setListData(devices);  		select_button.setEnabled(devices.length > 0);  	} -	private AltosDeviceDialog (Frame in_frame, Component location, int in_product) { +	public void add_bluetooth() { } + +	public AltosDeviceDialog (Frame in_frame, Component location, int in_product) {  		super(in_frame, "Device Selection", true);  		product = in_product; @@ -69,10 +58,6 @@ public class AltosDeviceDialog extends AltosDialog implements ActionListener {  		cancel_button.setActionCommand("cancel");  		cancel_button.addActionListener(this); -		manage_bluetooth_button = new JButton("Manage Bluetooth"); -		manage_bluetooth_button.setActionCommand("manage"); -		manage_bluetooth_button.addActionListener(this); -  		select_button = new JButton("Select");  		select_button.setActionCommand("select");  		select_button.addActionListener(this); @@ -139,14 +124,15 @@ public class AltosDeviceDialog extends AltosDialog implements ActionListener {  		listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));  		//Lay out the buttons from left to right. -		JPanel buttonPane = new JPanel(); +		buttonPane = new JPanel();  		buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));  		buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));  		buttonPane.add(Box.createHorizontalGlue());  		buttonPane.add(cancel_button);  		buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); -		buttonPane.add(manage_bluetooth_button); -		buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + +		add_bluetooth(); +  		buttonPane.add(select_button);  		//Put everything together, using the content pane's BorderLayout. @@ -163,23 +149,12 @@ public class AltosDeviceDialog extends AltosDialog implements ActionListener {  	//Handle clicks on the Set and Cancel buttons.  	public void actionPerformed(ActionEvent e) { -		if ("select".equals(e.getActionCommand())) +		if ("select".equals(e.getActionCommand())) {  			value = (AltosDevice)(list.getSelectedValue()); -		if ("manage".equals(e.getActionCommand())) { -			AltosBTManage.show(frame, AltosBTKnown.bt_known()); -			update_devices(); -			return; +			setVisible(false);  		} -		setVisible(false); +		if ("cancel".equals(e.getActionCommand())) +			setVisible(false);  	} -	public static AltosDevice show (Component frameComp, int product) { - -		Frame				frame = JOptionPane.getFrameForComponent(frameComp); -		AltosDeviceDialog	dialog; - -		dialog = new AltosDeviceDialog(frame, frameComp, product); -		dialog.setVisible(true); -		return dialog.getValue(); -	}  } diff --git a/altosui/AltosFontListener.java b/altosuilib/AltosFontListener.java index 0dda0f29..ef543264 100644 --- a/altosui/AltosFontListener.java +++ b/altosuilib/AltosFontListener.java @@ -15,7 +15,7 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altosuilib;  public interface AltosFontListener {  	void font_size_changed(int font_size); diff --git a/altosuilib/AltosUIConfigure.java b/altosuilib/AltosUIConfigure.java new file mode 100644 index 00000000..6c9a841e --- /dev/null +++ b/altosuilib/AltosUIConfigure.java @@ -0,0 +1,274 @@ +/* + * 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; + +import java.awt.*; +import java.awt.event.*; +import java.beans.*; +import javax.swing.*; +import javax.swing.event.*; + +class DelegatingRenderer implements ListCellRenderer { + +	// ... +	public static void install(JComboBox comboBox) { +		DelegatingRenderer renderer = new DelegatingRenderer(comboBox); +		renderer.initialise(); +		comboBox.setRenderer(renderer); +	} + +	// ... +	private final JComboBox comboBox; + +	// ... +	private ListCellRenderer delegate; + +	// ... +	private DelegatingRenderer(JComboBox comboBox) { +		this.comboBox = comboBox; +	} + +	// ... +	private void initialise() { +		delegate = new JComboBox().getRenderer(); +		comboBox.addPropertyChangeListener("UI", new PropertyChangeListener() { + +				public void propertyChange(PropertyChangeEvent evt) { +					delegate = new JComboBox().getRenderer(); +				} +			}); +	} + +	// ... +	public Component getListCellRendererComponent(JList list, +						      Object value, int index, boolean isSelected, boolean cellHasFocus) { + +		return delegate.getListCellRendererComponent(list, +							     ((UIManager.LookAndFeelInfo) value).getName(), +							     index, isSelected, cellHasFocus); +	} +} + +public class AltosUIConfigure +	extends AltosUIDialog +{ +	public JFrame		owner; +	public Container	pane; + +	public int		row; + +	final static String[] font_size_names = { "Small", "Medium", "Large" }; + +	public GridBagConstraints constraints (int x, int width, int fill) { +		GridBagConstraints c = new GridBagConstraints(); +		Insets insets = new Insets(4, 4, 4, 4); + +		c.insets = insets; +		c.fill = fill; +		if (width == 3) +			c.anchor = GridBagConstraints.CENTER; +		else if (x == 2) +			c.anchor = GridBagConstraints.EAST; +		else +			c.anchor = GridBagConstraints.WEST; +		c.gridx = x; +		c.gridwidth = width; +		c.gridy = row; +		return c; +	} + +	public GridBagConstraints constraints(int x, int width) { +		return constraints(x, width, GridBagConstraints.NONE); +	} + +	public void add_voice() { +	} + +	public void add_log_dir() { +		/* Log directory settings */ +		pane.add(new JLabel("Log Directory"), constraints(0, 1)); + +		final JButton configure_log = new JButton(AltosUIPreferences.logdir().getPath()); +		configure_log.addActionListener(new ActionListener() { +				public void actionPerformed(ActionEvent e) { +					AltosUIPreferences.ConfigureLog(); +					configure_log.setText(AltosUIPreferences.logdir().getPath()); +				} +			}); +		pane.add(configure_log, constraints(1, 2)); +		configure_log.setToolTipText("Which directory flight logs are stored in"); +		row++; +	} + +	public void add_callsign() { +	} + +	public void add_units() { +		/* Imperial units setting */ +		pane.add(new JLabel("Imperial Units"), constraints(0, 1)); + +		JRadioButton imperial_units = new JRadioButton("Enable", AltosUIPreferences.imperial_units()); +		imperial_units.addActionListener(new ActionListener() { +				public void actionPerformed(ActionEvent e) { +					JRadioButton item = (JRadioButton) e.getSource(); +					boolean enabled = item.isSelected(); +					AltosUIPreferences.set_imperial_units(enabled); +				} +			}); +		imperial_units.setToolTipText("Use Imperial units instead of metric"); +		pane.add(imperial_units, constraints(1, 2)); +		row++; +	} + +	public void add_font_size() { +		/* Font size setting */ +		pane.add(new JLabel("Font size"), constraints(0, 1)); + +		final JComboBox font_size_value = new JComboBox(font_size_names); +		int font_size = AltosUIPreferences.font_size(); +		font_size_value.setSelectedIndex(font_size - AltosUILib.font_size_small); +		font_size_value.addActionListener(new ActionListener() { +				public void actionPerformed(ActionEvent e) { +					int	size = font_size_value.getSelectedIndex() + AltosUILib.font_size_small; + +					AltosUIPreferences.set_font_size(size); +				} +			}); +		pane.add(font_size_value, constraints(1, 2, GridBagConstraints.BOTH)); +		font_size_value.setToolTipText("Font size used in telemetry window"); +		row++; +	} + +	public void add_look_and_feel() { +		/* Look & Feel setting */ +		pane.add(new JLabel("Look & feel"), constraints(0, 1)); + +		/* +		class LookAndFeelRenderer extends BasicComboBoxRenderer implements ListCellRenderer { + +			public LookAndFeelRenderer() { +				super(); +			} + +			public Component getListCellRendererComponent( +				JList list, +				Object value, +				int index, +				boolean isSelected, +				boolean cellHasFocus) +			{ +				super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); +				setText(((UIManager.LookAndFeelInfo) value).getName()); +				return this; +			} +		} +		*/ + +		final UIManager.LookAndFeelInfo[] look_and_feels = UIManager.getInstalledLookAndFeels(); + +		final JComboBox look_and_feel_value = new JComboBox(look_and_feels); + +		DelegatingRenderer.install(look_and_feel_value); + +		String look_and_feel  = AltosUIPreferences.look_and_feel(); +		for (int i = 0; i < look_and_feels.length; i++) +			if (look_and_feel.equals(look_and_feels[i].getClassName())) +				look_and_feel_value.setSelectedIndex(i); + +		look_and_feel_value.addActionListener(new ActionListener() { +				public void actionPerformed(ActionEvent e) { +					int	id = look_and_feel_value.getSelectedIndex(); + +					AltosUIPreferences.set_look_and_feel(look_and_feels[id].getClassName()); +				} +			}); +		pane.add(look_and_feel_value, constraints(1, 2, GridBagConstraints.BOTH)); +		look_and_feel_value.setToolTipText("Look&feel used for new windows"); +		row++; +	} + +	public void add_serial_debug() { +		GridBagConstraints c = new GridBagConstraints(); + +		/* Serial debug setting */ +		pane.add(new JLabel("Serial Debug"), constraints(0, 1)); + +		JRadioButton serial_debug = new JRadioButton("Enable", AltosUIPreferences.serial_debug()); +		serial_debug.addActionListener(new ActionListener() { +				public void actionPerformed(ActionEvent e) { +					JRadioButton item = (JRadioButton) e.getSource(); +					boolean enabled = item.isSelected(); +					AltosUIPreferences.set_serial_debug(enabled); +				} +			}); +		serial_debug.setToolTipText("Enable/Disable USB I/O getting sent to the console"); +		c.gridx = 1; +		c.gridy = row++; +		c.gridwidth = 3; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.WEST; +		pane.add(serial_debug, c); +	} + +	public void add_bluetooth() { +	} + +	public void add_frequencies() { +	} + +	public AltosUIConfigure(JFrame in_owner) { +		super(in_owner, "Configure AltosUI", false); + +		owner = in_owner; +		pane = getContentPane(); +		pane.setLayout(new GridBagLayout()); + +		row = 0; + +		/* Nice label at the top */ +		pane.add(new JLabel ("Configure AltOS UI"), +			 constraints(0, 3)); +		row++; + +		pane.add(new JLabel (String.format("AltOS version %s", AltosUIVersion.version)), +			 constraints(0, 3)); +		row++; + +		add_voice(); +		add_log_dir(); +		add_callsign(); +		add_units(); +		add_font_size(); +		add_look_and_feel(); +		add_bluetooth(); +		add_frequencies(); + +		/* And a close button at the bottom */ +		JButton close = new JButton("Close"); +		close.addActionListener(new ActionListener() { +				public void actionPerformed(ActionEvent e) { +					setVisible(false); +				} +			}); +		pane.add(close, constraints(0, 3)); + +		pack(); +		setLocationRelativeTo(owner); +		setVisible(true); +	} +} diff --git a/altosui/AltosDialog.java b/altosuilib/AltosUIDialog.java index c2a9d6e6..c0c33ba6 100644 --- a/altosui/AltosDialog.java +++ b/altosuilib/AltosUIDialog.java @@ -15,45 +15,45 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altosuilib;  import java.awt.*;  import java.awt.event.*;  import javax.swing.*; -class AltosDialogListener extends WindowAdapter { +class AltosUIDialogListener extends WindowAdapter {  	public void windowClosing (WindowEvent e) { -		AltosUIPreferences.unregister_ui_listener((AltosDialog) e.getWindow()); +		AltosUIPreferences.unregister_ui_listener((AltosUIDialog) e.getWindow());  	}  } -public class AltosDialog extends JDialog implements AltosUIListener { +public class AltosUIDialog extends JDialog implements AltosUIListener {  	public void ui_changed(String look_and_feel) {  		SwingUtilities.updateComponentTreeUI(this);  		this.pack();  	} -	public AltosDialog() { +	public AltosUIDialog() {  		AltosUIPreferences.register_ui_listener(this); -		addWindowListener(new AltosDialogListener()); +		addWindowListener(new AltosUIDialogListener());  	} -	public AltosDialog(Frame frame, String label, boolean modal) { +	public AltosUIDialog(Frame frame, String label, boolean modal) {  		super(frame, label, modal);  		AltosUIPreferences.register_ui_listener(this); -		addWindowListener(new AltosDialogListener()); +		addWindowListener(new AltosUIDialogListener());  	} -	public AltosDialog(Dialog dialog, String label, boolean modal) { +	public AltosUIDialog(Dialog dialog, String label, boolean modal) {  		super(dialog, label, modal);  		AltosUIPreferences.register_ui_listener(this); -		addWindowListener(new AltosDialogListener()); +		addWindowListener(new AltosUIDialogListener());  	} -	public AltosDialog(Frame frame, boolean modal) { +	public AltosUIDialog(Frame frame, boolean modal) {  		super(frame, modal);  		AltosUIPreferences.register_ui_listener(this); -		addWindowListener(new AltosDialogListener()); +		addWindowListener(new AltosUIDialogListener());  	}  } diff --git a/altosui/AltosFrame.java b/altosuilib/AltosUIFrame.java index 731a29b4..409aea2e 100644 --- a/altosui/AltosFrame.java +++ b/altosuilib/AltosUIFrame.java @@ -15,27 +15,27 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altosuilib;  import java.awt.*;  import java.awt.event.*;  import javax.swing.*;  import java.util.*; -class AltosFrameListener extends WindowAdapter { +class AltosUIFrameListener extends WindowAdapter {  	public void windowClosing (WindowEvent e) { -		AltosUIPreferences.unregister_ui_listener((AltosFrame) e.getWindow()); +		AltosUIPreferences.unregister_ui_listener((AltosUIFrame) e.getWindow());  	}  } -public class AltosFrame extends JFrame implements AltosUIListener { +public class AltosUIFrame extends JFrame implements AltosUIListener {  	public void ui_changed(String look_and_feel) {  		SwingUtilities.updateComponentTreeUI(this);  		this.pack();  	} -	static final String[] icon_names = { +	static String[] altos_icon_names = {  		"/altus-metrum-16.png",  		"/altus-metrum-32.png",  		"/altus-metrum-48.png", @@ -44,28 +44,39 @@ public class AltosFrame extends JFrame implements AltosUIListener {  		"/altus-metrum-256.png"  	}; +	static public String[] icon_names; +	 +	static public void set_icon_names(String[] new_icon_names) { icon_names = new_icon_names; } + +	public String[] icon_names() { +		if (icon_names == null) +			set_icon_names(altos_icon_names); +		return icon_names; +	} +  	public void set_icon() {  		ArrayList<Image> icons = new ArrayList<Image>(); +		String[] icon_names = icon_names();  		for (int i = 0; i < icon_names.length; i++) { -			java.net.URL imgURL = AltosUI.class.getResource(icon_names[i]); +			java.net.URL imgURL = AltosUIFrame.class.getResource(icon_names[i]);  			if (imgURL != null)  				icons.add(new ImageIcon(imgURL).getImage());  		} -  		setIconImages(icons);  	} -	public AltosFrame() { + +	public AltosUIFrame() {  		AltosUIPreferences.register_ui_listener(this); -		addWindowListener(new AltosFrameListener()); +		addWindowListener(new AltosUIFrameListener());  		set_icon();  	} -	public AltosFrame(String name) { +	public AltosUIFrame(String name) {  		super(name);  		AltosUIPreferences.register_ui_listener(this); -		addWindowListener(new AltosFrameListener()); +		addWindowListener(new AltosUIFrameListener());  		set_icon();  	}  } diff --git a/altosuilib/AltosUILib.java b/altosuilib/AltosUILib.java new file mode 100644 index 00000000..5d5f9aaa --- /dev/null +++ b/altosuilib/AltosUILib.java @@ -0,0 +1,93 @@ +/* + * 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; + +import java.awt.*; +import libaltosJNI.*; + +import org.altusmetrum.AltosLib.*; + +public class AltosUILib extends AltosLib { + +	public static final int tab_elt_pad = 5; + +	public static Font label_font; +	public static Font value_font; +	public static Font status_font; +	public static Font table_label_font; +	public static Font table_value_font; + +	final public static int font_size_small = 1; +	final public static int font_size_medium = 2; +	final public static int font_size_large = 3; + +	static void set_fonts(int size) { +		int	brief_size; +		int	table_size; +		int	status_size; + +		switch (size) { +		case font_size_small: +			brief_size = 16; +			status_size = 18; +			table_size = 11; +			break; +		default: +		case font_size_medium: +			brief_size = 22; +			status_size = 24; +			table_size = 14; +			break; +		case font_size_large: +			brief_size = 26; +			status_size = 30; +			table_size = 17; +			break; +		} +		label_font = new Font("Dialog", Font.PLAIN, brief_size); +		value_font = new Font("Monospaced", Font.PLAIN, brief_size); +		status_font = new Font("SansSerif", Font.BOLD, status_size); +		table_label_font = new Font("SansSerif", Font.PLAIN, table_size); +		table_value_font = new Font("Monospaced", Font.PLAIN, table_size); +	} + +	static final int text_width = 20; + +	static public boolean initialized = false; +	static public boolean loaded_library = false; + +	public static boolean load_library() { +		if (!initialized) { +			try { +				System.loadLibrary("altos"); +				libaltos.altos_init(); +				loaded_library = true; +			} catch (UnsatisfiedLinkError e) { +				try { +					System.loadLibrary("altos64"); +					libaltos.altos_init(); +					loaded_library = true; +				} catch (UnsatisfiedLinkError e2) { +					loaded_library = false; +				} +			} +			initialized = true; +		} +		return loaded_library; +	} +} diff --git a/altosui/AltosUIListener.java b/altosuilib/AltosUIListener.java index 7ee62afc..f4127f58 100644 --- a/altosui/AltosUIListener.java +++ b/altosuilib/AltosUIListener.java @@ -15,7 +15,7 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altosuilib;  public interface AltosUIListener {  	public void ui_changed(String look_and_feel); diff --git a/altosuilib/AltosUIPreferences.java b/altosuilib/AltosUIPreferences.java new file mode 100644 index 00000000..485cb582 --- /dev/null +++ b/altosuilib/AltosUIPreferences.java @@ -0,0 +1,180 @@ +/* + * 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.altosuilib; + +import java.io.*; +import java.util.*; +import java.awt.Component; +import javax.swing.*; +import org.altusmetrum.AltosLib.*; + +public class AltosUIPreferences extends AltosPreferences { + +	/* font size preferences name */ +	final static String fontSizePreference = "FONT-SIZE"; + +	/* Look&Feel preference name */ +	final static String lookAndFeelPreference = "LOOK-AND-FEEL"; + +	/* UI Component to pop dialogs up */ +	static Component component; + +	static LinkedList<AltosFontListener> font_listeners; + +	static int font_size = AltosUILib.font_size_medium; + +	static LinkedList<AltosUIListener> ui_listeners; + +	static String look_and_feel = null; + +	/* Serial debug */ +	public static boolean serial_debug; + +	public static void init() { +		AltosPreferences.init(new AltosUIPreferencesBackend()); + +		font_listeners = new LinkedList<AltosFontListener>(); + +		font_size = backend.getInt(fontSizePreference, AltosUILib.font_size_medium); +		AltosUILib.set_fonts(font_size); +		look_and_feel = backend.getString(lookAndFeelPreference, UIManager.getSystemLookAndFeelClassName()); + +		ui_listeners = new LinkedList<AltosUIListener>(); +		serial_debug = backend.getBoolean(serialDebugPreference, false); +		AltosLink.set_debug(serial_debug); +	} + +	static { init(); } + +	public static void set_component(Component in_component) { +		component = in_component; +	} + +	private static boolean check_dir(File dir) { +		if (!dir.exists()) { +			if (!dir.mkdirs()) { +				JOptionPane.showMessageDialog(component, +							      dir.getName(), +							      "Cannot create directory", +							      JOptionPane.ERROR_MESSAGE); +				return false; +			} +		} else if (!dir.isDirectory()) { +			JOptionPane.showMessageDialog(component, +						      dir.getName(), +						      "Is not a directory", +						      JOptionPane.ERROR_MESSAGE); +			return false; +		} +		return true; +	} + +	/* Configure the log directory. This is where all telemetry and eeprom files +	 * will be written to, and where replay will look for telemetry files +	 */ +	public static void ConfigureLog() { +		JFileChooser	logdir_chooser = new JFileChooser(logdir.getParentFile()); + +		logdir_chooser.setDialogTitle("Configure Data Logging Directory"); +		logdir_chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + +		if (logdir_chooser.showDialog(component, "Select Directory") == JFileChooser.APPROVE_OPTION) { +			File dir = logdir_chooser.getSelectedFile(); +			if (check_dir(dir)) +				set_logdir(dir); +		} +	} +	public static int font_size() { +		synchronized (backend) { +			return font_size; +		} +	} + +	static void set_fonts() { +	} + +	public static void set_font_size(int new_font_size) { +		synchronized (backend) { +			font_size = new_font_size; +			backend.putInt(fontSizePreference, font_size); +			flush_preferences(); +			AltosUILib.set_fonts(font_size); +			for (AltosFontListener l : font_listeners) +				l.font_size_changed(font_size); +		} +	} + +	public static void register_font_listener(AltosFontListener l) { +		synchronized (backend) { +			font_listeners.add(l); +		} +	} + +	public static void unregister_font_listener(AltosFontListener l) { +		synchronized (backend) { +			font_listeners.remove(l); +		} +	} + +	public static void set_look_and_feel(String new_look_and_feel) { +		try { +			UIManager.setLookAndFeel(new_look_and_feel); +		} catch (Exception e) { +		} +		synchronized(backend) { +			look_and_feel = new_look_and_feel; +			backend.putString(lookAndFeelPreference, look_and_feel); +			flush_preferences(); +			for (AltosUIListener l : ui_listeners) +				l.ui_changed(look_and_feel); +		} +	} + +	public static String look_and_feel() { +		synchronized (backend) { +			return look_and_feel; +		} +	} + +	public static void register_ui_listener(AltosUIListener l) { +		synchronized(backend) { +			ui_listeners.add(l); +		} +	} + +	public static void unregister_ui_listener(AltosUIListener l) { +		synchronized (backend) { +			ui_listeners.remove(l); +		} +	} +	public static void set_serial_debug(boolean new_serial_debug) { +		AltosLink.set_debug(new_serial_debug); +		synchronized (backend) { +			serial_debug = new_serial_debug; +			backend.putBoolean(serialDebugPreference, serial_debug); +			flush_preferences(); +		} +	} + +	public static boolean serial_debug() { +		synchronized (backend) { +			return serial_debug; +		} +	} + +} diff --git a/altosuilib/AltosUIPreferencesBackend.java b/altosuilib/AltosUIPreferencesBackend.java new file mode 100644 index 00000000..c6c05e55 --- /dev/null +++ b/altosuilib/AltosUIPreferencesBackend.java @@ -0,0 +1,101 @@ +/* + * Copyright © 2012 Mike Beattie <mike@ethernal.org> + * + * 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; + +import java.io.File; +import java.util.prefs.*; +import org.altusmetrum.AltosLib.*; +import javax.swing.filechooser.FileSystemView; + +public class AltosUIPreferencesBackend implements AltosPreferencesBackend { + +	private Preferences _preferences = null; +	 +	public AltosUIPreferencesBackend() { +		_preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); +	} + +	public AltosUIPreferencesBackend(Preferences in_preferences) { +		_preferences = in_preferences; +	} + +	public String  getString(String key, String def) { +		return _preferences.get(key, def); +	} +	public void    putString(String key, String value) { +		_preferences.put(key, value); +	} + +	public int     getInt(String key, int def) { +		return _preferences.getInt(key, def); +	} +	public void    putInt(String key, int value) { +		_preferences.putInt(key, value); +	} + +	public double  getDouble(String key, double def) { +		return _preferences.getDouble(key, def); +	} +	public void    putDouble(String key, double value) { +		_preferences.putDouble(key, value); +	} + +	public boolean getBoolean(String key, boolean def) { +		return _preferences.getBoolean(key, def); +	} +	public void    putBoolean(String key, boolean value) { +		_preferences.putBoolean(key, value); +	} + +	public boolean nodeExists(String key) { +		try { +			return _preferences.nodeExists(key); +		} catch (BackingStoreException be) { +			return false; +		} +	} + +	public AltosPreferencesBackend node(String key) { +		return new AltosUIPreferencesBackend(_preferences.node(key)); +	} + +	public String[] keys() { +		try { +			return _preferences.keys(); +		} catch (BackingStoreException be) { +			return null; +		} +	} + +	public void remove(String key) { +		_preferences.remove(key); +	} + +	public void    flush() { +		try { +			_preferences.flush(); +		} catch (BackingStoreException ee) { +			System.err.printf("Cannot save preferences\n"); +		} +	} + +	public File homeDirectory() { +		/* Use the file system view default directory */ +		return FileSystemView.getFileSystemView().getDefaultDirectory(); +	} +} diff --git a/altosui/AltosVersion.java.in b/altosuilib/AltosUIVersion.java.in index b0b3c0cf..6fb3b38b 100644 --- a/altosui/AltosVersion.java.in +++ b/altosuilib/AltosUIVersion.java.in @@ -15,8 +15,8 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altosuilib; -public class AltosVersion { +public class AltosUIVersion {  	public final static String version = "@VERSION@";  } diff --git a/altosui/AltosUSBDevice.java b/altosuilib/AltosUSBDevice.java index 3af7a7fa..bab16fb0 100644 --- a/altosui/AltosUSBDevice.java +++ b/altosuilib/AltosUSBDevice.java @@ -15,7 +15,8 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altosuilib; +  import java.util.*;  import libaltosJNI.*; @@ -49,12 +50,12 @@ public class AltosUSBDevice  extends altos_device implements AltosDevice {  		return libaltos.altos_open(this);  	} -	private boolean isAltusMetrum() { -		if (getVendor() != Altos.vendor_altusmetrum) +	public boolean isAltusMetrum() { +		if (getVendor() != AltosUILib.vendor_altusmetrum)  			return false; -		if (getProduct() < Altos.product_altusmetrum_min) +		if (getProduct() < AltosUILib.product_altusmetrum_min)  			return false; -		if (getProduct() > Altos.product_altusmetrum_max) +		if (getProduct() > AltosUILib.product_altusmetrum_max)  			return false;  		return true;  	} @@ -64,22 +65,22 @@ public class AltosUSBDevice  extends altos_device implements AltosDevice {  		if (!isAltusMetrum())  			return false; -		if (want_product == Altos.product_any) +		if (want_product == AltosUILib.product_any)  			return true; -		if (want_product == Altos.product_basestation) -			return matchProduct(Altos.product_teledongle) || -				matchProduct(Altos.product_teleterra) || -				matchProduct(Altos.product_telebt) || -				matchProduct(Altos.product_megadongle); +		if (want_product == AltosUILib.product_basestation) +			return matchProduct(AltosUILib.product_teledongle) || +				matchProduct(AltosUILib.product_teleterra) || +				matchProduct(AltosUILib.product_telebt) || +				matchProduct(AltosUILib.product_megadongle); -		if (want_product == Altos.product_altimeter) -			return matchProduct(Altos.product_telemetrum) || -				matchProduct(Altos.product_megametrum); +		if (want_product == AltosUILib.product_altimeter) +			return matchProduct(AltosUILib.product_telemetrum) || +				matchProduct(AltosUILib.product_megametrum);  		int have_product = getProduct(); -		if (have_product == Altos.product_altusmetrum)	/* old devices match any request */ +		if (have_product == AltosUILib.product_altusmetrum)	/* old devices match any request */  			return true;  		if (want_product == have_product) @@ -88,8 +89,8 @@ public class AltosUSBDevice  extends altos_device implements AltosDevice {  		return false;  	} -	static java.util.List<AltosDevice> list(int product) { -		if (!Altos.load_library()) +	static public java.util.List<AltosDevice> list(int product) { +		if (!AltosUILib.load_library())  			return null;  		SWIGTYPE_p_altos_list list = libaltos.altos_list_start(); diff --git a/altosuilib/AltosUnitsListener.java b/altosuilib/AltosUnitsListener.java new file mode 100644 index 00000000..22c66cd4 --- /dev/null +++ b/altosuilib/AltosUnitsListener.java @@ -0,0 +1,22 @@ +/* + * 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.altosuilib; + +public interface AltosUnitsListener { +	public void units_changed(); +} diff --git a/altosuilib/Makefile.am b/altosuilib/Makefile.am new file mode 100644 index 00000000..da5fb848 --- /dev/null +++ b/altosuilib/Makefile.am @@ -0,0 +1,43 @@ +AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation + +JAVAROOT=bin + +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="$(JAVAROOT):../altoslib/*:../libaltos:/usr/share/java/*" + +SRC=. + +altosuilibdir = $(datadir)/java + +altosuilib_JAVA = \ +	AltosUIConfigure.java \ +	AltosDevice.java \ +	AltosDeviceDialog.java \ +	AltosUSBDevice.java \ +	AltosFontListener.java \ +	AltosUIDialog.java \ +	AltosUIFrame.java \ +	AltosUILib.java \ +	AltosUIListener.java \ +	AltosUIPreferencesBackend.java \ +	AltosUIPreferences.java \ +	AltosUIVersion.java \ +	AltosUnitsListener.java + +JAR=altosuilib.jar + +all-local: $(JAR) + +clean-local: +	-rm -rf $(JAVAROOT) $(JAR) + +install-altosuilibJAVA: $(JAR) +	@$(NORMAL_INSTALL) +	test -z "$(altosuilibdir)" || $(MKDIR_P) "$(DESTDIR)$(altosuilibdir)" +	echo " $(INSTALL_DATA)" "$(JAR)" "'$(DESTDIR)$(altosuilibdir)/$(JAR)"; \ +	$(INSTALL_DATA) "$(JAR)" "$(DESTDIR)$(altosuilibdir)" + +$(JAVAROOT): +	mkdir -p $(JAVAROOT) + +$(JAR): classaltosuilib.stamp +	jar cf $@ -C $(JAVAROOT) . diff --git a/configure.ac b/configure.ac index 0fcd97e2..ee685344 100644 --- a/configure.ac +++ b/configure.ac @@ -146,10 +146,13 @@ AM_CONDITIONAL([LIBSTLINK], [test x$HAVE_STLINK != xno])  AC_OUTPUT([  Makefile  altoslib/Makefile +altosuilib/Makefile +altosuilib/AltosUIVersion.java  altosui/Makefile -altosui/AltosVersion.java  altosui/Info.plist -altosui/libaltos/Makefile +libaltos/Makefile +micropeak/Makefile +micropeak/Info.plist  altosdroid/Makefile  altosdroid/local.properties  ao-tools/Makefile diff --git a/icon/altus-metrum.ico b/icon/altus-metrum.icoBinary files differ index e32b4f1e..bedf04ef 100644 --- a/icon/altus-metrum.ico +++ b/icon/altus-metrum.ico diff --git a/icon/micro-peak.ico b/icon/micro-peak.icoBinary files differ new file mode 100644 index 00000000..b672aa04 --- /dev/null +++ b/icon/micro-peak.ico diff --git a/icon/micropeak-128.png b/icon/micropeak-128.pngBinary files differ new file mode 100644 index 00000000..f045dc6a --- /dev/null +++ b/icon/micropeak-128.png diff --git a/icon/micropeak-16.png b/icon/micropeak-16.pngBinary files differ new file mode 100644 index 00000000..d8140802 --- /dev/null +++ b/icon/micropeak-16.png diff --git a/icon/micropeak-256.png b/icon/micropeak-256.pngBinary files differ new file mode 100644 index 00000000..b96d4706 --- /dev/null +++ b/icon/micropeak-256.png diff --git a/icon/micropeak-32.png b/icon/micropeak-32.pngBinary files differ new file mode 100644 index 00000000..d34c5c12 --- /dev/null +++ b/icon/micropeak-32.png diff --git a/icon/micropeak-48.png b/icon/micropeak-48.pngBinary files differ new file mode 100644 index 00000000..86dc4f7f --- /dev/null +++ b/icon/micropeak-48.png diff --git a/icon/micropeak-64.png b/icon/micropeak-64.pngBinary files differ new file mode 100644 index 00000000..6ca7c2eb --- /dev/null +++ b/icon/micropeak-64.png diff --git a/altosui/libaltos/.gitignore b/libaltos/.gitignore index c490e6f8..c490e6f8 100644 --- a/altosui/libaltos/.gitignore +++ b/libaltos/.gitignore diff --git a/altosui/libaltos/Makefile-standalone b/libaltos/Makefile-standalone index 4e438050..a1f9f5bc 100644 --- a/altosui/libaltos/Makefile-standalone +++ b/libaltos/Makefile-standalone @@ -22,9 +22,20 @@ endif  #  ifeq ($(OS),Darwin) +#OS_LIB_CFLAGS=\ +#	-DDARWIN -DPOSIX_TTY -arch i386 -arch x86_64 \ +#	--sysroot=/Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 \ +#	-iwithsysroot /System/Library/Frameworks/JavaVM.framework/Headers \ +#	-iwithsysroot /System/Library/Frameworks/IOKit.framework/Headers \ +#	-iwithsysroot /System/Library/Frameworks/CoreFoundation.framework/Headers + +XCODE=/Applications/Xcode.app +SDK=$(XCODE)/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk +MINVERSION=10.5 +  OS_LIB_CFLAGS=\ -	-DDARWIN -DPOSIX_TTY -arch i386 -arch x86_64 \ -	--sysroot=/Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 \ +	-DDARWIN -DPOSIX_TTY -arch i386 -arch x86_64 -isysroot $(SDK) \ +	-mmacosx-version-min=10.5 \  	-iwithsysroot /System/Library/Frameworks/JavaVM.framework/Headers \  	-iwithsysroot /System/Library/Frameworks/IOKit.framework/Headers \  	-iwithsysroot /System/Library/Frameworks/CoreFoundation.framework/Headers diff --git a/altosui/libaltos/Makefile.am b/libaltos/Makefile.am index b5ab1ddb..b5ab1ddb 100644 --- a/altosui/libaltos/Makefile.am +++ b/libaltos/Makefile.am diff --git a/altosui/libaltos/cjnitest.c b/libaltos/cjnitest.c index f0fe78f7..f0fe78f7 100644 --- a/altosui/libaltos/cjnitest.c +++ b/libaltos/cjnitest.c diff --git a/altosui/libaltos/libaltos.c b/libaltos/libaltos.c index ab6ca878..ca56746a 100644 --- a/altosui/libaltos/libaltos.c +++ b/libaltos/libaltos.c @@ -20,16 +20,6 @@  #include <stdlib.h>  #include <string.h> -#define USB_VENDOR_FSF			0xfffe -#define USB_VENDOR_ALTUSMETRUM		USB_VENDOR_FSF -#define USB_PRODUCT_ALTUSMETRUM		0x000a -#define USB_PRODUCT_ALTUSMETRUM_MIN	0x000a -#define USB_PRODUCT_ALTUSMETRUM_MAX	0x00ff - -#define USB_IS_ALTUSMETRUM(v,p)	((v) == USB_VENDOR_ALTUSMETRUM && \ -		(USB_PRODUCT_ALTUSMETRUM_MIN <= (p) && \ -		 (p) <= USB_PRODUCT_ALTUSMETRUM_MAX)) -  #define BLUETOOTH_PRODUCT_TELEBT	"TeleBT"  #define USE_POLL @@ -158,6 +148,8 @@ altos_open(struct altos_device *device)  		return NULL;  	}  	cfmakeraw(&term); +	cfsetospeed(&term, B9600); +	cfsetispeed(&term, B9600);  #ifdef USE_POLL  	term.c_cc[VMIN] = 1;  	term.c_cc[VTIME] = 0; @@ -473,6 +465,7 @@ usb_tty(char *sys)  				base, config, interface);  			endpoint_full = cc_fullname(sys, endpoint_base); +  			/* Check for tty:ttyACMx style names  			 */  			ntty = scandir(endpoint_full, &namelist, @@ -488,16 +481,29 @@ usb_tty(char *sys)  			/* Check for tty/ttyACMx style names  			 */  			tty_dir = cc_fullname(endpoint_full, "tty"); -			free(endpoint_full);  			ntty = scandir(tty_dir, &namelist,  				       dir_filter_tty,  				       alphasort);  			free (tty_dir);  			if (ntty > 0) {  				tty = cc_fullname("/dev", namelist[0]->d_name); +				free(endpoint_full); +				free(namelist); +				return tty; +			} + +			/* Check for ttyACMx style names +			 */ +			ntty = scandir(endpoint_full, &namelist, +				       dir_filter_tty, +				       alphasort); +			free(endpoint_full); +			if (ntty > 0) { +				tty = cc_fullname("/dev", namelist[0]->d_name);  				free(namelist);  				return tty;  			} +  		}  	}  	return NULL; @@ -507,7 +513,11 @@ static struct altos_usbdev *  usb_scan_device(char *sys)  {  	struct altos_usbdev *usbdev; +	char *tty; +	tty = usb_tty(sys); +	if (!tty) +		return NULL;  	usbdev = calloc(1, sizeof (struct altos_usbdev));  	if (!usbdev)  		return NULL; @@ -517,7 +527,7 @@ usb_scan_device(char *sys)  	usbdev->serial = load_dec(sys, "serial");  	usbdev->idProduct = load_hex(sys, "idProduct");  	usbdev->idVendor = load_hex(sys, "idVendor"); -	usbdev->tty = usb_tty(sys); +	usbdev->tty = tty;  	return usbdev;  } @@ -581,27 +591,34 @@ altos_list_start(void)  	for (e = 0; e < n; e++) {  		dir = cc_fullname(USB_DEVICES, ents[e]->d_name);  		dev = usb_scan_device(dir); +		if (!dev) +			continue;  		free(dir); -		if (USB_IS_ALTUSMETRUM(dev->idVendor, dev->idProduct)) { -			if (devs->dev) -				devs->dev = realloc(devs->dev, -						    (devs->ndev + 1) * sizeof (struct usbdev *)); -			else -				devs->dev = malloc (sizeof (struct usbdev *)); -			devs->dev[devs->ndev++] = dev; -		} +		if (devs->dev) +			devs->dev = realloc(devs->dev, +					    (devs->ndev + 1) * sizeof (struct usbdev *)); +		else +			devs->dev = malloc (sizeof (struct usbdev *)); +		devs->dev[devs->ndev++] = dev;  	}  	free(ents);  	devs->current = 0;  	return devs;  } +PUBLIC struct altos_list * +altos_ftdi_list_start(void) +{ +	return altos_list_start(); +} +  int  altos_list_next(struct altos_list *list, struct altos_device *device)  {  	struct altos_usbdev *dev; -	if (list->current >= list->ndev) +	if (list->current >= list->ndev) {  		return 0; +	}  	dev = list->dev[list->current];  	strcpy(device->name, dev->product_name);  	device->vendor = dev->idVendor; @@ -774,6 +791,7 @@ no_file:  struct altos_list {  	io_iterator_t iterator; +	int ftdi;  };  static int @@ -831,8 +849,21 @@ altos_list_start(void)  	int i;  	ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator); -	if (ret != kIOReturnSuccess) +	if (ret != kIOReturnSuccess) { +		free(list);  		return NULL; +	} +	list->ftdi = 0; +	return list; +} + +PUBLIC struct altos_list * +altos_ftdi_list_start(void) +{ +	struct altos_list *list = altos_list_start(); + +	if (list) +		list->ftdi = 1;  	return list;  } @@ -850,10 +881,15 @@ altos_list_next(struct altos_list *list, struct altos_device *device)  		if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||  		    !get_number (object, CFSTR(kUSBProductID), &device->product))  			continue; -		if (device->vendor != 0xfffe) -			continue; -		if (device->product < 0x000a || 0x0013 < device->product) -			continue; +		if (list->ftdi) { +			if (device->vendor != 0x0403) +				continue; +		} else { +			if (device->vendor != 0xfffe) +				continue; +			if (device->product < 0x000a || 0x0013 < device->product) +				continue; +		}  		if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&  		    get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&  		    get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) { @@ -924,6 +960,7 @@ altos_bt_open(struct altos_bt_device *device)  struct altos_list {  	HDEVINFO	dev_info;  	int		index; +	int		ftdi;  };  #define USB_BUF_SIZE	64 @@ -974,6 +1011,26 @@ altos_list_start(void)  		return NULL;  	}  	list->index = 0; +	list->ftdi = 0; +	return list; +} + +PUBLIC struct altos_list * +altos_ftdi_list_start(void) +{ +	struct altos_list	*list = calloc(1, sizeof (struct altos_list)); + +	if (!list) +		return NULL; +	list->dev_info = SetupDiGetClassDevs(NULL, "FTDIBUS", NULL, +					     DIGCF_ALLCLASSES|DIGCF_PRESENT); +	if (list->dev_info == INVALID_HANDLE_VALUE) { +		altos_set_last_windows_error(); +		free(list); +		return NULL; +	} +	list->index = 0; +	list->ftdi = 1;  	return list;  } @@ -1008,27 +1065,29 @@ altos_list_next(struct altos_list *list, struct altos_device *device)  			continue;  		} -		/* Fetch symbolic name for this device and parse out -		 * the vid/pid/serial info */ -		symbolic_len = sizeof(symbolic); -		result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL, -					 symbolic, &symbolic_len); -		if (result != 0) { -			altos_set_last_windows_error(); -			printf("cannot find SymbolicName value\n"); -			RegCloseKey(dev_key); -			continue; -		} -		vid = pid = serial = 0; -		sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1, -		       "%04X", &vid); -		sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1, -		       "%04X", &pid); -		sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1, -		       "%d", &serial); -		if (!USB_IS_ALTUSMETRUM(vid, pid)) { -			RegCloseKey(dev_key); -			continue; +		if (list->ftdi) { +			vid = 0x0403; +			pid = 0x6015; +			serial = 0; +		} else { +			/* Fetch symbolic name for this device and parse out +			 * the vid/pid/serial info */ +			symbolic_len = sizeof(symbolic); +			result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL, +						 symbolic, &symbolic_len); +			if (result != 0) { +				altos_set_last_windows_error(); +				printf("cannot find SymbolicName value\n"); +				RegCloseKey(dev_key); +				continue; +			} +			vid = pid = serial = 0; +			sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1, +			       "%04X", &vid); +			sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1, +			       "%04X", &pid); +			sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1, +			       "%d", &serial);  		}  		/* Fetch the com port name */ @@ -1196,6 +1255,7 @@ altos_open(struct altos_device *device)  	struct altos_file	*file = calloc (1, sizeof (struct altos_file));  	char	full_name[64];  	COMMTIMEOUTS timeouts; +	DCB	     dcb;  	if (!file)  		return NULL; @@ -1221,6 +1281,11 @@ altos_open(struct altos_device *device)  	timeouts.WriteTotalTimeoutConstant = 0;  	SetCommTimeouts(file->handle, &timeouts); +	if (GetCommState(file->handle, &dcb)) { +		dcb.BaudRate = CBR_9600; +		(void) SetCommState(file->handle, &dcb); +	} +  	return file;  } diff --git a/libaltos/libaltos.dylib b/libaltos/libaltos.dylibBinary files differ new file mode 100755 index 00000000..cfbd3f54 --- /dev/null +++ b/libaltos/libaltos.dylib diff --git a/altosui/libaltos/libaltos.h b/libaltos/libaltos.h index f90fbb87..6d43159b 100644 --- a/altosui/libaltos/libaltos.h +++ b/libaltos/libaltos.h @@ -73,6 +73,9 @@ altos_get_last_error(struct altos_error *error);  PUBLIC struct altos_list *  altos_list_start(void); +PUBLIC struct altos_list * +altos_ftdi_list_start(void); +  /* Returns 1 for success, zero on end of list */  PUBLIC int  altos_list_next(struct altos_list *list, struct altos_device *device); diff --git a/altosui/libaltos/libaltos.i0 b/libaltos/libaltos.i0 index d06468f5..d06468f5 100644 --- a/altosui/libaltos/libaltos.i0 +++ b/libaltos/libaltos.i0 diff --git a/micropeak/.gitignore b/micropeak/.gitignore new file mode 100644 index 00000000..fc99b31c --- /dev/null +++ b/micropeak/.gitignore @@ -0,0 +1,6 @@ +*.jar +Manifest.txt +classes +*.stamp +micropeak +micropeak-test diff --git a/micropeak/FTDI.tar.gz b/micropeak/FTDI.tar.gzBinary files differ new file mode 100644 index 00000000..cd08ecf2 --- /dev/null +++ b/micropeak/FTDI.tar.gz diff --git a/micropeak/Info.plist.in b/micropeak/Info.plist.in new file mode 100644 index 00000000..40984c5a --- /dev/null +++ b/micropeak/Info.plist.in @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> +<plist version="0.9"> +<dict> +	<key>CFBundleName</key> +	<string>MicroPeak</string> +	<key>CFBundleVersion</key> +	<string>@VERSION@</string> +	<key>CFBundleAllowMixedLocalizations</key> +	<string>true</string> +	<key>CFBundleExecutable</key> +	<string>JavaApplicationStub</string> +	<key>CFBundleDevelopmentRegion</key> +	<string>English</string> +	<key>CFBundlePackageType</key> +	<string>APPL</string> +	<key>CFBundleIdentifier</key> +	<string>org.altusmetrum.micropeak</string> +	<key>CFBundleSignature</key> +	<string>Altu</string> +	<key>CFBundleGetInfoString</key> +	<string>MicroPeak UI version @VERSION@</string> +	<key>CFBundleInfoDictionaryVersion</key> +	<string>6.0</string> +	<key>CFBundleIconFile</key> +	<string>MicroPeak.icns</string> +	<key>Java</key> +	<dict> +		<key>MainClass</key> +		<string>org.altusmetrum.micropeak.MicroPeak</string> +		<key>JVMVersion</key> +		<string>1.5+</string> +		<key>ClassPath</key> +		<array> +			<string>$JAVAROOT/micropeak.jar</string> +		</array> +		<key>Properties</key> +		<dict> +		  <key>apple.laf.useScreenMenuBar</key> +		  <string>true</string> +		</dict> +		<key>VMOptions</key> +		<array> +		  <string>-Xms512M</string> +		  <string>-Xmx512M</string> +		  <string>-Dosgi.clean=true</string> +		</array> +	</dict> +</dict> +</plist> diff --git a/micropeak/Makefile.am b/micropeak/Makefile.am new file mode 100644 index 00000000..4a7aaaa1 --- /dev/null +++ b/micropeak/Makefile.am @@ -0,0 +1,243 @@ +JAVAROOT=classes +AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation + +altoslibdir=$(libdir)/altos + +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:../altosuilib/*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" + +bin_SCRIPTS=micropeak + +micropeakdir=$(datadir)/java + +micropeak_JAVA= \ +	MicroPeak.java \ +	MicroData.java \ +	MicroDataPoint.java \ +	MicroDownload.java \ +	MicroExport.java \ +	MicroFile.java \ +	MicroFrame.java \ +	MicroGraph.java \ +	MicroRaw.java \ +	MicroSave.java \ +	MicroSerial.java \ +	MicroStats.java \ +	MicroStatsTable.java \ +	MicroFileChooser.java \ +	MicroDeviceDialog.java \ +	MicroUSB.java + +JFREECHART_CLASS= \ +    jfreechart.jar + +JCOMMON_CLASS=\ +    jcommon.jar + +JAR=micropeak.jar + +FATJAR=micropeak-fat.jar + +LIBALTOS= \ +	libaltos.so \ +	libaltos.dylib \ +	altos64.dll \ +	altos.dll + +ALTOSLIB_CLASS=\ +	AltosLib.jar + +ALTOSUILIB_CLASS=\ +	altosuilib.jar + +# Icons +ICONDIR=$(top_srcdir)/icon + +JAVA_ICONS=\ +	$(ICONDIR)/micropeak-16.png \ +	$(ICONDIR)/micropeak-32.png \ +	$(ICONDIR)/micropeak-48.png \ +	$(ICONDIR)/micropeak-64.png \ +	$(ICONDIR)/micropeak-128.png \ +	$(ICONDIR)/micropeak-256.png + +# icon base names for jar +ICONJAR= -C $(ICONDIR) micropeak-16.png \ +	-C $(ICONDIR) micropeak-32.png \ +	-C $(ICONDIR) micropeak-48.png \ +	-C $(ICONDIR) micropeak-64.png \ +	-C $(ICONDIR) micropeak-128.png \ +	-C $(ICONDIR) micropeak-256.png + +WINDOWS_ICON=$(ICONDIR)/micro-peak.ico + +all-local: micropeak-test micropeak-jdb $(JAR) + +clean-local: +	-rm -rf classes $(JAR) $(FATJAR) \ +		$(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) \ +		$(ALTOSLIB_CLASS) \ +		$(ALTOSUILIB_CLASS) \ +		$(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt \ +		micropeak micropeak-test macosx linux windows + +LINUX_DIST=MicroPeak-Linux-$(VERSION).tar.bz2 +MACOSX_DIST=MicroPeak-Mac-$(VERSION).dmg +WINDOWS_DIST=MicroPeak-Windows-$(VERSION_DASH).exe + +FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) + +LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC) +LINUX_EXTRA=micropeak-fat + +MACOSX_INFO_PLIST=Info.plist +MACOSX_DRIVER=FTDI.tar.gz +MACOSX_README=ReadMe-Mac.rtf +MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(MACOSX_DRIVER) $(MACOSX_README) + +WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON) + +if FATINSTALL + +FATTARGET=$(FATDIR)/$(VERSION) + +LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST) +MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST) +WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST) + +fat: $(LINUX_DIST_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET) + +$(LINUX_DIST_TARGET): $(LINUX_DIST) +	mkdir -p $(FATTARGET) +	cp -p $< $@ + +$(MACOSX_DIST_TARGET): $(MACOSX_DIST) +	mkdir -p $(FATTARGET) +	cp -p $< $@ + +$(WINDOWS_DIST_TARGET): $(WINDOWS_DIST) +	mkdir -p $(FATTARGET) +	cp -p $< $@ + +else +fat: $(LINUX_DIST) $(MACOSX_DIST) $(WINDOWS_DIST) +endif + +micropeak: Makefile +	echo "#!/bin/sh" > $@ +	echo 'exec java  -Djava.library.path="$(altoslibdir)" -jar "$(micropeakdir)/micropeak.jar" "$$@"' >> $@ +	chmod +x $@ + +micropeak-jdb: Makefile +	echo "#!/bin/sh" > $@ +	echo 'exec jdb -classpath "classes:./*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="../libaltos/.libs" org.altusmetrum.micropeak.MicroPeak "$$@"' >> $@ +	chmod +x $@ + +micropeak-test: Makefile +	echo "#!/bin/sh" > $@ +	echo 'exec java -cp "./*:../libaltos/*:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="../libaltos/.libs" -jar micropeak.jar "$$@"' >> $@ +	chmod +x $@ + +install-micropeakJAVA: micropeak.jar +	@$(NORMAL_INSTALL) +	test -z "$(micropeakdir)" || $(MKDIR_P) "$(DESTDIR)$(micropeakdir)" +	echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(micropeakdir)/micropeak.jar'"; \ +	$(INSTALL_DATA) "$<" "$(DESTDIR)$(micropeakdir)" + +$(JAR): classmicropeak.stamp Manifest.txt $(JAVA_ICONS) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) +	jar cfm $@ Manifest.txt \ +		$(ICONJAR) \ +		-C classes org \ +		-C ../libaltos libaltosJNI + +$(FATJAR): classmicropeak.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(JAVA_ICONS) +	jar cfm $@ Manifest-fat.txt \ +		$(ICONJAR) \ +		-C classes org \ +		-C ../libaltos libaltosJNI + +classaltosui.stamp: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) + +libaltos.so: build-libaltos +	-rm -f "$@" +	$(LN_S) ../libaltos/.libs/"$@" . + +libaltos.dylib: +	-rm -f "$@" +	$(LN_S) ../libaltos/"$@" . + +altos.dll: ../libaltos/altos.dll +	-rm -f "$@" +	$(LN_S) ../libaltos/"$@" . + +altos64.dll: ../libaltos/altos64.dll +	-rm -f "$@" +	$(LN_S) ../libaltos/"$@" . + +../libaltos/.libs/libaltos.so: build-libaltos + +../libaltos/altos.dll: build-altos-dll + +../libaltos/altos64.dll: build-altos64-dll + +build-libaltos: +	+cd ../libaltos && make libaltos.la +build-altos-dll: +	+cd ../libaltos && make altos.dll + +build-altos64-dll: +	+cd ../libaltos && make altos64.dll + +$(ALTOSLIB_CLASS): +	-rm -f "$@" +	$(LN_S) ../altoslib/"$@" . + +$(ALTOSUILIB_CLASS): +	-rm -f "$@" +	$(LN_S) ../altosuilib/"$@" . + +$(JFREECHART_CLASS): +	-rm -f "$@" +	$(LN_S) "$(JFREECHART)"/"$@" . + +$(JCOMMON_CLASS): +	-rm -f "$@" +	$(LN_S) "$(JCOMMON)"/"$@" . + +$(LINUX_DIST): $(LINUX_FILES) $(LINUX_EXTRA) +	-rm -f $@ +	-rm -rf linux +	mkdir -p linux/MicroPeak +	cp -p $(LINUX_FILES) linux/MicroPeak +	cp -p micropeak-fat linux/MicroPeak/micropeak +	chmod +x linux/MicroPeak/micropeak +	tar cjf $@ -C linux MicroPeak + +$(MACOSX_DIST): $(MACOSX_FILES) +	-rm -f $@ +	-rm -rf macosx +	mkdir macosx +	cp -a MicroPeak.app macosx/ +	cp -a $(MACOSX_README) macosx/ReadMe.rtf +	cp -p Info.plist macosx/MicroPeak.app/Contents +	tar xzf $(MACOSX_DRIVER) -C macosx +	mkdir -p macosx/MicroPeak.app/Contents/Resources/Java +	cp -p $(FATJAR) macosx/MicroPeak.app/Contents/Resources/Java/micropeak.jar +	cp -p libaltos.dylib macosx/MicroPeak.app/Contents/Resources/Java +	cp -p $(ALTOSLIB_CLASS) macosx/MicroPeak.app/Contents/Resources/Java +	cp -p $(ALTOSUILIB_CLASS) macosx/MicroPeak.app/Contents/Resources/Java +	cp -p $(JFREECHART_CLASS) macosx/MicroPeak.app/Contents/Resources/Java +	cp -p $(JCOMMON_CLASS) macosx/MicroPeak.app/Contents/Resources/Java +	genisoimage -D -V MicroPeak-$(VERSION) -no-pad -r -apple -o $@ macosx + +$(WINDOWS_DIST): $(WINDOWS_FILES) micropeak-windows.nsi +	-rm -f $@ +	makensis -Omicropeak-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" micropeak-windows.nsi + +Manifest.txt: Makefile +	echo 'Main-Class: org.altusmetrum.micropeak.MicroPeak' > $@ +	echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(JCOMMON)/jcommon.jar $(JFREECHART)/jfreechart.jar" >> $@ + +Manifest-fat.txt: +	echo 'Main-Class: org.altusmetrum.micropeak.MicroPeak' > $@ +	echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) jcommon.jar jfreechart.jar" >> $@ + diff --git a/micropeak/MicroData.java b/micropeak/MicroData.java new file mode 100644 index 00000000..71919ddb --- /dev/null +++ b/micropeak/MicroData.java @@ -0,0 +1,356 @@ +/* + * 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.micropeak; + +import java.lang.*; +import java.io.*; +import java.util.*; +import org.altusmetrum.AltosLib.*; + +class MicroIterator implements Iterator<MicroDataPoint> { +	int		i; +	MicroData	data; + +	public boolean hasNext() { +		return i < data.pressures.length; +	} + +	public MicroDataPoint next() { +		return new MicroDataPoint(data, i++); +	} + +	public MicroIterator (MicroData data) { +		this.data = data; +		i = 0; +	} + +	public void remove() { +	} +} + +class MicroIterable implements Iterable<MicroDataPoint> { + +	MicroData	data; + +	public Iterator<MicroDataPoint> iterator() { +		return new MicroIterator(data); +	} + +	public MicroIterable(MicroData data) { +		this.data = data; +	} +} + +public class MicroData { +	public int		ground_pressure; +	public int		min_pressure; +	public int[]		pressures; +	private double		time_step; +	private double		ground_altitude; +	private ArrayList<Integer>	bytes; +	String			name; +	 + +	class FileEndedException extends Exception { +	} + +	class NonHexcharException extends Exception { +	} + +	class InvalidCrcException extends Exception { +	} + +	private int getc(InputStream f) throws IOException, FileEndedException { +		int	c = f.read(); + +		if (c == -1) +			throw new FileEndedException(); +		bytes.add(c); +		return c; +	} + +	private int get_nonwhite(InputStream f) throws IOException, FileEndedException { +		int	c; + +		for (;;) { +			c = getc(f); +			if (!Character.isWhitespace(c)) +				return c; +		} +	} + +	private int get_hexc(InputStream f) throws IOException, FileEndedException, NonHexcharException { +		int	c = get_nonwhite(f); + +		if ('0' <= c && c <= '9') +			return c - '0'; +		if ('a' <= c && c <= 'f') +			return c - 'a' + 10; +		if ('A' <= c && c <= 'F') +			return c - 'A' + 10; +		throw new NonHexcharException(); +	} + +	private static final int POLY = 0x8408; + +	private int log_crc(int crc, int b) { +		int	i; + +		for (i = 0; i < 8; i++) { +			if (((crc & 0x0001) ^ (b & 0x0001)) != 0) +				crc = (crc >> 1) ^ POLY; +			else +				crc = crc >> 1; +			b >>= 1; +		} +		return crc & 0xffff; +	} + +	int	file_crc; + +	private int get_hex(InputStream f) throws IOException, FileEndedException, NonHexcharException { +		int	a = get_hexc(f); +		int	b = get_hexc(f); + +		int h = (a << 4) + b; + +		file_crc = log_crc(file_crc, h); +		return h; +	} + +	private boolean find_header(InputStream f) throws IOException { +		try { +			for (;;) { +				if (get_nonwhite(f) == 'M' && get_nonwhite(f) == 'P') +					return true; +			} +		} catch (FileEndedException fe) { +			return false; +		} +	}  + +	private int get_32(InputStream f)  throws IOException, FileEndedException, NonHexcharException { +		int	v = 0; +		for (int i = 0; i < 4; i++) { +			v += get_hex(f) << (i * 8); +		} +		return v; +	} + +	private int get_16(InputStream f) throws IOException, FileEndedException, NonHexcharException { +		int	v = 0; +		for (int i = 0; i < 2; i++) { +			v += get_hex(f) << (i * 8); +		} +		return v; +	} + +	private int swap16(int i) { +		return ((i << 8) & 0xff00) | ((i >> 8) & 0xff); +	} + +	public boolean	crc_valid; + +	int mix_in (int high, int low) { +		return  high - (high & 0xffff) + low; +	} + +	boolean closer (int target, int a, int b) { +		return Math.abs (target - a) < Math.abs(target - b); +	} + +	public double altitude(int i) { +		return AltosConvert.pressure_to_altitude(pressures[i]); +	} + +	public Iterable<MicroDataPoint> points() { +		return new MicroIterable(this); +	} + +	int fact(int n) { +		if (n == 0) +			return 1; +		return n * fact(n-1); +	} + +	int choose(int n, int k) { +		return fact(n) / (fact(k) * fact(n-k)); +	} + + +	public double avg_altitude(int center, int dist) { +		int	start = center - dist; +		int	stop = center + dist; + +		if (start < 0) +			start = 0; +		if (stop >= pressures.length) +			stop = pressures.length - 1; + +		double	sum = 0; +		double	div = 0; + +		int	n = dist * 2; + +		for (int i = start; i <= stop; i++) { +			int	k = i - (center - dist); +			int	c = choose (n, k); + +			sum += c * pressures[i]; +			div += c; +		} + +		double pres = sum / div; + +		double alt = AltosConvert.pressure_to_altitude(pres); +		return alt; +	} + +	public double pressure(int i) { +		return pressures[i]; +	} + +	public double height(int i) { +		return altitude(i) - ground_altitude; +	} + +	public double apogee_pressure() { +		return min_pressure; +	} + +	public double apogee_altitude() { +		return AltosConvert.pressure_to_altitude(apogee_pressure()); +	} + +	public double apogee_height() { +		return apogee_altitude() - ground_altitude; +	} + +	static final int speed_avg = 3; +	static final int accel_avg = 5; + +	private double avg_speed(int center, int dist) { +		if (center == 0) +			return 0; + +		double ai = avg_altitude(center, dist); +		double aj = avg_altitude(center - 1, dist); +		double s = (ai - aj) / time_step; + +		return s; +	} + +	public double speed(int i) { +		return avg_speed(i, speed_avg); +	} + +	public double acceleration(int i) { +		if (i == 0) +			return 0; +		return (avg_speed(i, accel_avg) - avg_speed(i-1, accel_avg)) / time_step; +	} + +	public double time(int i) { +		return i * time_step; +	} + +	public void save (OutputStream f) throws IOException { +		for (int c : bytes) +			f.write(c); +		f.write('\n'); +	} + +	public void export (Writer f) throws IOException { +		PrintWriter	pw = new PrintWriter(f); +		pw.printf("  Time, Press(Pa), Height(m), Height(f), Speed(m/s), Speed(mph), Speed(mach), Accel(m/s²), Accel(ft/s²),  Accel(g)\n"); +		for (MicroDataPoint point : points()) { +			pw.printf("%6.3f,%10.0f,%10.1f,%10.1f,%11.2f,%11.2f,%12.4f,%12.2f,%13.2f,%10.4f\n", +				  point.time, +				  point.pressure, +				  point.height, +				  AltosConvert.meters_to_feet(point.height), +				  point.speed, +				  AltosConvert.meters_to_mph(point.speed), +				  AltosConvert.meters_to_mach(point.speed), +				  point.accel, +				  AltosConvert.meters_to_feet(point.accel), +				  AltosConvert.meters_to_g(point.accel)); +		} +	} + +	public void set_name(String name) { +		this.name = name; +	} + +	public MicroData (InputStream f, String name) throws IOException, InterruptedException { +		this.name = name; +		bytes = new ArrayList<Integer>(); +		if (!find_header(f)) +			throw new IOException("No MicroPeak data header found"); +		try { +			file_crc = 0xffff; +			ground_pressure = get_32(f); +			min_pressure = get_32(f); +			int nsamples = get_16(f); +			pressures = new int[nsamples + 1]; + +			ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure); +			int cur = ground_pressure; +			pressures[0] = cur; +			for (int i = 0; i < nsamples; i++) { +				int	k = get_16(f); +				int	same = mix_in(cur, k); +				int	up = mix_in(cur + 0x10000, k); +				int	down = mix_in(cur - 0x10000, k); + +				if (closer (cur, same, up)) { +					if (closer (cur, same, down)) +						cur = same; +					else +						cur = down; +				} else { +					if (closer (cur, up, down)) +						cur = up; +					else +						cur = down; +				} +				 +				pressures[i+1] = cur; +			} + +			int current_crc = swap16(~file_crc & 0xffff); +			int crc = get_16(f); + +			crc_valid = crc == current_crc; + +			time_step = 0.192; +		} catch (FileEndedException fe) { +			throw new IOException("File Ended Unexpectedly"); +		} catch (NonHexcharException ne) { +			throw new IOException("Non hexadecimal character found"); +		} +	} + +	public MicroData() { +		ground_pressure = 101000; +		min_pressure = 101000; +		pressures = new int[1]; +		pressures[0] = 101000; +	} +	 +} diff --git a/micropeak/MicroDataPoint.java b/micropeak/MicroDataPoint.java new file mode 100644 index 00000000..c58708e6 --- /dev/null +++ b/micropeak/MicroDataPoint.java @@ -0,0 +1,42 @@ +/* + * 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.micropeak; + +public class MicroDataPoint { +	public double	time; +	public double	pressure; +	public double	height; +	public double	speed; +	public double	accel; + +	public MicroDataPoint (double pressure, double height, double speed, double accel, double time) { +		this.pressure = pressure; +		this.height = height; +		this.speed = speed; +		this.accel = accel; +		this.time = time; +	} + +	public MicroDataPoint(MicroData data, int i) { +		this(data.pressure(i), +		     data.height(i), +		     data.speed(i), +		     data.acceleration(i), +		     data.time(i)); +	} +}
\ No newline at end of file diff --git a/micropeak/MicroDeviceDialog.java b/micropeak/MicroDeviceDialog.java new file mode 100644 index 00000000..23195dac --- /dev/null +++ b/micropeak/MicroDeviceDialog.java @@ -0,0 +1,59 @@ +/* + * 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.micropeak; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import org.altusmetrum.altosuilib.*; + +public class MicroDeviceDialog extends AltosDeviceDialog { + +	public AltosDevice[] devices() { +		java.util.List<MicroUSB>	list = MicroUSB.list(); + +		if (list == null) { +			JOptionPane.showMessageDialog(frame, +						      "libaltos failed to load", +						      "Helper Library Failed", +						      JOptionPane.ERROR_MESSAGE); +			return new AltosDevice[0]; +		} + +		int		num_devices = list.size(); +		AltosDevice[]	devices = new AltosDevice[num_devices]; + +		for (int i = 0; i < num_devices; i++) +			devices[i] = list.get(i); +		return devices; +	} + +	public MicroDeviceDialog (Frame in_frame, Component location) { +		super(in_frame, location, 0); +	} + +	public static AltosDevice show (Component frameComp) { +		Frame			frame = JOptionPane.getFrameForComponent(frameComp); +		MicroDeviceDialog	dialog; + +		dialog = new MicroDeviceDialog (frame, frameComp); +		dialog.setVisible(true); +		return dialog.getValue(); +	} +} diff --git a/micropeak/MicroDownload.java b/micropeak/MicroDownload.java new file mode 100644 index 00000000..28a7550d --- /dev/null +++ b/micropeak/MicroDownload.java @@ -0,0 +1,144 @@ +/* + * 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.micropeak; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroDownload extends AltosUIDialog implements Runnable, ActionListener { +	MicroPeak	owner; +	Container	pane; +	AltosDevice	device; +	JButton		cancel; +	MicroData	data; +	MicroSerial	serial; + +	private void done_internal() { +		setVisible(false); +		if (data != null) { +			if (data.crc_valid) { +				owner = owner.SetData(data); +				MicroSave save = new MicroSave(owner, data); +				if (save.runDialog()) +					owner.SetName(data.name); +			} else { +				JOptionPane.showMessageDialog(owner, +							      "Flight data corrupted", +							      "Download Failed", +							      JOptionPane.ERROR_MESSAGE); +			} +		} +		dispose(); +	} + +	public void done() { +		Runnable r = new Runnable() { +				public void run() { +					try { +						done_internal(); +					} catch (Exception ex) { +					} +				} +			}; +		SwingUtilities.invokeLater(r); +	} + +	public void run() { +		try { +			data = new MicroData(serial, device.toShortString()); +			serial.close(); +		} catch (FileNotFoundException fe) { +		} catch (IOException ioe) { +		} catch (InterruptedException ie) { +		} +		done(); +	} + +	Thread	serial_thread; + +	public void start() { +		try { +			serial = new MicroSerial(device); +		} catch (FileNotFoundException fe) { +			return; +		} +		serial_thread = new Thread(this); +		serial_thread.start(); +	} + +	public void actionPerformed(ActionEvent ae) { +		if (serial_thread != null) { +			serial.close(); +			serial_thread.interrupt(); +		} +	} + +	public MicroDownload(MicroPeak owner, AltosDevice device) { +		super (owner, "Download MicroPeak Data", false); + +		GridBagConstraints c; +		Insets il = new Insets(4,4,4,4); +		Insets ir = new Insets(4,4,4,4); + +		this.owner = owner; +		this.device = device; + +		pane = getContentPane(); +		pane.setLayout(new GridBagLayout()); + +		c = new GridBagConstraints(); +		c.gridx = 0; c.gridy = 0; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		JLabel device_label = new JLabel("Device:"); +		pane.add(device_label, c); + +		c = new GridBagConstraints(); +		c.gridx = 1; c.gridy = 0; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = ir; +		JLabel device_value = new JLabel(device.toString()); +		pane.add(device_value, c); + +		cancel = new JButton("Cancel"); +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.CENTER; +		c.gridx = 0; c.gridy = 1; +		c.gridwidth = GridBagConstraints.REMAINDER; +		Insets ic = new Insets(4,4,4,4); +		c.insets = ic; +		pane.add(cancel, c); + +		cancel.addActionListener(this); + +		pack(); +		setLocationRelativeTo(owner); +		setVisible(true); +		this.start(); +	} +} diff --git a/micropeak/MicroExport.java b/micropeak/MicroExport.java new file mode 100644 index 00000000..4b83bb4d --- /dev/null +++ b/micropeak/MicroExport.java @@ -0,0 +1,105 @@ +/* + * 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.micropeak; + +import java.io.*; +import java.util.ArrayList; + +import java.awt.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroExport extends JFileChooser { + +	JFrame		frame; +	MicroData	data; + +	public static void export(File file, MicroData data) throws FileNotFoundException, IOException { +		FileWriter fw = new FileWriter(file); +		data.export(fw); +		fw.close(); +	} + +	public boolean runDialog() { +		int	ret; + +		setSelectedFile(new File(AltosLib.replace_extension(data.name, ".csv"))); +		for (;;) { +			ret = showSaveDialog(frame); +			if (ret != APPROVE_OPTION) +				return false; +			File	file; +			String	filename; +			file = getSelectedFile(); +			if (file == null) +				continue; +			if (!file.getName().contains(".")) { +				String fullname = file.getPath(); +				file = new File(fullname.concat(".csv")); +			} +			filename = file.getName(); +			if (file.exists()) { +				if (file.isDirectory()) { +					JOptionPane.showMessageDialog(frame, +								      String.format("\"%s\" is a directory", +										    filename), +								      "Directory", +								      JOptionPane.ERROR_MESSAGE); +					continue; +				} +				int r = JOptionPane.showConfirmDialog(frame, +								      String.format("\"%s\" already exists. Overwrite?", +										    filename), +								      "Overwrite file?", +								      JOptionPane.YES_NO_OPTION); +				if (r != JOptionPane.YES_OPTION) +					continue; +							       +				if (!file.canWrite()) { +					JOptionPane.showMessageDialog(frame, +								      String.format("\"%s\" is not writable", +										    filename), +								      "File not writable", +								      JOptionPane.ERROR_MESSAGE); +					continue; +				} +			} +			try { +				export(file, data); +				return true; +			} catch (FileNotFoundException fe) { +				JOptionPane.showMessageDialog(frame, +							      fe.getMessage(), +							      "Cannot create file", +							      JOptionPane.ERROR_MESSAGE); +			} catch (IOException ioe) { +			} +		} +	} + +	public MicroExport(JFrame frame, MicroData data) { +		this.frame = frame; +		this.data = data; +		setDialogTitle("Export MicroPeak Data File"); +		setFileFilter(new FileNameExtensionFilter("MicroPeak CSV file", +							  "csv")); +		setCurrentDirectory(AltosUIPreferences.logdir()); +	} +} diff --git a/micropeak/MicroFile.java b/micropeak/MicroFile.java new file mode 100644 index 00000000..13d48380 --- /dev/null +++ b/micropeak/MicroFile.java @@ -0,0 +1,45 @@ +/* + * Copyright © 2013 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.micropeak; + +import java.io.*; +import java.util.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroFile { + +	public static File make(File directory, int year, int month, int day) { +		for (int sequence = 1;; sequence++) { +			String s = String.format("%04d-%02d-%02d-flight-%03d.mpd", +						 year, month, day, sequence); +			File file = new File(directory, s); +			if (!file.exists()) +				return file; +		} +	} + +	public static File make(File directory) { +		Calendar	cal = Calendar.getInstance(); +		return make(directory, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH)); +	} + +	public static File make() { +		return make(AltosUIPreferences.logdir()); +	} +}
\ No newline at end of file diff --git a/micropeak/MicroFileChooser.java b/micropeak/MicroFileChooser.java new file mode 100644 index 00000000..21ddb0f8 --- /dev/null +++ b/micropeak/MicroFileChooser.java @@ -0,0 +1,55 @@ +/* + * 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.micropeak; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.io.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroFileChooser extends JFileChooser { +	JFrame	frame; +	String	filename; +	File	file; + +	public String filename() { +		return filename; +	} + +	public File file() { +		return file; +	} + +	public File runDialog() { +		int	ret; + +		ret = showOpenDialog(frame); +		if (ret == APPROVE_OPTION) +			return getSelectedFile(); +		return null; +	} + +	public MicroFileChooser(JFrame in_frame) { +		frame = in_frame; +		setDialogTitle("Select MicroPeak Data File"); +		setFileFilter(new FileNameExtensionFilter("MicroPeak data file", +							  "mpd")); +		setCurrentDirectory(AltosUIPreferences.logdir()); +	} +} diff --git a/micropeak/MicroFrame.java b/micropeak/MicroFrame.java new file mode 100644 index 00000000..03e3af0c --- /dev/null +++ b/micropeak/MicroFrame.java @@ -0,0 +1,37 @@ +/* + * 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.micropeak; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.util.*; +import org.altusmetrum.altosuilib.*; + +public class MicroFrame extends AltosUIFrame { +	static String[] micro_icon_names = { +		"/micropeak-16.png", +		"/micropeak-32.png", +		"/micropeak-48.png", +		"/micropeak-64.png", +		"/micropeak-128.png", +		"/micropeak-256.png" +	}; + +	static { set_icon_names(micro_icon_names); } +} diff --git a/micropeak/MicroGraph.java b/micropeak/MicroGraph.java new file mode 100644 index 00000000..5aa127bb --- /dev/null +++ b/micropeak/MicroGraph.java @@ -0,0 +1,179 @@ +/* + * 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.micropeak; + +import java.io.*; +import java.util.ArrayList; + +import java.awt.*; +import javax.swing.*; +import org.altusmetrum.AltosLib.*; + +import org.jfree.ui.*; +import org.jfree.chart.*; +import org.jfree.chart.plot.*; +import org.jfree.chart.axis.*; +import org.jfree.chart.renderer.*; +import org.jfree.chart.renderer.xy.*; +import org.jfree.chart.labels.*; +import org.jfree.data.xy.*; +import org.jfree.data.*; + +class MicroSeries extends XYSeries { +	NumberAxis	axis; +	String		label; +	String		units; +	Color		color; +	XYItemRenderer	renderer; +	 +	void set_units(String units) { +		this.units = units; + +		axis.setLabel(String.format("%s (%s)", label, units)); + +		StandardXYToolTipGenerator	ttg; + +		ttg = new StandardXYToolTipGenerator(String.format("{1}s: {2}%s ({0})", units), +						     new java.text.DecimalFormat("0.00"), +						     new java.text.DecimalFormat("0.00")); +		renderer.setBaseToolTipGenerator(ttg); +	} + +	void set_enable(boolean enable) { +		renderer.setSeriesVisible(0, enable); +		axis.setVisible(enable); +	} + +	public MicroSeries (String label, String units, Color color) { +		super(label); +		this.label = label; +		this.units = units; +		this.color = color; + +		axis = new NumberAxis(); +		axis.setLabelPaint(color); +		axis.setTickLabelPaint(color); + +		renderer = new XYLineAndShapeRenderer(true, false); +		renderer.setSeriesPaint(0, color); +		set_units(units); +	} +} + +public class MicroGraph implements AltosUnitsListener { + +	XYPlot		plot; +	JFreeChart	chart; +	ChartPanel	panel; +	NumberAxis	xAxis; +	MicroSeries	heightSeries; +        MicroSeries	speedSeries; +	MicroSeries	accelSeries; + +	static final private Color height_color = new Color(194,31,31); +	static final private Color speed_color = new Color(31,194,31); +	static final private Color accel_color = new Color(31,31,194); +	static final private Color gridline_color = new Color(0, 0, 0); +	static final private Color border_color = new Color(255, 255, 255); +	static final private Color background_color = new Color(255, 255, 255); + +	MicroData	data; + +	public JPanel panel() { +		return panel; +	} + +	private MicroSeries addSeries(int index, String label, String units, Color color) { +		MicroSeries		series = new MicroSeries(label, units, color); +		XYSeriesCollection	dataset = new XYSeriesCollection(series); + +		series.renderer.setPlot(plot); +		plot.setRangeAxis(index, series.axis); +		plot.setDataset(index, dataset); +		plot.setRenderer(index, series.renderer); +		plot.mapDatasetToRangeAxis(index, index); +		return series; +	} +	 +	public void resetData() { +		heightSeries.clear(); +		speedSeries.clear(); +		accelSeries.clear(); +		if (data != null) { +			for (MicroDataPoint point : data.points()) { +				heightSeries.add(point.time, AltosConvert.height.value(point.height)); +				speedSeries.add(point.time, AltosConvert.speed.value(point.speed)); +				accelSeries.add(point.time, AltosConvert.accel.value(point.accel)); +			} +		} +//		accelSeries.set_enable(false); +	} + +	public void setName (String name) { +		chart.setTitle(name); +	} + +	public void setData (MicroData data) { +		this.data = data; +		if (data != null) +			setName(data.name); +		resetData(); +	} + +	public void units_changed(boolean imperial_units) { +		heightSeries.set_units(AltosConvert.height.show_units()); +		speedSeries.set_units(AltosConvert.speed.show_units()); +		accelSeries.set_units(AltosConvert.accel.show_units()); +		resetData(); +	} + +	public MicroGraph() { + +		xAxis = new NumberAxis("Time (s)"); +		 +		xAxis.setAutoRangeIncludesZero(true); + +		plot = new XYPlot(); +		plot.setDomainAxis(xAxis); +		plot.setOrientation(PlotOrientation.VERTICAL); +		plot.setDomainPannable(true); +		plot.setRangePannable(true); + +		chart = new JFreeChart("Flight", JFreeChart.DEFAULT_TITLE_FONT, +				       plot, true); + +		ChartUtilities.applyCurrentTheme(chart); + +		heightSeries = addSeries(0, "Height", AltosConvert.height.show_units(), height_color); +		speedSeries = addSeries(1, "Speed", AltosConvert.speed.show_units(), speed_color); +		accelSeries = addSeries(2, "Acceleration", AltosConvert.accel.show_units(), accel_color); + +		plot.setDomainGridlinePaint(gridline_color); +		plot.setRangeGridlinePaint(gridline_color); +		plot.setBackgroundPaint(background_color); +		plot.setBackgroundAlpha((float) 1); + +		chart.setBackgroundPaint(background_color); +		chart.setBorderPaint(border_color); +		panel = new ChartPanel(chart); +		panel.setMouseWheelEnabled(true); +		panel.setPreferredSize(new java.awt.Dimension(800, 500)); + +		AltosPreferences.register_units_listener(this); +	} +}
\ No newline at end of file diff --git a/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub b/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStubBinary files differ new file mode 100755 index 00000000..c661d3e1 --- /dev/null +++ b/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub diff --git a/micropeak/MicroPeak.app/Contents/PkgInfo b/micropeak/MicroPeak.app/Contents/PkgInfo new file mode 100644 index 00000000..8a43480f --- /dev/null +++ b/micropeak/MicroPeak.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPLAM.O diff --git a/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns b/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icnsBinary files differ new file mode 100644 index 00000000..9ba83bf5 --- /dev/null +++ b/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns diff --git a/micropeak/MicroPeak.java b/micropeak/MicroPeak.java new file mode 100644 index 00000000..5d128dfd --- /dev/null +++ b/micropeak/MicroPeak.java @@ -0,0 +1,305 @@ +/* + * 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.micropeak; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroPeak extends MicroFrame implements ActionListener, ItemListener { + +	File		filename; +	MicroGraph	graph; +	MicroStatsTable	stats; +	MicroRaw	raw; +	MicroData	data; +	Container	container; +	JTabbedPane	pane; +	static int	number_of_windows; + +	MicroPeak SetData(MicroData data) { +		MicroPeak	mp = this; +		if (this.data != null) { +			mp = new MicroPeak(); +			return mp.SetData(data); +		} +		this.data = data; +		graph.setData(data); +		stats.setData(data); +		raw.setData(data); +		setTitle(data.name); +		return this; +	} + +	void SetName(String name) { +		graph.setName(name); +		setTitle(name); +	} + +	private static MicroData ReadFile(File filename) throws IOException, FileNotFoundException { +		MicroData	data = null; +		FileInputStream	fis = new FileInputStream(filename); +		try { +			data = new MicroData((InputStream) fis, filename.getName()); +		} catch (InterruptedException ie) { +			data = null; +		} finally { +			fis.close(); +		} +		return data; +	} + +	private void OpenFile(File filename) { +		try { +			SetData(ReadFile(filename)); +		} catch (FileNotFoundException fne) { +			JOptionPane.showMessageDialog(this, +						      fne.getMessage(), +						      "Cannot open file", +						      JOptionPane.ERROR_MESSAGE); +		} catch (IOException ioe) { +			JOptionPane.showMessageDialog(this, +						      ioe.getMessage(), +						      "File Read Error", +						      JOptionPane.ERROR_MESSAGE); +		} +	} + +	private void SelectFile() { +		MicroFileChooser	chooser = new MicroFileChooser(this); +		File			file = chooser.runDialog(); + +		if (file != null) +			OpenFile(file); +	} + +	private void Preferences() { +		new AltosUIConfigure(this); +	} + +	private void DownloadData() { +		AltosDevice	device = MicroDeviceDialog.show(this); +		 +		if (device != null) +			new MicroDownload(this, device); +	} + +	private void no_data() { +			JOptionPane.showMessageDialog(this, +						      "No data available", +						      "No data", +						      JOptionPane.INFORMATION_MESSAGE); +	} + +	private void Save() { +		if (data == null) { +			no_data(); +			return; +		} +		MicroSave	save = new MicroSave (this, data); +		if (save.runDialog()) +			SetName(data.name); +	} +	 +	private void Export() { +		if (data == null) { +			no_data(); +			return; +		} +		MicroExport	export = new MicroExport (this, data); +		export.runDialog(); +	} + +	private static void CommandGraph(File file) { +		MicroPeak m = new MicroPeak(); +		m.OpenFile(file); +	} + +	private static void CommandExport(File file) { +		try { +			MicroData d = ReadFile(file); +			if (d != null) { +				File	csv = new File(AltosLib.replace_extension(file.getPath(), ".csv")); +				try { +					System.out.printf ("Export \"%s\" to \"%s\"\n", file.getPath(), csv.getPath()); +					MicroExport.export(csv, d); +				} catch (FileNotFoundException fe) { +					System.err.printf("Cannot create file \"%s\" (%s)\n", csv.getName(), fe.getMessage()); +				} catch (IOException ie) { +					System.err.printf("Cannot write file \"%s\" (%s)\n", csv.getName(), ie.getMessage()); +				} +			} +		} catch (IOException ie) { +			System.err.printf("Cannot read file \"%s\" (%s)\n", file.getName(), ie.getMessage()); +		} +	} + +	private void Close() { +		setVisible(false); +		dispose(); +		--number_of_windows; +		if (number_of_windows == 0) +			System.exit(0); +	} + +	public void actionPerformed(ActionEvent ev) { +		if ("Exit".equals(ev.getActionCommand())) +			System.exit(0); +		else if ("Close".equals(ev.getActionCommand())) +			Close(); +		else if ("Open".equals(ev.getActionCommand())) +			SelectFile(); +		else if ("Download".equals(ev.getActionCommand())) +			DownloadData(); +		else if ("Export".equals(ev.getActionCommand())) +			Export(); +		else if ("Preferences".equals(ev.getActionCommand())) +			Preferences(); +		else if ("Save a Copy".equals(ev.getActionCommand())) +			Save(); +	} + +	public void itemStateChanged(ItemEvent e) { +	} + +	public MicroPeak() { + +		++number_of_windows; + +		AltosUIPreferences.set_component(this); + +		container = getContentPane(); +		pane = new JTabbedPane(); + +		setTitle("MicroPeak"); + +		JMenuBar menuBar = new JMenuBar(); +		setJMenuBar(menuBar); + +		JMenu fileMenu = new JMenu("File"); +		menuBar.add(fileMenu); + +		JMenuItem openAction = new JMenuItem("Open"); +		fileMenu.add(openAction); +		openAction.addActionListener(this); + +		JMenuItem downloadAction = new JMenuItem("Download"); +		fileMenu.add(downloadAction); +		downloadAction.addActionListener(this); + +		JMenuItem saveAction = new JMenuItem("Save a Copy"); +		fileMenu.add(saveAction); +		saveAction.addActionListener(this); + +		JMenuItem exportAction = new JMenuItem("Export"); +		fileMenu.add(exportAction); +		exportAction.addActionListener(this); + +		JMenuItem preferencesAction = new JMenuItem("Preferences"); +		fileMenu.add(preferencesAction); +		preferencesAction.addActionListener(this); + +		JMenuItem closeAction = new JMenuItem("Close"); +		fileMenu.add(closeAction); +		closeAction.addActionListener(this); + +		JMenuItem exitAction = new JMenuItem("Exit"); +		fileMenu.add(exitAction); +		exitAction.addActionListener(this); + +		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); +		addWindowListener(new WindowAdapter() { +			@Override +			public void windowClosing(WindowEvent e) { +				Close(); +			} +		}); + +		graph = new MicroGraph(); +		stats = new MicroStatsTable(); +		raw = new MicroRaw(); +		pane.add(graph.panel, "Graph"); +		pane.add(stats, "Statistics"); +		JScrollPane scroll = new JScrollPane(raw); +		pane.add(scroll, "Raw Data"); +		pane.doLayout(); +		pane.validate(); +		container.add(pane); +		container.doLayout(); +		container.validate(); +		doLayout(); +		validate(); +		Insets i = getInsets(); +		Dimension ps = pane.getPreferredSize(); +		ps.width += i.left + i.right; +		ps.height += i.top + i.bottom; +//		setPreferredSize(ps); +		setSize(ps); +		setLocationByPlatform(true); +		setVisible(true); +	} + +	public static void help(int code) { +		System.out.printf("Usage: micropeak [OPTION] ... [FILE]...\n"); +		System.out.printf("  Options:\n"); +		System.out.printf("    --csv\tgenerate comma separated output for spreadsheets, etc\n"); +		System.out.printf("    --graph\tgraph a flight\n"); +		System.exit(code); +	} + +	public static void main(final String[] args) { +		boolean	opened = false; +		boolean graphing = true; + +		try { +			UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel()); +		} catch (Exception e) { +		} + +		for (int i = 0; i < args.length; i++) { +			if (args[i].equals("--help")) +				help(0); +			else if (args[i].equals("--export")) +				graphing = false; +			else if (args[i].equals("--graph")) +				graphing = true; +			else if (args[i].startsWith("--")) +				help(1); +			else { +				File	file = new File(args[i]); +				try { +					if (graphing) +						CommandGraph(file); +					else +						CommandExport(file); +					opened = true; +				} catch (Exception e) { +					System.err.printf("Error processing \"%s\": %s\n", +							  file.getName(), e.getMessage()); +				} +			} +		} +		if (!opened) +			new MicroPeak(); +	} +} diff --git a/micropeak/MicroRaw.java b/micropeak/MicroRaw.java new file mode 100644 index 00000000..8546cffb --- /dev/null +++ b/micropeak/MicroRaw.java @@ -0,0 +1,45 @@ +/* + * Copyright © 2013 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.micropeak; + +import java.awt.*; +import java.io.*; +import javax.swing.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroRaw extends JTextArea { + +	public void setData(MicroData data) { +		StringWriter	sw = new StringWriter(); +		try { +			data.export(sw); +			setRows(data.pressures.length + 1); +			setText(sw.toString()); +		} catch (IOException ie) { +			setText(String.format("Error writing data: %s", ie.getMessage())); +		} +		setCaretPosition(0); +	} + +	public MicroRaw() { +		super(1, 30); +		setFont(AltosUILib.table_value_font); +		setEditable(false); +	} +} diff --git a/micropeak/MicroSave.java b/micropeak/MicroSave.java new file mode 100644 index 00000000..7879ff90 --- /dev/null +++ b/micropeak/MicroSave.java @@ -0,0 +1,107 @@ +/* + * 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.micropeak; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroSave extends JFileChooser { + +	JFrame		frame; +	MicroData	data; + +	public static void save(File file, MicroData data) throws FileNotFoundException, IOException { +		FileOutputStream fos = new FileOutputStream(file); +		data.save(fos); +		fos.close(); +	} + +	public boolean runDialog() { +		int	ret; + +		for (;;) { +			ret = showSaveDialog(frame); +			if (ret != APPROVE_OPTION) +				return false; +			File	file; +			String	filename; +			file = getSelectedFile(); +			if (file == null) +				continue; +			if (!file.getName().contains(".")) { +				String fullname = file.getPath(); +				file = new File(fullname.concat(".mpd")); +			} +			filename = file.getName(); +			if (file.exists()) { +				if (file.isDirectory()) { +					JOptionPane.showMessageDialog(frame, +								      String.format("\"%s\" is a directory", +										    filename), +								      "Directory", +								      JOptionPane.ERROR_MESSAGE); +					continue; +				} +				int r = JOptionPane.showConfirmDialog(frame, +								      String.format("\"%s\" already exists. Overwrite?", +										    filename), +								      "Overwrite file?", +								      JOptionPane.YES_NO_OPTION); +				if (r != JOptionPane.YES_OPTION) +					continue; +							       +				if (!file.canWrite()) { +					JOptionPane.showMessageDialog(frame, +								      String.format("\"%s\" is not writable", +										    filename), +								      "File not writable", +								      JOptionPane.ERROR_MESSAGE); +					continue; +				} +			} +			try { +				save(file, data); +				data.set_name(filename); +				return true; +			} catch (FileNotFoundException fe) { +				JOptionPane.showMessageDialog(frame, +							      fe.getMessage(), +							      "Cannot create file", +							      JOptionPane.ERROR_MESSAGE); +			} catch (IOException ioe) { +			} +		} +	} + +	public MicroSave(JFrame frame, MicroData data) { +		this.frame = frame; +		this.data = data; +		setDialogTitle("Save MicroPeak Data File"); +		setFileFilter(new FileNameExtensionFilter("MicroPeak data file", +							  "mpd")); +		setCurrentDirectory(AltosUIPreferences.logdir()); +		setSelectedFile(MicroFile.make()); +	} +} diff --git a/micropeak/MicroSerial.java b/micropeak/MicroSerial.java new file mode 100644 index 00000000..15ef8582 --- /dev/null +++ b/micropeak/MicroSerial.java @@ -0,0 +1,55 @@ +/* + * 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.micropeak; + +import java.util.*; +import java.io.*; +import libaltosJNI.*; +import org.altusmetrum.altosuilib.*; + +public class MicroSerial extends InputStream { +	SWIGTYPE_p_altos_file	file; + +	public int read() { +		int	c = libaltos.altos_getchar(file, 0); +		if (Thread.interrupted()) +			return -1; +		if (c == -1) +			return -1; +		if (AltosUIPreferences.serial_debug) +			System.out.printf("%c", c); +		return c; +	} + +	public void close() { +		if (file != null) { +			libaltos.altos_close(file); +			file = null; +		} +	} + +	public MicroSerial(AltosDevice device) throws FileNotFoundException { +		file = device.open(); +		if (file == null) { +			final String message = device.getErrorString(); +			throw new FileNotFoundException(String.format("%s (%s)", +								      device.toShortString(), +								      message)); +		} +	} +} diff --git a/micropeak/MicroStats.java b/micropeak/MicroStats.java new file mode 100644 index 00000000..90e9dd1f --- /dev/null +++ b/micropeak/MicroStats.java @@ -0,0 +1,167 @@ +/* + * 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.micropeak; + +import java.io.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroStats { +	double		coast_height; +	double		coast_time; + +	double		apogee_height; +	double		apogee_time; + +	double		landed_height; +	double		landed_time; + +	double		max_speed; +	double		max_accel; + +	MicroData	data; + +	void find_landing() { +		landed_height = 0; + +		for (MicroDataPoint point : data.points()) { +			landed_height = point.height; +			landed_time = point.time; +		} + +		boolean above = false; +		for (MicroDataPoint point : data.points()) { +			if (point.height > landed_height + 10) { +				above = true; +			} else { +				if (above && point.height < landed_height + 2) { +					above = false; +					landed_time = point.time; +				} +			} +		} +	} + +	void find_apogee() { +		apogee_height = data.apogee_height(); +		double searched_apogee = 0; +		apogee_time = 0; +		 +		/* This just finds the apogee time -- we've recorded the +		 * peak altitude separately in eeprom, and that could +		 * have occurred after the eeprom was full. +		 */ +		for (MicroDataPoint point : data.points()) { +			if (point.height > searched_apogee) { +				searched_apogee = point.height; +				apogee_time = point.time; +			} +		} +	} + +	void find_coast() { +		coast_height = 0; +		coast_time = 0; + +		for (MicroDataPoint point : data.points()) { +			if (point.accel < -9.8) +				break; +			coast_time = point.time; +			coast_height = point.height; +		} +	} + +	void find_max_speed() { +		max_speed = 0; +		for (MicroDataPoint point : data.points()) { +			if (point.time > apogee_time) +				break; +			if (point.speed > max_speed) +				max_speed = point.speed; +		} +	} + +	void find_max_accel() { +		max_accel = 0; +		for (MicroDataPoint point : data.points()) { +			if (point.time > apogee_time) +				break; +			if (point.accel > max_accel) +				max_accel = point.accel; +		} +	} + +	double boost_duration() { +		return coast_time; +	} + +	double boost_height() { +		return coast_height; +	} + +	double	boost_speed() { +		return coast_height / coast_time; +	} + +	double boost_accel() { +		return boost_speed() / boost_duration(); +	} + +	double coast_duration() { +		return apogee_time - coast_time; +	} + +	double coast_height() { +		return apogee_height - coast_height; +	} + +	double coast_speed() { +		return coast_height() / coast_duration(); +	} + +	double coast_accel() { +		return coast_speed() / coast_duration(); +	} + +	double descent_duration() { +		return landed_time - apogee_time; +	} + +	double descent_height() { +		return apogee_height - landed_height; +	} + +	double descent_speed() { +		return descent_height() / descent_duration(); +	} + +	public MicroStats(MicroData data) { + +		this.data = data; + +		find_coast(); +		find_apogee(); +		find_landing(); +		find_max_speed(); +		find_max_accel(); +	} + +	public MicroStats() { +		this(new MicroData()); +	} +} diff --git a/micropeak/MicroStatsTable.java b/micropeak/MicroStatsTable.java new file mode 100644 index 00000000..f373e25d --- /dev/null +++ b/micropeak/MicroStatsTable.java @@ -0,0 +1,138 @@ +/* + * 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.micropeak; + +import java.awt.*; +import javax.swing.*; +import org.altusmetrum.AltosLib.*; +import org.altusmetrum.altosuilib.*; + +public class MicroStatsTable extends JComponent { +	GridBagLayout	layout; + +	class MicroStat { +		JLabel		label; +		JTextField[]	texts; + +		public void set_values(String ... values) { +			for (int j = 0; j < values.length; j++) { +				texts[j].setText(values[j]); +			} +		} + +		public MicroStat(GridBagLayout layout, int y, String label_text, String ... values) { +			GridBagConstraints	c = new GridBagConstraints(); +			c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad); +			c.weighty = 1; + +			label = new JLabel(label_text); +			label.setFont(AltosUILib.label_font); +			label.setHorizontalAlignment(SwingConstants.LEFT); +			c.gridx = 0; c.gridy = y; +			c.anchor = GridBagConstraints.WEST; +			c.fill = GridBagConstraints.VERTICAL; +			c.weightx = 0; +			layout.setConstraints(label, c); +			add(label); + +			texts = new JTextField[values.length]; +			for (int j = 0; j < values.length; j++) { +				JTextField value = new JTextField(values[j]); +				value.setFont(AltosUILib.value_font); +				value.setHorizontalAlignment(SwingConstants.RIGHT); +				texts[j] = value; +				c.gridx = j+1; c.gridy = y; +				c.anchor = GridBagConstraints.EAST; +				c.fill = GridBagConstraints.BOTH; +				c.weightx = 1; +				layout.setConstraints(value, c); +				add(value); +			} +		} +	} + +	MicroStat	max_height, max_speed; +	MicroStat	max_accel, avg_accel; +	MicroStat	boost_duration; +	MicroStat	coast_duration; +	MicroStat	descent_speed; +	MicroStat	descent_duration; +	MicroStat	flight_time; +	 +	public void setStats(MicroStats stats) { +		max_height.set_values(String.format("%5.0f m", stats.apogee_height), +				      String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.apogee_height))); +		max_speed.set_values(String.format("%5.0f m/s", stats.max_speed), +				     String.format("%5.0f mph", AltosConvert.meters_to_mph(stats.max_speed)), +				     String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed))); +		max_accel.set_values(String.format("%5.0f m/s²", stats.max_accel), +				     String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_accel)), +				     String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_accel))); +		avg_accel.set_values(String.format("%5.0f m/s²", stats.boost_accel(), +						   String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.boost_accel())), +						   String.format("%5.0f G", AltosConvert.meters_to_g(stats.boost_accel())))); +		boost_duration.set_values(String.format("%6.1f s", stats.boost_duration())); +		coast_duration.set_values(String.format("%6.1f s", stats.coast_duration())); +		descent_speed.set_values(String.format("%5.0f m/s", stats.descent_speed()), +					 String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.descent_speed()))); +		descent_duration.set_values(String.format("%6.1f s", stats.descent_duration())); +		flight_time.set_values(String.format("%6.1f s", stats.landed_time)); +	} + +	public void setData(MicroData data) { +		setStats(new MicroStats(data)); +	} + +	public MicroStatsTable(MicroStats stats) { +		layout = new GridBagLayout(); + +		setLayout(layout); +		int y = 0; +		max_height = new MicroStat(layout, y++, "Maximum height", +					   String.format("%5.0f m", stats.apogee_height), +					   String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.apogee_height))); +		max_speed = new MicroStat(layout, y++, "Maximum speed", +					  String.format("%5.0f m/s", stats.max_speed), +					  String.format("%5.0f mph", AltosConvert.meters_to_mph(stats.max_speed)), +					  String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed))); +		max_accel = new MicroStat(layout, y++, "Maximum boost acceleration", +					  String.format("%5.0f m/s²", stats.max_accel), +					  String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_accel)), +					  String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_accel))); +		avg_accel = new MicroStat(layout, y++, "Average boost acceleration", +					  String.format("%5.0f m/s²", stats.boost_accel(), +							String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.boost_accel())), +							String.format("%5.0f G", AltosConvert.meters_to_g(stats.boost_accel())))); +		boost_duration = new MicroStat(layout, y++, "Boost duration", +					       String.format("%6.0f s", stats.boost_duration())); +		coast_duration = new MicroStat(layout, y++, "Coast duration", +					       String.format("%6.1f s", stats.coast_duration())); +		descent_speed = new MicroStat(layout, y++, "Descent rate", +					      String.format("%5.0f m/s", stats.descent_speed()), +					      String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.descent_speed()))); +		descent_duration = new MicroStat(layout, y++, "Descent duration", +						 String.format("%6.1f s", stats.descent_duration())); +		flight_time = new MicroStat(layout, y++, "Flight Time", +					    String.format("%6.0f s", stats.landed_time)); +	} + +	public MicroStatsTable() { +		this(new MicroStats()); +	} +	 +}
\ No newline at end of file diff --git a/micropeak/MicroUSB.java b/micropeak/MicroUSB.java new file mode 100644 index 00000000..f56d81d4 --- /dev/null +++ b/micropeak/MicroUSB.java @@ -0,0 +1,109 @@ +/* + * 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.micropeak; + +import java.util.*; +import libaltosJNI.*; +import org.altusmetrum.altosuilib.*; + +public class MicroUSB extends altos_device implements AltosDevice { + +	static boolean	initialized = false; +	static boolean	loaded_library = false; + +	public static boolean load_library() { +		if (!initialized) { +			try { +				System.loadLibrary("altos"); +				libaltos.altos_init(); +				loaded_library = true; +			} catch (UnsatisfiedLinkError e) { +				try { +					System.loadLibrary("altos64"); +					libaltos.altos_init(); +					loaded_library = true; +				} catch (UnsatisfiedLinkError e2) { +					loaded_library = false; +				} +			} +			initialized = true; +		} +		return loaded_library; +	} + +	public String toString() { +		String	name = getName(); +		if (name == null) +			name = "Altus Metrum"; +		return String.format("%-24.24s %s", +				     name, getPath()); +	} + +	public String toShortString() { +		String	name = getName(); +		if (name == null) +			name = "Altus Metrum"; +		return String.format("%s %s", +				     name, getPath()); + +	} + +	public String getErrorString() { +		altos_error	error = new altos_error(); + +		libaltos.altos_get_last_error(error); +		return String.format("%s (%d)", error.getString(), error.getCode()); +	} + +	public SWIGTYPE_p_altos_file open() { +		return libaltos.altos_open(this); +	} + +	private boolean isMicro() { +		if (getVendor() != 0x0403) +			return false; +		if (getProduct() != 0x6015) +			return false; +		return true; +	} + +	public boolean matchProduct(int product) { +		return isMicro(); +	} + +	static java.util.List<MicroUSB> list() { +		if (!load_library()) +			return null; + +		SWIGTYPE_p_altos_list list = libaltos.altos_ftdi_list_start(); + +		ArrayList<MicroUSB> device_list = new ArrayList<MicroUSB>(); +		if (list != null) { +			for (;;) { +				MicroUSB device = new MicroUSB(); +				if (libaltos.altos_list_next(list, device) == 0) +					break; +				if (device.isMicro()) +					device_list.add(device); +			} +			libaltos.altos_list_finish(list); +		} + +		return device_list; +	} +}
\ No newline at end of file diff --git a/micropeak/ReadMe-Mac.rtf b/micropeak/ReadMe-Mac.rtf new file mode 100644 index 00000000..64bbdeb6 --- /dev/null +++ b/micropeak/ReadMe-Mac.rtf @@ -0,0 +1,19 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww10800\viewh8400\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\f0\fs24 \cf0 Installing MicroPeak software for Mac OS X computers\ +\ +There are two files included in the Mac OS X distribution:\ +\ + 1) The MicroPeak application\ +\ + 2) The FTDI device drivers\ +\ +As with most Mac OS X applications, install MicroPeak by dragging it from the distribution disk image to a suitable place on your computer.\ +\ +To communicate with the MicroPeak serial adapter, you need to installed the FTDI device drivers, which is done by double-clicking on the FTDIUSBSerialDriver package file. That will guide you through the installation process.\ +\ +Thanks for choosing AltusMetrum products!}
\ No newline at end of file diff --git a/micropeak/micropeak-fat b/micropeak/micropeak-fat new file mode 100755 index 00000000..ace7548d --- /dev/null +++ b/micropeak/micropeak-fat @@ -0,0 +1,4 @@ +#!/bin/sh +me=`which "$0"` +dir=`dirname "$me"` +exec java -cp "$dir/*" -Djava.library.path="$dir" -jar "$dir"/micropeak-fat.jar  "$@" diff --git a/micropeak/micropeak-windows.nsi b/micropeak/micropeak-windows.nsi new file mode 100644 index 00000000..425048bd --- /dev/null +++ b/micropeak/micropeak-windows.nsi @@ -0,0 +1,123 @@ +!addplugindir Instdrv/NSIS/Plugins +; Definitions for Java 1.6 Detection +!define JRE_VERSION "1.6" +!define JRE_ALTERNATE "1.7" +!define JRE_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=52247&/jre-6u27-windows-i586-p.exe" +!define PRODUCT_NAME "Altus Metrum Windows Software" + +Name "Altus Metrum MicroPeak Installer" + +; Default install directory +InstallDir "$PROGRAMFILES\AltusMetrum" + +; Tell the installer where to re-install a new version +InstallDirRegKey HKLM "Software\AltusMetrum" "Install_Dir" + +LicenseText "GNU General Public License Version 2" +LicenseData "../COPYING" + +; Need admin privs for Vista or Win7 +RequestExecutionLevel admin + +ShowInstDetails Show + +ComponentText "Altus Metrum MicroPeak Software Installer" + +Function GetJRE +        MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION} 32-bit, it will now \ +                         be downloaded and installed" + +        StrCpy $2 "$TEMP\Java Runtime Environment.exe" +        nsisdl::download /TIMEOUT=30000 ${JRE_URL} $2 +        Pop $R0 ;Get the return value +                StrCmp $R0 "success" +3 +                MessageBox MB_OK "Download failed: $R0" +                Quit +        ExecWait $2 +        Delete $2 +FunctionEnd + + +Function DetectJRE +  ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" \ +             "CurrentVersion" +  StrCmp $2 ${JRE_VERSION} done + +  StrCmp $2 ${JRE_ALTERNATE} done + +  Call GetJRE + +  done: +FunctionEnd + +; Pages to present + +Page license +Page components +Page directory +Page instfiles + +UninstPage uninstConfirm +UninstPage instfiles + +; And the stuff to install + +Section "MicroPeak Application" +	Call DetectJRE + +	SetOutPath $INSTDIR + +	File "micropeak-fat.jar" +	File "AltosLib.jar" +	File "AltosUILib.jar" +	File "jfreechart.jar" +	File "jcommon.jar" + +	File "*.dll" + +	File "../icon/*.ico" + +	CreateShortCut "$SMPROGRAMS\MicroPeak.lnk" "$SYSDIR\javaw.exe" "-jar micropeak-fat.jar" "$INSTDIR\micro-peak.ico" +SectionEnd + +Section "MicroPeak Desktop Shortcut" +	CreateShortCut "$DESKTOP\MicroPeak.lnk" "$INSTDIR\micropeak-fat.jar"  "" "$INSTDIR\micro-peak.ico" +SectionEnd + +Section "Documentation" + +	SetOutPath $INSTDIR + +	File "../doc/micropeak.pdf" +SectionEnd + +Section "Uninstaller" + +	; Deal with the uninstaller + +	SetOutPath $INSTDIR + +	; Write the install path to the registry +	WriteRegStr HKLM SOFTWARE\AltusMetrum "Install_Dir" "$INSTDIR" + +	; Write the uninstall keys for windows +	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "DisplayName" "Altus Metrum" +	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "UninstallString" '"$INSTDIR\uninstall.exe"' +	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoModify" "1" +	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoRepair" "1" + +	WriteUninstaller "uninstall.exe" +SectionEnd + +Section "Uninstall" +	DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" +	DeleteRegKey HKLM "Software\AltusMetrum" + +	Delete "$INSTDIR\*.*" +	RMDir "$INSTDIR" + +	; Remove shortcuts, if any +	Delete "$SMPROGRAMS\MicroPeak.lnk" +	Delete "$DESKTOP\MicroPeak.lnk" +	 +SectionEnd diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index 63d2f955..8068740f 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -834,8 +834,8 @@ ao_radio_rx_isr(void)  {  	uint8_t	d; -	d = stm_spi2.dr; -	stm_spi2.dr = 0; +	d = AO_CC1120_SPI.dr; +	AO_CC1120_SPI.dr = 0;  	if (rx_ignore == 0) {  		if (rx_data_cur >= rx_data_count)  			ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); @@ -862,6 +862,7 @@ ao_radio_rx_wait(void)  	do {  		if (ao_radio_mcu_wake)  			ao_radio_check_marc_status(); +		ao_alarm(AO_MS_TO_TICKS(100));  		ao_arch_block_interrupts();  		rx_waiting = 1;  		while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK && @@ -873,6 +874,7 @@ ao_radio_rx_wait(void)  		}  		rx_waiting = 0;  		ao_arch_release_interrupts(); +		ao_clear_alarm();  	} while (ao_radio_mcu_wake);  	if (ao_radio_abort)  		return 0; @@ -922,10 +924,10 @@ ao_radio_recv(__xdata void *d, uint8_t size)  	ao_radio_wake = 0;  	ao_radio_mcu_wake = 0; -	stm_spi2.cr2 = 0; +	AO_CC1120_SPI.cr2 = 0;  	/* clear any RXNE */ -	(void) stm_spi2.dr; +	(void) AO_CC1120_SPI.dr;  	/* Have the radio signal when the preamble quality goes high */  	ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_PQT_REACHED); diff --git a/src/megadongle-v0.1/ao_pins.h b/src/megadongle-v0.1/ao_pins.h index 9fc93fb1..c766a48c 100644 --- a/src/megadongle-v0.1/ao_pins.h +++ b/src/megadongle-v0.1/ao_pins.h @@ -135,6 +135,7 @@  #define AO_CC1120_SPI_CS_PORT	(&stm_gpioa)  #define AO_CC1120_SPI_CS_PIN	0  #define AO_CC1120_SPI_BUS	AO_SPI_2_PB13_PB14_PB15 +#define AO_CC1120_SPI		stm_spi2  #define AO_CC1120_INT_PORT	(&stm_gpioc)  #define AO_CC1120_INT_PIN	13 diff --git a/src/megametrum-v0.1/ao_pins.h b/src/megametrum-v0.1/ao_pins.h index b1a70ea2..64da41a9 100644 --- a/src/megametrum-v0.1/ao_pins.h +++ b/src/megametrum-v0.1/ao_pins.h @@ -281,6 +281,7 @@ struct ao_adc {  #define AO_CC1120_SPI_CS_PORT	(&stm_gpioc)  #define AO_CC1120_SPI_CS_PIN	5  #define AO_CC1120_SPI_BUS	AO_SPI_2_PB13_PB14_PB15 +#define AO_CC1120_SPI		stm_spi2  #define AO_CC1120_INT_PORT		(&stm_gpioc)  #define AO_CC1120_INT_PIN		14 diff --git a/src/micropeak/Makefile b/src/micropeak/Makefile index 0c48ed66..ff0a4499 100644 --- a/src/micropeak/Makefile +++ b/src/micropeak/Makefile @@ -20,13 +20,6 @@ ifndef VERSION  include ../Version  endif -# Support for a logging EEPROM -# -#EEPROM_SRC=ao_async.c \ -#	ao_i2c_attiny.c \ -#	ao_at24c.c -# -  ALTOS_SRC = \  	ao_micropeak.c \  	ao_spi_attiny.c \ @@ -39,7 +32,8 @@ ALTOS_SRC = \  	ao_notask.c \  	ao_eeprom_tiny.c \  	ao_panic.c \ -	$(EEPROM_SRC) +	ao_log_micro.c \ +	ao_async.c  INC=\  	ao.h \ @@ -48,13 +42,15 @@ INC=\  	ao_arch_funcs.h \  	ao_exti.h \  	ao_ms5607.h \ +	ao_log_micro.h \ +	ao_micropeak.h \  	altitude-pa.h  IDPRODUCT=0  PRODUCT=MicroPeak-v0.1  PRODUCT_DEF=-DMICROPEAK  CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers -CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DATTINY +CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY  NICKLE=nickle diff --git a/src/micropeak/ao_async.c b/src/micropeak/ao_async.c index 04bba9e8..3556f54c 100644 --- a/src/micropeak/ao_async.c +++ b/src/micropeak/ao_async.c @@ -21,20 +21,51 @@  #define AO_ASYNC_BAUD	38400l  #define AO_ASYNC_DELAY	(uint8_t) (1000000l / AO_ASYNC_BAUD) +#define LED_PORT	PORTB + +void +ao_async_start(void) +{ +	LED_PORT |= (1 << AO_LED_SERIAL); +} + +void +ao_async_stop(void) +{ +	LED_PORT &= ~(1 << AO_LED_SERIAL); +} +  void  ao_async_byte(uint8_t byte)  {  	uint8_t		b;  	uint16_t	w; -	/* start bit */ - -	/* start     data         stop */ -	w = 0x001 | (byte << 1) | 0x000; +	/*    start           data           stop */ +	w = (0x000 << 0) | (byte << 1) | (0x001 << 9); +	ao_arch_block_interrupts();  	for (b = 0; b < 10; b++) { -		ao_led_set((w & 1) << AO_LED_SERIAL); +		uint8_t	v = LED_PORT & ~(1 << AO_LED_SERIAL); +		v |= (w & 1) << AO_LED_SERIAL; +		LED_PORT = v;  		w >>= 1; -		ao_delay_us(26); + +		/* Carefully timed to hit around 9600 baud */ +		asm volatile ("nop"); +		asm volatile ("nop"); + +		asm volatile ("nop"); +		asm volatile ("nop"); +		asm volatile ("nop"); +		asm volatile ("nop"); +		asm volatile ("nop"); + +		asm volatile ("nop"); +		asm volatile ("nop"); +		asm volatile ("nop"); +		asm volatile ("nop"); +		asm volatile ("nop");  	} +	ao_arch_release_interrupts();  } diff --git a/src/micropeak/ao_async.h b/src/micropeak/ao_async.h index a06d2e1a..1b239712 100644 --- a/src/micropeak/ao_async.h +++ b/src/micropeak/ao_async.h @@ -19,6 +19,12 @@  #define _AO_ASYNC_H_  void +ao_async_start(void); + +void +ao_async_stop(void); + +void  ao_async_byte(uint8_t byte);  #endif /* _AO_ASYNC_H_ */ diff --git a/src/micropeak/ao_log_micro.c b/src/micropeak/ao_log_micro.c index eda0d1d2..d665efb5 100644 --- a/src/micropeak/ao_log_micro.c +++ b/src/micropeak/ao_log_micro.c @@ -16,58 +16,106 @@   */  #include <ao.h> +#include <ao_micropeak.h>  #include <ao_log_micro.h>  #include <ao_async.h> -#if HAS_EEPROM - -ao_pos_t	ao_log_micro_pos; +static uint16_t ao_log_offset = STARTING_LOG_OFFSET;  void -ao_log_micro_data(uint32_t data) +ao_log_micro_save(void)  { -	ao_storage_write(ao_log_micro_pos, &data, sizeof (data)); -	ao_log_micro_pos += sizeof (data); +	uint16_t	n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t); +	ao_eeprom_write(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground)); +	ao_eeprom_write(PA_MIN_OFFSET, &pa_min, sizeof (pa_min)); +	ao_eeprom_write(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));  } -uint32_t	ao_log_last_ground; -uint32_t	ao_log_last_done; +void +ao_log_micro_restore(void) +{ +	ao_eeprom_read(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground)); +	ao_eeprom_read(PA_MIN_OFFSET, &pa_min, sizeof (pa_min)); +} -uint8_t -ao_log_micro_scan(void) +void +ao_log_micro_data(void)  { -	uint32_t	data; -	ao_pos_t	pos; +	uint16_t	low_bits = pa; -	ao_storage_read(0, &data, sizeof (data)); -	if ((data & AO_LOG_MICRO_MASK) != AO_LOG_MICRO_GROUND) -		return 0; +	if (ao_log_offset < MAX_LOG_OFFSET) { +		ao_eeprom_write(ao_log_offset, &low_bits, sizeof (low_bits)); +		ao_log_offset += sizeof (low_bits); +	} +} + +#define POLY 0x8408 + +static uint16_t +ao_log_micro_crc(uint16_t crc, uint8_t byte) +{ +	uint8_t	i; -	ao_log_last_ground = data & ~(AO_LOG_MICRO_MASK); -	for (pos = 4; pos < ao_storage_total; pos += 4) { -		ao_storage_read(pos, &data, sizeof (data)); -		if ((data & AO_LOG_MICRO_MASK) == AO_LOG_MICRO_GROUND) { -			ao_log_last_done = data & ~(AO_LOG_MICRO_MASK); -			return 1; -		} +	for (i = 0; i < 8; i++) { +		if ((crc & 0x0001) ^ (byte & 0x0001)) +			crc = (crc >> 1) ^ POLY; +		else +			crc = crc >> 1; +		byte >>= 1;  	} -	return 0; +	return crc; +} + +static void +ao_log_hex_nibble(uint8_t b) +{ +	if (b < 10) +		ao_async_byte('0' + b); +	else +		ao_async_byte('a' - 10 + b); +} + +static void +ao_log_hex(uint8_t b) +{ +	ao_log_hex_nibble(b>>4); +	ao_log_hex_nibble(b&0xf); +} + +static void +ao_log_newline(void) +{ +	ao_async_byte('\r'); +	ao_async_byte('\n');  }  void  ao_log_micro_dump(void)  { -	ao_pos_t	pos; -	uint8_t		data[4]; -	uint8_t		i; +	uint16_t	n_samples; +	uint16_t	nbytes; +	uint8_t		byte; +	uint16_t	b; +	uint16_t	crc = 0xffff; -	for (pos = 0; pos < ao_storage_total; pos += 4) { -		ao_storage_read(pos, data, 4); -		for (i = 0; i < 4; i++) -			ao_async_byte(data[i]); -		if (data[3] == (uint8_t) (AO_LOG_MICRO_GROUND >> 24)) -			break; +	ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples)); +	if (n_samples == 0xffff) +		n_samples = 0; +	nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples; +	ao_async_start(); +	ao_async_byte('M'); +	ao_async_byte('P'); +	for (b = 0; b < nbytes; b++) { +		if ((b & 0xf) == 0) +			ao_log_newline(); +		ao_eeprom_read(b, &byte, 1); +		ao_log_hex(byte); +		crc = ao_log_micro_crc(crc, byte);  	} +	ao_log_newline(); +	crc = ~crc; +	ao_log_hex(crc >> 8); +	ao_log_hex(crc); +	ao_log_newline(); +	ao_async_stop();  } - -#endif diff --git a/src/micropeak/ao_log_micro.h b/src/micropeak/ao_log_micro.h index 15b2d178..976852ee 100644 --- a/src/micropeak/ao_log_micro.h +++ b/src/micropeak/ao_log_micro.h @@ -18,19 +18,20 @@  #ifndef _AO_LOG_MICRO_H_  #define _AO_LOG_MICRO_H_ -#define AO_LOG_MICRO_GROUND	(0l << 24) -#define AO_LOG_MICRO_DATA	(1l << 24) -#define AO_LOG_MICRO_DONE	(0xaal << 24) -#define AO_LOG_MICRO_MASK	(0xffl << 24) +#define PA_GROUND_OFFSET	0 +#define PA_MIN_OFFSET		4 +#define N_SAMPLES_OFFSET	8 +#define STARTING_LOG_OFFSET	10 +#define MAX_LOG_OFFSET		512  void -ao_log_micro_data(uint32_t data); +ao_log_micro_save(void); -extern uint32_t	ao_log_last_ground; -extern uint32_t	ao_log_last_done; +void +ao_log_micro_restore(void); -uint8_t -ao_log_micro_scan(void); +void +ao_log_micro_data(void);  void  ao_log_micro_dump(void); diff --git a/src/micropeak/ao_micropeak.c b/src/micropeak/ao_micropeak.c index 525cfa42..f361aa26 100644 --- a/src/micropeak/ao_micropeak.c +++ b/src/micropeak/ao_micropeak.c @@ -16,22 +16,23 @@   */  #include <ao.h> +#include <ao_micropeak.h>  #include <ao_ms5607.h>  #include <ao_log_micro.h> +#include <ao_async.h>  static struct ao_ms5607_sample	sample;  static struct ao_ms5607_value	value; -static uint32_t	pa; -static uint32_t	pa_sum; -static uint32_t	pa_avg; -static int32_t	pa_diff; -static uint32_t	pa_ground; -static uint32_t	pa_min; -static uint32_t	pa_interval_min, pa_interval_max; -static alt_t	ground_alt, max_alt; +uint32_t	pa; +uint32_t	pa_avg; +uint32_t	pa_ground; +uint32_t	pa_min; +alt_t		ground_alt, max_alt;  alt_t		ao_max_height; +static uint32_t	pa_sum; +  static void  ao_pa_get(void)  { @@ -40,22 +41,6 @@ ao_pa_get(void)  	pa = value.pres;  } -#define FILTER_SHIFT		3 -#define SAMPLE_SLEEP		AO_MS_TO_TICKS(96) - -/* 16 sample, or about two seconds worth */ -#define GROUND_AVG_SHIFT	4 -#define GROUND_AVG		(1 << GROUND_AVG_SHIFT) - -/* Pressure change (in Pa) to detect boost */ -#define BOOST_DETECT		120	/* 10m at sea level, 12m at 2000m */ - -/* Wait after power on before doing anything to give the user time to assemble the rocket */ -#define BOOST_DELAY		AO_SEC_TO_TICKS(30) - -/* Pressure change (in Pa) to detect landing */ -#define LAND_DETECT		12	/* 1m at sea level, 1.2m at 2000m */ -  static void  ao_compute_height(void)  { @@ -64,96 +49,56 @@ ao_compute_height(void)  	ao_max_height = max_alt - ground_alt;  } -#if !HAS_EEPROM - -#define PA_GROUND_OFFSET	0 -#define PA_MIN_OFFSET		4 -#define N_SAMPLES_OFFSET	8 -#define STARTING_LOG_OFFSET	10 -#define MAX_LOG_OFFSET		512 - -static uint16_t ao_log_offset = STARTING_LOG_OFFSET; - -void -ao_save_flight(void) +static void +ao_pips(void)  { -	uint16_t	n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t); -	ao_eeprom_write(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground)); -	ao_eeprom_write(PA_MIN_OFFSET, &pa_min, sizeof (pa_min)); -	ao_eeprom_write(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples)); +	uint8_t	i; +	for (i = 0; i < 10; i++) { +		ao_led_toggle(AO_LED_REPORT); +		ao_delay(AO_MS_TO_TICKS(80)); +	} +	ao_delay(AO_MS_TO_TICKS(200));  } -void -ao_restore_flight(void) -{ -	ao_eeprom_read(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground)); -	ao_eeprom_read(PA_MIN_OFFSET, &pa_min, sizeof (pa_min)); -} +#define NUM_PA_HIST	16 -void -ao_log_micro(void) -{ -	uint16_t	low_bits = pa; +#define SKIP_PA_HIST(i,j)	(((i) + (j)) & (NUM_PA_HIST - 1)) -	if (ao_log_offset < MAX_LOG_OFFSET) { -		ao_eeprom_write(ao_log_offset, &low_bits, sizeof (low_bits)); -		ao_log_offset += sizeof (low_bits); -	} -} -#endif +static uint32_t	pa_hist[NUM_PA_HIST];  int  main(void)  {  	int16_t		sample_count;  	uint16_t	time; -#if HAS_EEPROM -	uint8_t	dump_eeprom = 0; -#endif +	uint32_t	pa_interval_min, pa_interval_max; +	int32_t		pa_diff; +	uint8_t		h, i; +  	ao_led_init(LEDS_AVAILABLE);  	ao_timer_init(); -#if HAS_EEPROM - -	/* Set MOSI and CLK as inputs with pull-ups */ -	DDRB &= ~(1 << 0) | (1 << 2); -	PORTB |= (1 << 0) | (1 << 2); - -	/* Check to see if either MOSI or CLK are pulled low by the -	 * user shorting them to ground. If so, dump the eeprom out -	 * via the LED. Wait for the shorting wire to go away before -	 * continuing. -	 */ -	while ((PINB & ((1 << 0) | (1 << 2))) != ((1 << 0) | (1 << 2))) -		dump_eeprom = 1; -	PORTB &= ~(1 << 0) | (1 << 2); - -	ao_i2c_init(); -#endif -	ao_restore_flight(); -	ao_compute_height(); -	/* Give the person a second to get their finger out of the way */ -	ao_delay(AO_MS_TO_TICKS(1000)); -	ao_report_altitude(); -	 +	/* Init external hardware */  	ao_spi_init();  	ao_ms5607_init();  	ao_ms5607_setup(); -#if HAS_EEPROM -	ao_storage_init(); - -	/* Check to see if there's a flight recorded in memory */ -	if (dump_eeprom && ao_log_micro_scan()) -		ao_log_micro_dump(); -#endif	 +	/* Give the person a second to get their finger out of the way */ +	ao_delay(AO_MS_TO_TICKS(1000)); +	ao_log_micro_restore(); +	ao_compute_height(); +	ao_report_altitude(); +	ao_pips(); +	ao_log_micro_dump(); +	  	ao_delay(BOOST_DELAY);  	/* Wait for motion, averaging values to get ground pressure */  	time = ao_time();  	ao_pa_get();  	pa_avg = pa_ground = pa << FILTER_SHIFT;  	sample_count = 0; +	h = 0;  	for (;;) {  		time += SAMPLE_SLEEP;  		if (sample_count == 0) @@ -162,6 +107,8 @@ main(void)  		ao_pa_get();  		if (sample_count == 0)  			ao_led_off(AO_LED_REPORT); +		pa_hist[h] = pa; +		h = SKIP_PA_HIST(h,1);  		pa_avg = pa_avg - (pa_avg >> FILTER_SHIFT) + pa;  		pa_diff = pa_ground - pa_avg; @@ -182,9 +129,18 @@ main(void)  	pa_ground >>= FILTER_SHIFT; -#if HAS_EEPROM -	ao_log_micro_data(AO_LOG_MICRO_GROUND | pa_ground); -#endif +	/* Go back and find the first sample a decent interval above the ground */ +	pa_min = pa_ground - LAND_DETECT; +	for (i = SKIP_PA_HIST(h,2); i != h; i = SKIP_PA_HIST(i,2)) { +		if (pa_hist[i] < pa_min) +			break; +	} + +	/* Log the remaining samples so we get a complete history since leaving the ground */ +	for (; i != h; i = SKIP_PA_HIST(i,2)) { +		pa = pa_hist[i]; +		ao_log_micro_data(); +	}  	/* Now sit around until the pressure is stable again and record the max */ @@ -200,12 +156,8 @@ main(void)  		ao_pa_get();  		if ((sample_count & 3) == 0)  			ao_led_off(AO_LED_REPORT); -#if HAS_EEPROM -		ao_log_micro_data(AO_LOG_MICRO_DATA | pa); -#else  		if (sample_count & 1) -			ao_log_micro(); -#endif +			ao_log_micro_data();  		pa_avg = pa_avg - (pa_avg >> FILTER_SHIFT) + pa;  		if (pa_avg < pa_min)  			pa_min = pa_avg; @@ -228,10 +180,7 @@ main(void)  		}  	}  	pa_min >>= FILTER_SHIFT; -#if HAS_EEPROM -	ao_log_micro_data(AO_LOG_MICRO_DONE | pa_min); -#endif -	ao_save_flight(); +	ao_log_micro_save();  	ao_compute_height();  	ao_report_altitude();  	for (;;) { diff --git a/src/micropeak/ao_micropeak.h b/src/micropeak/ao_micropeak.h new file mode 100644 index 00000000..e408d7c5 --- /dev/null +++ b/src/micropeak/ao_micropeak.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef _AO_MICROPEAK_H_ +#define _AO_MICROPEAK_H_ + +#define FILTER_SHIFT		3 +#define SAMPLE_SLEEP		AO_MS_TO_TICKS(96) + +/* 16 sample, or about two seconds worth */ +#define GROUND_AVG_SHIFT	4 +#define GROUND_AVG		(1 << GROUND_AVG_SHIFT) + +/* Pressure change (in Pa) to detect boost */ +#define BOOST_DETECT		120	/* 10m at sea level, 12m at 2000m */ + +/* Wait after power on before doing anything to give the user time to assemble the rocket */ +#define BOOST_DELAY		AO_SEC_TO_TICKS(30) + +/* Pressure change (in Pa) to detect landing */ +#define LAND_DETECT		12	/* 1m at sea level, 1.2m at 2000m */ + +/* Current sensor pressure value */ +extern uint32_t	pa; + +/* IIR filtered pressure value */ +extern uint32_t	pa_avg; + +/* Average pressure value on ground */ +extern uint32_t	pa_ground; + +/* Minimum recorded filtered pressure value */ +extern uint32_t	pa_min; + +/* Pressure values converted to altitudes */ +extern alt_t	ground_alt, max_alt; + +/* max_alt - ground_alt */ +extern alt_t	ao_max_height; + +#endif + | 
