Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
authorBdale Garbee <bdale@gag.com>
Sat, 12 Jan 2013 17:57:22 +0000 (10:57 -0700)
committerBdale Garbee <bdale@gag.com>
Sat, 12 Jan 2013 17:57:22 +0000 (10:57 -0700)
125 files changed:
Makefile.am
altoslib/AltosPreferences.java
altoslib/AltosRecord.java
altoslib/AltosRecordMM.java
altoslib/AltosRecordNone.java
altoslib/AltosRecordTM.java
altoslib/AltosSpeed.java
altoslib/AltosState.java
altoslib/AltosUnitsListener.java [new file with mode: 0644]
altoslib/Makefile.am
altosui/AltosBTDevice.java
altosui/AltosBTKnown.java
altosui/AltosBTManage.java
altosui/AltosCSVUI.java
altosui/AltosConfig.java
altosui/AltosConfigFreqUI.java
altosui/AltosConfigPyroUI.java
altosui/AltosConfigTD.java
altosui/AltosConfigTDUI.java
altosui/AltosConfigUI.java
altosui/AltosConfigureUI.java
altosui/AltosDebug.java
altosui/AltosDeviceDialog.java [deleted file]
altosui/AltosDeviceUIDialog.java [new file with mode: 0644]
altosui/AltosDialog.java [deleted file]
altosui/AltosEepromManage.java
altosui/AltosEepromMonitor.java
altosui/AltosEepromSelect.java
altosui/AltosFlash.java
altosui/AltosFlashUI.java
altosui/AltosFlightUI.java
altosui/AltosFontListener.java [deleted file]
altosui/AltosFrame.java [deleted file]
altosui/AltosGraphUI.java
altosui/AltosIdleMonitorUI.java
altosui/AltosIgniteUI.java
altosui/AltosLaunch.java
altosui/AltosLaunchUI.java
altosui/AltosRomconfigUI.java
altosui/AltosScanUI.java
altosui/AltosSerial.java
altosui/AltosSerialInUseException.java
altosui/AltosSiteMapPreload.java
altosui/AltosUI.java
altosui/AltosUIListener.java [deleted file]
altosui/AltosUIPreferences.java
altosui/AltosUSBDevice.java [deleted file]
altosui/AltosVersion.java.in [deleted file]
altosui/Makefile.am
altosui/ReadMe-Mac.rtf [new file with mode: 0644]
altosui/libaltos/.gitignore [deleted file]
altosui/libaltos/Makefile-standalone [deleted file]
altosui/libaltos/Makefile.am [deleted file]
altosui/libaltos/cjnitest.c [deleted file]
altosui/libaltos/libaltos.c [deleted file]
altosui/libaltos/libaltos.dylib [deleted file]
altosui/libaltos/libaltos.h [deleted file]
altosui/libaltos/libaltos.i0 [deleted file]
altosuilib/AltosDevice.java [new file with mode: 0644]
altosuilib/AltosDeviceDialog.java [new file with mode: 0644]
altosuilib/AltosFontListener.java [new file with mode: 0644]
altosuilib/AltosUIConfigure.java [new file with mode: 0644]
altosuilib/AltosUIDialog.java [new file with mode: 0644]
altosuilib/AltosUIFrame.java [new file with mode: 0644]
altosuilib/AltosUILib.java [new file with mode: 0644]
altosuilib/AltosUIListener.java [new file with mode: 0644]
altosuilib/AltosUIPreferences.java [new file with mode: 0644]
altosuilib/AltosUIPreferencesBackend.java [new file with mode: 0644]
altosuilib/AltosUIVersion.java.in [new file with mode: 0644]
altosuilib/AltosUSBDevice.java [new file with mode: 0644]
altosuilib/AltosUnitsListener.java [new file with mode: 0644]
altosuilib/Makefile.am [new file with mode: 0644]
configure.ac
icon/altus-metrum.ico
icon/micro-peak.ico [new file with mode: 0644]
icon/micropeak-128.png [new file with mode: 0644]
icon/micropeak-16.png [new file with mode: 0644]
icon/micropeak-256.png [new file with mode: 0644]
icon/micropeak-32.png [new file with mode: 0644]
icon/micropeak-48.png [new file with mode: 0644]
icon/micropeak-64.png [new file with mode: 0644]
libaltos/.gitignore [new file with mode: 0644]
libaltos/Makefile-standalone [new file with mode: 0644]
libaltos/Makefile.am [new file with mode: 0644]
libaltos/cjnitest.c [new file with mode: 0644]
libaltos/libaltos.c [new file with mode: 0644]
libaltos/libaltos.dylib [new file with mode: 0755]
libaltos/libaltos.h [new file with mode: 0644]
libaltos/libaltos.i0 [new file with mode: 0644]
micropeak/.gitignore [new file with mode: 0644]
micropeak/FTDI.tar.gz [new file with mode: 0644]
micropeak/Info.plist.in [new file with mode: 0644]
micropeak/Makefile.am [new file with mode: 0644]
micropeak/MicroData.java [new file with mode: 0644]
micropeak/MicroDataPoint.java [new file with mode: 0644]
micropeak/MicroDeviceDialog.java [new file with mode: 0644]
micropeak/MicroDownload.java [new file with mode: 0644]
micropeak/MicroExport.java [new file with mode: 0644]
micropeak/MicroFile.java [new file with mode: 0644]
micropeak/MicroFileChooser.java [new file with mode: 0644]
micropeak/MicroFrame.java [new file with mode: 0644]
micropeak/MicroGraph.java [new file with mode: 0644]
micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub [new file with mode: 0755]
micropeak/MicroPeak.app/Contents/PkgInfo [new file with mode: 0644]
micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns [new file with mode: 0644]
micropeak/MicroPeak.java [new file with mode: 0644]
micropeak/MicroRaw.java [new file with mode: 0644]
micropeak/MicroSave.java [new file with mode: 0644]
micropeak/MicroSerial.java [new file with mode: 0644]
micropeak/MicroStats.java [new file with mode: 0644]
micropeak/MicroStatsTable.java [new file with mode: 0644]
micropeak/MicroUSB.java [new file with mode: 0644]
micropeak/ReadMe-Mac.rtf [new file with mode: 0644]
micropeak/micropeak-fat [new file with mode: 0755]
micropeak/micropeak-windows.nsi [new file with mode: 0644]
src/drivers/ao_cc1120.c
src/megadongle-v0.1/ao_pins.h
src/megametrum-v0.1/ao_pins.h
src/micropeak/Makefile
src/micropeak/ao_async.c
src/micropeak/ao_async.h
src/micropeak/ao_log_micro.c
src/micropeak/ao_log_micro.h
src/micropeak/ao_micropeak.c
src/micropeak/ao_micropeak.h [new file with mode: 0644]

index aaa0ae14c7a4029a3b218f23b58ff38025a604e9..59cddb9f68e4376f9ca2a2b6d9c4dbb096d44a90 100644 (file)
@@ -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
index 47196d6e70b89342ef3f876207bef574bcb941f4..e50b9b5cf05a9a856b1b60fb3af6fe604ac3db39 100644 (file)
@@ -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);
+               }
        }
 }
index 091695154fea3cc01a2a5fecf7b2afebed47e218..2c4b6fa5398c0042de71b6bb9f0525727c26534f 100644 (file)
@@ -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;
index 9f5292346a61e773aee88f2aa22e290fda86590f..546f305537ef162909883f427ae12629c7f8fa94 100644 (file)
@@ -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();
index ca0a5fe32a6f4bf954f49d1436b6f69b3c238107..d4ea305f86859fa3154f00682f4ed2ae3a99da31 100644 (file)
@@ -28,6 +28,10 @@ public class AltosRecordNone extends AltosRecord {
                super.copy(old);
        }
 
+       public AltosRecordNone clone() {
+               return new AltosRecordNone(this);
+       }
+
        public AltosRecordNone() {
                super();
        }
index 9530be31fc4f26579cfb672654a6551b1b08d2bf..f6ed496690c127b521b70ee16420604bce09c708 100644 (file)
@@ -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();
index af63ed17ebbefb79cbaf81f6c3ca51c2da98dabb..4e2daf5ad05f9e4553641a4c117c3c31c7b648d4 100644 (file)
@@ -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";
        }
 
index 218c598ab5d80d6a4e264b86a1a9d25209b5f933..4f59c840c4f6d02acc8e862a27578b9ed4534c0a 100644 (file)
@@ -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 (file)
index 0000000..50a00cd
--- /dev/null
@@ -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);
+}
index 0086bc6555fc617414ddc63b51756012e1efc555..1b03c92557d4bd4dc3d83e979272e3cead0693a8 100644 (file)
@@ -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 \
index 03e7cbeca929c97e4030b76c0346df4bd99f6b3d..222b3c97a1e6cb90b2ef50f899ff8d07fe9eba91 100644 (file)
@@ -17,6 +17,7 @@
 
 package altosui;
 import libaltosJNI.*;
+import org.altusmetrum.altosuilib.*;
 
 public class AltosBTDevice extends altos_bt_device implements AltosDevice {
 
index ae04ac8ce010757c35fb06d91a227b47a66554e9..606c0349fe526ccf41ccfc008ce70c0af1af53d8 100644 (file)
@@ -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>();
index 9a28d72b61e4fb1879b16f9c269b3643a79f0a3a..b7b632a72bc5729438f851cbea98209a253cfc56 100644 (file)
@@ -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;
index 1d024086514e8161d91a46d2170a789940ac37c6..83bf16a78f0d100f4e9552c3ad7f27559d9afb4a 100644 (file)
@@ -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;
index e1ffebb4b95f1129144e1a86c70dadf2915ae78d..1cd61a89fa32b4d5c0006813f747d02c307bdb89 100644 (file)
@@ -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);
index 918748f7d4918ce04d8478f046b2518a22844a14..75101e3d57164f4356a97366fbfd3ae285eec155 100644 (file)
@@ -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;
index 17adb15f6dd74e815e5ba835686614aeabbdfda7..5cdaf5647f3bfe7a4ba000a98c3c07f722b3f8e3 100644 (file)
@@ -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;
index e7b9b81f691cbf085c5d73f50cc379664ac3fe15..794f8103c26e759f2be90a2a1161554a4588e2f7 100644 (file)
@@ -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);
index 532a49fa1cd2b66cf98b3ff3fad930f69a40f7f9..540738439280e2268efb0b03361f497e2ef16c5f 100644 (file)
@@ -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
 {
 
index 95780e2b26a0484272728a0875a39da0aea1e3a8..599ed0512bca0c869d1dc38c48ec3e98d48e8022 100644 (file)
@@ -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
 {
 
index c576b052f71f2db15e9360ba253fbfc9762ad2fa..0e411b03e4dfc7f87fc4641f40f9a86c1bfb18d2 100644 (file)
@@ -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;
        }
 }
index 16b10c3af2b07bf278a59f20952723ef2e8fb57b..482f4c3650d918a16c2651840196387e6c9b4960 100644 (file)
@@ -18,6 +18,7 @@
 package altosui;
 
 import java.io.*;
+import org.altusmetrum.altosuilib.*;
 
 public class AltosDebug extends AltosSerial {
 
diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java
deleted file mode 100644 (file)
index 0aeadae..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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.*;
-
-public class AltosDeviceDialog extends AltosDialog 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() {
-               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;
-       }
-
-       private 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) {
-               super(in_frame, "Device Selection", true);
-
-               product = in_product;
-               frame = in_frame;
-               value = null;
-
-               AltosDevice[]   devices = devices();
-
-               cancel_button = new JButton("Cancel");
-               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);
-               if (devices.length == 0)
-                       select_button.setEnabled(false);
-               getRootPane().setDefaultButton(select_button);
-
-               list = new JList(devices) {
-                               //Subclass JList to workaround bug 4832765, which can cause the
-                               //scroll pane to not let the user easily scroll up to the beginning
-                               //of the list.  An alternative would be to set the unitIncrement
-                               //of the JScrollBar to a fixed value. You wouldn't get the nice
-                               //aligned scrolling, but it should work.
-                               public int getScrollableUnitIncrement(Rectangle visibleRect,
-                                                                     int orientation,
-                                                                     int direction) {
-                                       int row;
-                                       if (orientation == SwingConstants.VERTICAL &&
-                                           direction < 0 && (row = getFirstVisibleIndex()) != -1) {
-                                               Rectangle r = getCellBounds(row, row);
-                                               if ((r.y == visibleRect.y) && (row != 0))  {
-                                                       Point loc = r.getLocation();
-                                                       loc.y--;
-                                                       int prevIndex = locationToIndex(loc);
-                                                       Rectangle prevR = getCellBounds(prevIndex, prevIndex);
-
-                                                       if (prevR == null || prevR.y >= r.y) {
-                                                               return 0;
-                                                       }
-                                                       return prevR.height;
-                                               }
-                                       }
-                                       return super.getScrollableUnitIncrement(
-                                               visibleRect, orientation, direction);
-                               }
-                       };
-
-               list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-               list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
-               list.setVisibleRowCount(-1);
-               list.addMouseListener(new MouseAdapter() {
-                                public void mouseClicked(MouseEvent e) {
-                                        if (e.getClickCount() == 2) {
-                                                select_button.doClick(); //emulate button click
-                                        }
-                                }
-                       });
-               JScrollPane listScroller = new JScrollPane(list);
-               listScroller.setPreferredSize(new Dimension(400, 80));
-               listScroller.setAlignmentX(LEFT_ALIGNMENT);
-
-               //Create a container so that we can add a title around
-               //the scroll pane.  Can't add a title directly to the
-               //scroll pane because its background would be white.
-               //Lay out the label and scroll pane from top to bottom.
-               JPanel listPane = new JPanel();
-               listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
-
-               JLabel label = new JLabel("Select Device");
-               label.setLabelFor(list);
-               listPane.add(label);
-               listPane.add(Box.createRigidArea(new Dimension(0,5)));
-               listPane.add(listScroller);
-               listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
-
-               //Lay out the buttons from left to right.
-               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)));
-               buttonPane.add(select_button);
-
-               //Put everything together, using the content pane's BorderLayout.
-               Container contentPane = getContentPane();
-               contentPane.add(listPane, BorderLayout.CENTER);
-               contentPane.add(buttonPane, BorderLayout.PAGE_END);
-
-               //Initialize values.
-               if (devices != null && devices.length != 0)
-                       list.setSelectedValue(devices[0], true);
-               pack();
-               setLocationRelativeTo(location);
-       }
-
-       //Handle clicks on the Set and Cancel buttons.
-       public void actionPerformed(ActionEvent e) {
-               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);
-       }
-
-       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/AltosDeviceUIDialog.java b/altosui/AltosDeviceUIDialog.java
new file mode 100644 (file)
index 0000000..7ed599a
--- /dev/null
@@ -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/AltosDialog.java b/altosui/AltosDialog.java
deleted file mode 100644 (file)
index c2a9d6e..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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 altosui;
-
-import java.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-
-class AltosDialogListener extends WindowAdapter {
-       public void windowClosing (WindowEvent e) {
-               AltosUIPreferences.unregister_ui_listener((AltosDialog) e.getWindow());
-       }
-}
-
-public class AltosDialog extends JDialog implements AltosUIListener {
-
-       public void ui_changed(String look_and_feel) {
-               SwingUtilities.updateComponentTreeUI(this);
-               this.pack();
-       }
-
-       public AltosDialog() {
-               AltosUIPreferences.register_ui_listener(this);
-               addWindowListener(new AltosDialogListener());
-       }
-
-       public AltosDialog(Frame frame, String label, boolean modal) {
-               super(frame, label, modal);
-               AltosUIPreferences.register_ui_listener(this);
-               addWindowListener(new AltosDialogListener());
-       }
-
-       public AltosDialog(Dialog dialog, String label, boolean modal) {
-               super(dialog, label, modal);
-               AltosUIPreferences.register_ui_listener(this);
-               addWindowListener(new AltosDialogListener());
-       }
-
-       public AltosDialog(Frame frame, boolean modal) {
-               super(frame, modal);
-               AltosUIPreferences.register_ui_listener(this);
-               addWindowListener(new AltosDialogListener());
-       }
-}
index b8de77dabbc93721437defb51cbe24cc545d101e..cc9adb0c4c504f334fdc1f76629b312cca4ebae6 100644 (file)
@@ -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;
 
index 251344e9c44e4cc16c3ad2fddeadf0d07d336d36..8eae5eb841345c0202144e2c15af58d8d177af83 100644 (file)
@@ -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;
index d8b8693d8762f22f4b43232edf440df5c381f661..c08862127a56875b5c6d8e068135b4e197a452e9 100644 (file)
@@ -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;
index 313af70bd90258f600a000a73a0791e58be13c36..7a98ee144cd2c4ee6391317e07862d57cdf86f98 100644 (file)
@@ -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;
index 3ccfa76c3f74334c39f6bd34b5ead0b6799935e3..921207bc4f399bed6ff046ae0ba9b884ab4b1c73 100644 (file)
@@ -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;
index 43df705e96add4f6ff98777d586567c0db1dec8e..e2dc06bd97842182fc35bd3399258f22560a3bd2 100644 (file)
@@ -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/AltosFontListener.java b/altosui/AltosFontListener.java
deleted file mode 100644 (file)
index 0dda0f2..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 altosui;
-
-public interface AltosFontListener {
-       void font_size_changed(int font_size);
-}
diff --git a/altosui/AltosFrame.java b/altosui/AltosFrame.java
deleted file mode 100644 (file)
index 731a29b..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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 altosui;
-
-import java.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import java.util.*;
-
-class AltosFrameListener extends WindowAdapter {
-       public void windowClosing (WindowEvent e) {
-               AltosUIPreferences.unregister_ui_listener((AltosFrame) e.getWindow());
-       }
-}
-
-public class AltosFrame extends JFrame implements AltosUIListener {
-
-       public void ui_changed(String look_and_feel) {
-               SwingUtilities.updateComponentTreeUI(this);
-               this.pack();
-       }
-
-       static final String[] icon_names = {
-               "/altus-metrum-16.png",
-               "/altus-metrum-32.png",
-               "/altus-metrum-48.png",
-               "/altus-metrum-64.png",
-               "/altus-metrum-128.png",
-               "/altus-metrum-256.png"
-       };
-
-       public void set_icon() {
-               ArrayList<Image> icons = new ArrayList<Image>();
-               
-               for (int i = 0; i < icon_names.length; i++) {
-                       java.net.URL imgURL = AltosUI.class.getResource(icon_names[i]);
-                       if (imgURL != null)
-                               icons.add(new ImageIcon(imgURL).getImage());
-               }
-
-               setIconImages(icons);
-       }
-                       
-       public AltosFrame() {
-               AltosUIPreferences.register_ui_listener(this);
-               addWindowListener(new AltosFrameListener());
-               set_icon();
-       }
-
-       public AltosFrame(String name) {
-               super(name);
-               AltosUIPreferences.register_ui_listener(this);
-               addWindowListener(new AltosFrameListener());
-               set_icon();
-       }
-}
index b7c2e92e74c07ea3cad46cba633e71f88fe5bc71..d6891ffa04d33e7bb719b4cbd449700b582deddd 100644 (file)
@@ -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;
 
index 6f69600997c6ab0d0bac505c01ecc85b5254f30e..1b3dd5470a0e9b4ec951721e2ace1d43c31d004e 100644 (file)
@@ -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;
index ec331259c73531d69946bdd1e00fe341e041bde5..c1378eb948f5cd0300cf86e1074782372b7ce7b7 100644 (file)
@@ -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);
index de19221e9f0c117a29c7899ca07af2c0eba8eade..0bad80aac459d16ada7b64207bf062e4e36eddc7 100644 (file)
@@ -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;
index 39b986c0a129f0dde62a7533be54027bd9bb3ea9..7e7ed010af487dc5dce5ebac84f06af076adce65 100644 (file)
@@ -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);
index d4a5ef6dac33d65aee1407d0b905173d91ff9aed..5fc786e2f1247402aaed4cf60620abda4efbd89e 100644 (file)
@@ -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;
index 2a6e140ac34f786e5f363b6a3c73ab949847c677..14b523108b2900795576a953a3b8b4fa2db23e6f 100644 (file)
@@ -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 {
index 771fdd5dfe14326ae5a30b29284a676eac024f13..78d862d03645ccd7eae99eb1acfd1bbc17d19682 100644 (file)
@@ -26,6 +26,7 @@ import java.util.*;
 import java.awt.*;
 import javax.swing.*;
 import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
 
 import libaltosJNI.*;
 
index 7380f331b2d561b46b39943554735461af57acc0..932a3684ee0eb5709eb8c05ef59d6822e094f21f 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 package altosui;
+import org.altusmetrum.altosuilib.*;
 
 public class AltosSerialInUseException extends Exception {
        public AltosDevice      device;
index 33849c660bb1fa12124cd0bc6f89540883defa0c..f4dcc9033f4904dae8ba4c15a66e54bb83b10c58 100644 (file)
@@ -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;
 
index dcc0de600817aab22666705581ffe42afa8de996..70142a93b5d3beeb6d7e0a8c75b8308e31800273 100644 (file)
@@ -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/AltosUIListener.java b/altosui/AltosUIListener.java
deleted file mode 100644 (file)
index 7ee62af..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 altosui;
-
-public interface AltosUIListener {
-       public void ui_changed(String look_and_feel);
-}
index f6ee7e06910d11f6a90edffdace729bca9206979..9c56d0318e35eb26372e7554e7d27086640d3f52 100644 (file)
@@ -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/AltosUSBDevice.java b/altosui/AltosUSBDevice.java
deleted file mode 100644 (file)
index 3af7a7f..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package altosui;
-import java.util.*;
-import libaltosJNI.*;
-
-public class AltosUSBDevice  extends altos_device implements AltosDevice {
-
-       public String toString() {
-               String  name = getName();
-               if (name == null)
-                       name = "Altus Metrum";
-               return String.format("%-20.20s %4d %s",
-                                    name, getSerial(), getPath());
-       }
-
-       public String toShortString() {
-               String  name = getName();
-               if (name == null)
-                       name = "Altus Metrum";
-               return String.format("%s %d %s",
-                                    name, getSerial(), 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 isAltusMetrum() {
-               if (getVendor() != Altos.vendor_altusmetrum)
-                       return false;
-               if (getProduct() < Altos.product_altusmetrum_min)
-                       return false;
-               if (getProduct() > Altos.product_altusmetrum_max)
-                       return false;
-               return true;
-       }
-
-       public boolean matchProduct(int want_product) {
-
-               if (!isAltusMetrum())
-                       return false;
-
-               if (want_product == Altos.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 == Altos.product_altimeter)
-                       return matchProduct(Altos.product_telemetrum) ||
-                               matchProduct(Altos.product_megametrum);
-
-               int have_product = getProduct();
-
-               if (have_product == Altos.product_altusmetrum)  /* old devices match any request */
-                       return true;
-
-               if (want_product == have_product)
-                       return true;
-
-               return false;
-       }
-
-       static java.util.List<AltosDevice> list(int product) {
-               if (!Altos.load_library())
-                       return null;
-
-               SWIGTYPE_p_altos_list list = libaltos.altos_list_start();
-
-               ArrayList<AltosDevice> device_list = new ArrayList<AltosDevice>();
-               if (list != null) {
-                       for (;;) {
-                               AltosUSBDevice device = new AltosUSBDevice();
-                               if (libaltos.altos_list_next(list, device) == 0)
-                                       break;
-                               if (device.matchProduct(product))
-                                       device_list.add(device);
-                       }
-                       libaltos.altos_list_finish(list);
-               }
-
-               return device_list;
-       }
-}
\ No newline at end of file
diff --git a/altosui/AltosVersion.java.in b/altosui/AltosVersion.java.in
deleted file mode 100644 (file)
index b0b3c0c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 altosui;
-
-public class AltosVersion {
-       public final static String version = "@VERSION@";
-}
index 306a396e6fe5e21ded11331bcfc7ae6fc9ac2266..7d000f7b9ba7c270ddcd4f55b71413a40ce87de0 100644 (file)
@@ -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 (file)
index 0000000..8a95262
--- /dev/null
@@ -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/.gitignore b/altosui/libaltos/.gitignore
deleted file mode 100644 (file)
index c490e6f..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-*.so
-*.lo
-*.la
-*.java
-*.class
-.libs/
-classlibaltos.stamp
-libaltos_wrap.c
-libaltosJNI
-cjnitest
-libaltos.swig
-swig_bindings/
diff --git a/altosui/libaltos/Makefile-standalone b/altosui/libaltos/Makefile-standalone
deleted file mode 100644 (file)
index 4e43805..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-OS:=$(shell uname)
-
-#
-# Linux
-#
-ifeq ($(OS),Linux)
-
-JAVA_CFLAGS=-I/usr/lib/jvm/java-6-openjdk/include
-
-OS_LIB_CFLAGS=-DLINUX -DPOSIX_TTY $(JAVA_CFLAGS)
-
-OS_APP_CFLAGS=$(OS_LIB_CFLAGS)
-
-OS_LDFLAGS=
-
-LIBNAME=libaltos.so
-EXEEXT=
-endif
-
-#
-# Darwin (Mac OS X)
-#
-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
-OS_APP_CFLAGS=$(OS_LIB_CFLAGS)
-
-OS_LDFLAGS =\
-       -framework IOKit -framework CoreFoundation
-
-LIBNAME=libaltos.dylib
-EXEEXT=
-
-endif
-
-#
-# Windows
-#
-ifneq (,$(findstring MINGW,$(OS)))
-
-CC=gcc
-
-OS_LIB_CFLAGS = -DWINDOWS -mconsole -DBUILD_DLL
-OS_APP_CFLAGS = -DWINDOWS -mconsole
-
-OS_LDFLAGS = -lgdi32 -luser32 -lcfgmgr32 -lsetupapi -lole32 \
-       -ladvapi32 -lcomctl32 -mconsole -Wl,--add-stdcall-alias
-
-LIBNAME=altos.dll
-
-EXEEXT=.exe
-
-endif
-
-.SUFFIXES: .java .class
-
-CLASSPATH=".:jnitest/*:libaltosJNI:/usr/share/java/*"
-
-SWIG_DIR=swig_bindings/java
-SWIG_FILE=$(SWIG_DIR)/libaltos.swig
-SWIG_WRAP=$(SWIG_DIR)/libaltos_wrap.c
-
-JNI_DIR=libaltosJNI
-JNI_FILE=$(JNI_DIR)/libaltosJNI.java
-JNI_SRCS=$(JNI_FILE) \
-       $(JNI_DIR)/SWIGTYPE_p_altos_file.java \
-       $(JNI_DIR)/SWIGTYPE_p_altos_list.java \
-       $(JNI_DIR)/altos_device.java \
-       $(JNI_DIR)/libaltos.java
-
-JAVAFILES=\
-       $(JNI_SRCS)
-
-CLASSFILES = $(JAVAFILES:%.java=%.class)
-
-JAVAFLAGS=-Xlint:unchecked
-
-CJNITEST=cjnitest$(EXEEXT)
-
-all: $(LIBNAME) $(CJNITEST) $(CLASSFILES)
-
-.java.class:
-       javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
-
-CFLAGS=$(OS_LIB_CFLAGS) -O -I.
-
-LDFLAGS=$(OS_LDFLAGS)
-
-HEADERS=libaltos.h
-SRCS = libaltos.c $(SWIG_WRAP)
-OBJS = $(SRCS:%.c=%.o)
-LIBS = $(DARWIN_LIBS)
-
-$(CJNITEST): cjnitest.c $(LIBNAME)
-       $(CC) -o $@ $(OS_APP_CFLAGS) cjnitest.c $(LIBNAME) $(LIBS) $(LDFLAGS)
-
-$(LIBNAME): $(OBJS)
-       $(CC) -shared $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
-
-clean:
-       rm -f $(CLASSFILES) $(OBJS) $(LIBNAME) $(CJNITEST) cjnitest.o
-       rm -rf swig_bindings libaltosJNI
-
-distclean:     clean
-
-$(JNI_FILE): libaltos.i0 $(HEADERS)
-       mkdir -p $(SWIG_DIR)
-       mkdir -p libaltosJNI
-       sed 's;//%;%;' libaltos.i0 $(HEADERS) > $(SWIG_FILE)
-       swig -java -package libaltosJNI $(SWIG_FILE)
-       cp swig_bindings/java/*.java libaltosJNI
-
-$(SWIG_WRAP): $(JNI_FILE)
-
-ifeq ($(OS),Linux)
-install:       $(LIBNAME)
-       install -c $(LIBNAME) $(DESTDIR)/usr/lib/altos/$(LIBNAME)
-
-endif
-
-.NOTPARALLEL:
diff --git a/altosui/libaltos/Makefile.am b/altosui/libaltos/Makefile.am
deleted file mode 100644 (file)
index b5ab1dd..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-JAVAC=javac
-AM_CFLAGS=-DLINUX -DPOSIX_TTY -I$(JVM_INCLUDE)
-AM_JAVACFLAGS=-encoding UTF-8
-
-altoslibdir=$(libdir)/altos
-
-altoslib_LTLIBRARIES=libaltos.la
-
-libaltos_la_LDFLAGS = -version-info 1:0:1
-
-libaltos_la_SOURCES=\
-       libaltos.c \
-       libaltos_wrap.c
-
-noinst_PROGRAMS=cjnitest
-
-cjnitest_LDADD=libaltos.la
-
-LIBS=-lbluetooth
-
-HFILES=libaltos.h
-
-SWIG_FILE=libaltos.swig
-
-CLASSDIR=libaltosJNI
-
-$(SWIG_FILE): libaltos.i0 $(HFILES)
-       sed 's;//%;%;' libaltos.i0 $(HFILES) > $(SWIG_FILE)
-
-all-local: classlibaltos.stamp
-
-libaltos_wrap.c: classlibaltos.stamp
-
-classlibaltos.stamp: $(SWIG_FILE)
-       swig -java -package libaltosJNI $(SWIG_FILE)
-       mkdir -p libaltosJNI
-       $(JAVAC) -d . $(AM_JAVACFLAGS) $(JAVACFLAGS) *.java && \
-       touch classlibaltos.stamp
-
-MINGCC32=i686-w64-mingw32-gcc
-MINGCC64=x86_64-w64-mingw32-gcc
-MINGFLAGS=-Wall -DWINDOWS -DBUILD_DLL -I$(JVM_INCLUDE)
-MINGLIBS=-lsetupapi
-
-fat: altos.dll altos64.dll
-
-altos.dll: $(libaltos_la_SOURCES)
-       $(MINGCC32) -o $@ $(MINGFLAGS) -shared $(libaltos_la_SOURCES) $(MINGLIBS)
-
-altos64.dll: $(libaltos_la_SOURCES)
-       $(MINGCC64) -o $@ $(MINGFLAGS) -shared $(libaltos_la_SOURCES) $(MINGLIBS)
-
-clean-local:
-       -rm -rf libaltosJNI *.class *.java classlibaltos.stamp $(SWIG_FILE) libaltos_wrap.c altos.dll altos64.dll
diff --git a/altosui/libaltos/cjnitest.c b/altosui/libaltos/cjnitest.c
deleted file mode 100644 (file)
index f0fe78f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <stdio.h>
-#include "libaltos.h"
-
-static void
-altos_puts(struct altos_file *file, char *string)
-{
-       char    c;
-
-       while ((c = *string++))
-               altos_putchar(file, c);
-}
-
-main ()
-{
-       struct altos_device     device;
-       struct altos_list       *list;
-       struct altos_bt_device  bt_device;
-       struct altos_bt_list    *bt_list;
-
-       altos_init();
-       list = altos_list_start();
-       while (altos_list_next(list, &device)) {
-               struct altos_file       *file;
-               int                     c;
-
-               printf ("%04x:%04x %-20s %4d %s\n", device.vendor, device.product,
-                       device.name, device.serial, device.path);
-
-               file = altos_open(&device);
-               if (!file) {
-                       printf("altos_open failed\n");
-                       continue;
-               }
-               altos_puts(file,"v\nc s\n");
-               altos_flush(file);
-               while ((c = altos_getchar(file, 100)) >= 0) {
-                       putchar (c);
-               }
-               if (c != LIBALTOS_TIMEOUT)
-                       printf ("getchar returns %d\n", c);
-               altos_close(file);
-       }
-       altos_list_finish(list);
-#if HAS_BLUETOOTH
-       bt_list = altos_bt_list_start(8);
-       while (altos_bt_list_next(bt_list, &bt_device)) {
-               printf ("%s %s\n", bt_device.name, bt_device.addr);
-               if (strncmp(bt_device.name, "TeleBT", 6) == 0) {
-                       struct altos_file       *file;
-
-                       int                     c;
-                       file = altos_bt_open(&bt_device);
-                       if (!file) {
-                               printf("altos_bt_open failed\n");
-                               continue;
-                       }
-                       altos_puts(file,"v\nc s\n");
-                       altos_flush(file);
-                       while ((c = altos_getchar(file, 100)) >= 0) {
-                               putchar(c);
-                       }
-                       if (c != LIBALTOS_TIMEOUT)
-                               printf("getchar returns %d\n", c);
-                       altos_close(file);
-               }
-       }
-       altos_bt_list_finish(bt_list);
-#endif
-       altos_fini();
-       return 0;
-}
diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c
deleted file mode 100644 (file)
index ab6ca87..0000000
+++ /dev/null
@@ -1,1311 +0,0 @@
-/*
- * 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.
- */
-
-#include "libaltos.h"
-#include <stdio.h>
-#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
-
-PUBLIC int
-altos_init(void)
-{
-       return LIBALTOS_SUCCESS;
-}
-
-PUBLIC void
-altos_fini(void)
-{
-}
-
-static struct altos_error last_error;
-
-static void
-altos_set_last_error(int code, char *string)
-{
-       last_error.code = code;
-       strncpy(last_error.string, string, sizeof (last_error.string) -1);
-       last_error.string[sizeof(last_error.string)-1] = '\0';
-}
-
-PUBLIC void
-altos_get_last_error(struct altos_error *error)
-{
-       *error = last_error;
-}
-
-#ifdef DARWIN
-
-#undef USE_POLL
-
-/* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
-static char *
-altos_strndup (const char *s, size_t n)
-{
-    size_t len = strlen (s);
-    char *ret;
-
-    if (len <= n)
-       return strdup (s);
-    ret = malloc(n + 1);
-    strncpy(ret, s, n);
-    ret[n] = '\0';
-    return ret;
-}
-
-#else
-#define altos_strndup strndup
-#endif
-
-#ifdef POSIX_TTY
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <termios.h>
-#include <errno.h>
-
-#define USB_BUF_SIZE   64
-
-struct altos_file {
-       int                             fd;
-#ifdef USE_POLL
-       int                             pipe[2];
-#else
-       int                             out_fd;
-#endif
-       unsigned char                   out_data[USB_BUF_SIZE];
-       int                             out_used;
-       unsigned char                   in_data[USB_BUF_SIZE];
-       int                             in_used;
-       int                             in_read;
-};
-
-static void
-altos_set_last_posix_error(void)
-{
-       altos_set_last_error(errno, strerror(errno));
-}
-
-PUBLIC struct altos_file *
-altos_open(struct altos_device *device)
-{
-       struct altos_file       *file = calloc (sizeof (struct altos_file), 1);
-       int                     ret;
-       struct termios          term;
-
-       if (!file) {
-               altos_set_last_posix_error();
-               return NULL;
-       }
-
-//     altos_set_last_error(12, "yeah yeah, failed again");
-//     free(file);
-//     return NULL;
-
-       file->fd = open(device->path, O_RDWR | O_NOCTTY);
-       if (file->fd < 0) {
-               altos_set_last_posix_error();
-               free(file);
-               return NULL;
-       }
-#ifdef USE_POLL
-       pipe(file->pipe);
-#else
-       file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
-       if (file->out_fd < 0) {
-               altos_set_last_posix_error();
-               close(file->fd);
-               free(file);
-               return NULL;
-       }
-#endif
-       ret = tcgetattr(file->fd, &term);
-       if (ret < 0) {
-               altos_set_last_posix_error();
-               close(file->fd);
-#ifndef USE_POLL
-               close(file->out_fd);
-#endif
-               free(file);
-               return NULL;
-       }
-       cfmakeraw(&term);
-#ifdef USE_POLL
-       term.c_cc[VMIN] = 1;
-       term.c_cc[VTIME] = 0;
-#else
-       term.c_cc[VMIN] = 0;
-       term.c_cc[VTIME] = 1;
-#endif
-       ret = tcsetattr(file->fd, TCSAFLUSH, &term);
-       if (ret < 0) {
-               altos_set_last_posix_error();
-               close(file->fd);
-#ifndef USE_POLL
-               close(file->out_fd);
-#endif
-               free(file);
-               return NULL;
-       }
-       return file;
-}
-
-PUBLIC void
-altos_close(struct altos_file *file)
-{
-       if (file->fd != -1) {
-               int     fd = file->fd;
-               file->fd = -1;
-#ifdef USE_POLL
-               write(file->pipe[1], "\r", 1);
-#else
-               close(file->out_fd);
-               file->out_fd = -1;
-#endif
-               close(fd);
-       }
-}
-
-PUBLIC void
-altos_free(struct altos_file *file)
-{
-       altos_close(file);
-       free(file);
-}
-
-PUBLIC int
-altos_flush(struct altos_file *file)
-{
-       if (file->out_used && 0) {
-               printf ("flush \"");
-               fwrite(file->out_data, 1, file->out_used, stdout);
-               printf ("\"\n");
-       }
-       while (file->out_used) {
-               int     ret;
-
-               if (file->fd < 0)
-                       return -EBADF;
-#ifdef USE_POLL
-               ret = write (file->fd, file->out_data, file->out_used);
-#else
-               ret = write (file->out_fd, file->out_data, file->out_used);
-#endif
-               if (ret < 0) {
-                       altos_set_last_posix_error();
-                       return -last_error.code;
-               }
-               if (ret) {
-                       memmove(file->out_data, file->out_data + ret,
-                               file->out_used - ret);
-                       file->out_used -= ret;
-               }
-       }
-       return 0;
-}
-
-PUBLIC int
-altos_putchar(struct altos_file *file, char c)
-{
-       int     ret;
-
-       if (file->out_used == USB_BUF_SIZE) {
-               ret = altos_flush(file);
-               if (ret) {
-                       return ret;
-               }
-       }
-       file->out_data[file->out_used++] = c;
-       ret = 0;
-       if (file->out_used == USB_BUF_SIZE)
-               ret = altos_flush(file);
-       return ret;
-}
-
-#ifdef USE_POLL
-#include <poll.h>
-#endif
-
-static int
-altos_fill(struct altos_file *file, int timeout)
-{
-       int             ret;
-#ifdef USE_POLL
-       struct pollfd   fd[2];
-#endif
-
-       if (timeout == 0)
-               timeout = -1;
-       while (file->in_read == file->in_used) {
-               if (file->fd < 0)
-                       return LIBALTOS_ERROR;
-#ifdef USE_POLL
-               fd[0].fd = file->fd;
-               fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
-               fd[1].fd = file->pipe[0];
-               fd[1].events = POLLIN;
-               ret = poll(fd, 2, timeout);
-               if (ret < 0) {
-                       altos_set_last_posix_error();
-                       return LIBALTOS_ERROR;
-               }
-               if (ret == 0)
-                       return LIBALTOS_TIMEOUT;
-
-               if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
-                       return LIBALTOS_ERROR;
-               if (fd[0].revents & POLLIN)
-#endif
-               {
-                       ret = read(file->fd, file->in_data, USB_BUF_SIZE);
-                       if (ret < 0) {
-                               altos_set_last_posix_error();
-                               return LIBALTOS_ERROR;
-                       }
-                       file->in_read = 0;
-                       file->in_used = ret;
-#ifndef USE_POLL
-                       if (ret == 0 && timeout > 0)
-                               return LIBALTOS_TIMEOUT;
-#endif
-               }
-       }
-       if (file->in_used && 0) {
-               printf ("fill \"");
-               fwrite(file->in_data, 1, file->in_used, stdout);
-               printf ("\"\n");
-       }
-       return 0;
-}
-
-PUBLIC int
-altos_getchar(struct altos_file *file, int timeout)
-{
-       int     ret;
-       while (file->in_read == file->in_used) {
-               if (file->fd < 0)
-                       return LIBALTOS_ERROR;
-               ret = altos_fill(file, timeout);
-               if (ret)
-                       return ret;
-       }
-       return file->in_data[file->in_read++];
-}
-
-#endif /* POSIX_TTY */
-
-/*
- * Scan for Altus Metrum devices by looking through /sys
- */
-
-#ifdef LINUX
-
-#define _GNU_SOURCE
-#include <ctype.h>
-#include <dirent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/rfcomm.h>
-
-static char *
-cc_fullname (char *dir, char *file)
-{
-       char    *new;
-       int     dlen = strlen (dir);
-       int     flen = strlen (file);
-       int     slen = 0;
-
-       if (dir[dlen-1] != '/')
-               slen = 1;
-       new = malloc (dlen + slen + flen + 1);
-       if (!new)
-               return 0;
-       strcpy(new, dir);
-       if (slen)
-               strcat (new, "/");
-       strcat(new, file);
-       return new;
-}
-
-static char *
-cc_basename(char *file)
-{
-       char *b;
-
-       b = strrchr(file, '/');
-       if (!b)
-               return file;
-       return b + 1;
-}
-
-static char *
-load_string(char *dir, char *file)
-{
-       char    *full = cc_fullname(dir, file);
-       char    line[4096];
-       char    *r;
-       FILE    *f;
-       int     rlen;
-
-       f = fopen(full, "r");
-       free(full);
-       if (!f)
-               return NULL;
-       r = fgets(line, sizeof (line), f);
-       fclose(f);
-       if (!r)
-               return NULL;
-       rlen = strlen(r);
-       if (r[rlen-1] == '\n')
-               r[rlen-1] = '\0';
-       return strdup(r);
-}
-
-static int
-load_hex(char *dir, char *file)
-{
-       char    *line;
-       char    *end;
-       long    i;
-
-       line = load_string(dir, file);
-       if (!line)
-               return -1;
-       i = strtol(line, &end, 16);
-       free(line);
-       if (end == line)
-               return -1;
-       return i;
-}
-
-static int
-load_dec(char *dir, char *file)
-{
-       char    *line;
-       char    *end;
-       long    i;
-
-       line = load_string(dir, file);
-       if (!line)
-               return -1;
-       i = strtol(line, &end, 10);
-       free(line);
-       if (end == line)
-               return -1;
-       return i;
-}
-
-static int
-dir_filter_tty_colon(const struct dirent *d)
-{
-       return strncmp(d->d_name, "tty:", 4) == 0;
-}
-
-static int
-dir_filter_tty(const struct dirent *d)
-{
-       return strncmp(d->d_name, "tty", 3) == 0;
-}
-
-struct altos_usbdev {
-       char    *sys;
-       char    *tty;
-       char    *manufacturer;
-       char    *product_name;
-       int     serial; /* AltOS always uses simple integer serial numbers */
-       int     idProduct;
-       int     idVendor;
-};
-
-static char *
-usb_tty(char *sys)
-{
-       char *base;
-       int num_configs;
-       int config;
-       struct dirent **namelist;
-       int interface;
-       int num_interfaces;
-       char endpoint_base[20];
-       char *endpoint_full;
-       char *tty_dir;
-       int ntty;
-       char *tty;
-
-       base = cc_basename(sys);
-       num_configs = load_hex(sys, "bNumConfigurations");
-       num_interfaces = load_hex(sys, "bNumInterfaces");
-       for (config = 1; config <= num_configs; config++) {
-               for (interface = 0; interface < num_interfaces; interface++) {
-                       sprintf(endpoint_base, "%s:%d.%d",
-                               base, config, interface);
-                       endpoint_full = cc_fullname(sys, endpoint_base);
-
-                       /* Check for tty:ttyACMx style names
-                        */
-                       ntty = scandir(endpoint_full, &namelist,
-                                      dir_filter_tty_colon,
-                                      alphasort);
-                       if (ntty > 0) {
-                               free(endpoint_full);
-                               tty = cc_fullname("/dev", namelist[0]->d_name + 4);
-                               free(namelist);
-                               return tty;
-                       }
-
-                       /* 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(namelist);
-                               return tty;
-                       }
-               }
-       }
-       return NULL;
-}
-
-static struct altos_usbdev *
-usb_scan_device(char *sys)
-{
-       struct altos_usbdev *usbdev;
-
-       usbdev = calloc(1, sizeof (struct altos_usbdev));
-       if (!usbdev)
-               return NULL;
-       usbdev->sys = strdup(sys);
-       usbdev->manufacturer = load_string(sys, "manufacturer");
-       usbdev->product_name = load_string(sys, "product");
-       usbdev->serial = load_dec(sys, "serial");
-       usbdev->idProduct = load_hex(sys, "idProduct");
-       usbdev->idVendor = load_hex(sys, "idVendor");
-       usbdev->tty = usb_tty(sys);
-       return usbdev;
-}
-
-static void
-usbdev_free(struct altos_usbdev *usbdev)
-{
-       free(usbdev->sys);
-       free(usbdev->manufacturer);
-       free(usbdev->product_name);
-       /* this can get used as a return value */
-       if (usbdev->tty)
-               free(usbdev->tty);
-       free(usbdev);
-}
-
-#define USB_DEVICES    "/sys/bus/usb/devices"
-
-static int
-dir_filter_dev(const struct dirent *d)
-{
-       const char      *n = d->d_name;
-       char    c;
-
-       while ((c = *n++)) {
-               if (isdigit(c))
-                       continue;
-               if (c == '-')
-                       continue;
-               if (c == '.' && n != d->d_name + 1)
-                       continue;
-               return 0;
-       }
-       return 1;
-}
-
-struct altos_list {
-       struct altos_usbdev     **dev;
-       int                     current;
-       int                     ndev;
-};
-
-struct altos_list *
-altos_list_start(void)
-{
-       int                     e;
-       struct dirent           **ents;
-       char                    *dir;
-       struct altos_usbdev     *dev;
-       struct altos_list       *devs;
-       int                     n;
-
-       devs = calloc(1, sizeof (struct altos_list));
-       if (!devs)
-               return NULL;
-
-       n = scandir (USB_DEVICES, &ents,
-                    dir_filter_dev,
-                    alphasort);
-       if (!n)
-               return 0;
-       for (e = 0; e < n; e++) {
-               dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
-               dev = usb_scan_device(dir);
-               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;
-               }
-       }
-       free(ents);
-       devs->current = 0;
-       return devs;
-}
-
-int
-altos_list_next(struct altos_list *list, struct altos_device *device)
-{
-       struct altos_usbdev *dev;
-       if (list->current >= list->ndev)
-               return 0;
-       dev = list->dev[list->current];
-       strcpy(device->name, dev->product_name);
-       device->vendor = dev->idVendor;
-       device->product = dev->idProduct;
-       strcpy(device->path, dev->tty);
-       device->serial = dev->serial;
-       list->current++;
-       return 1;
-}
-
-void
-altos_list_finish(struct altos_list *usbdevs)
-{
-       int     i;
-
-       if (!usbdevs)
-               return;
-       for (i = 0; i < usbdevs->ndev; i++)
-               usbdev_free(usbdevs->dev[i]);
-       free(usbdevs);
-}
-
-struct altos_bt_list {
-       inquiry_info    *ii;
-       int             sock;
-       int             dev_id;
-       int             rsp;
-       int             num_rsp;
-};
-
-#define INQUIRY_MAX_RSP        255
-
-struct altos_bt_list *
-altos_bt_list_start(int inquiry_time)
-{
-       struct altos_bt_list    *bt_list;
-
-       bt_list = calloc(1, sizeof (struct altos_bt_list));
-       if (!bt_list)
-               goto no_bt_list;
-
-       bt_list->ii = calloc(INQUIRY_MAX_RSP, sizeof (inquiry_info));
-       if (!bt_list->ii)
-               goto no_ii;
-       bt_list->dev_id = hci_get_route(NULL);
-       if (bt_list->dev_id < 0)
-               goto no_dev_id;
-
-       bt_list->sock = hci_open_dev(bt_list->dev_id);
-       if (bt_list->sock < 0)
-               goto no_sock;
-
-       bt_list->num_rsp = hci_inquiry(bt_list->dev_id,
-                                      inquiry_time,
-                                      INQUIRY_MAX_RSP,
-                                      NULL,
-                                      &bt_list->ii,
-                                      IREQ_CACHE_FLUSH);
-       if (bt_list->num_rsp < 0)
-               goto no_rsp;
-
-       bt_list->rsp = 0;
-       return bt_list;
-
-no_rsp:
-       close(bt_list->sock);
-no_sock:
-no_dev_id:
-       free(bt_list->ii);
-no_ii:
-       free(bt_list);
-no_bt_list:
-       return NULL;
-}
-
-int
-altos_bt_list_next(struct altos_bt_list *bt_list,
-                  struct altos_bt_device *device)
-{
-       inquiry_info    *ii;
-
-       if (bt_list->rsp >= bt_list->num_rsp)
-               return 0;
-
-       ii = &bt_list->ii[bt_list->rsp];
-       ba2str(&ii->bdaddr, device->addr);
-       memset(&device->name, '\0', sizeof (device->name));
-       if (hci_read_remote_name(bt_list->sock, &ii->bdaddr,
-                                sizeof (device->name),
-                                device->name, 0) < 0) {
-               strcpy(device->name, "[unknown]");
-       }
-       bt_list->rsp++;
-       return 1;
-}
-
-void
-altos_bt_list_finish(struct altos_bt_list *bt_list)
-{
-       close(bt_list->sock);
-       free(bt_list->ii);
-       free(bt_list);
-}
-
-void
-altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
-{
-       strncpy(device->name, name, sizeof (device->name));
-       device->name[sizeof(device->name)-1] = '\0';
-       strncpy(device->addr, addr, sizeof (device->addr));
-       device->addr[sizeof(device->addr)-1] = '\0';
-}
-
-struct altos_file *
-altos_bt_open(struct altos_bt_device *device)
-{
-       struct sockaddr_rc addr = { 0 };
-       int     s, status;
-       struct altos_file *file;
-
-       file = calloc(1, sizeof (struct altos_file));
-       if (!file)
-               goto no_file;
-       file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-       if (file->fd < 0) {
-               altos_set_last_posix_error();
-               goto no_sock;
-       }
-
-       addr.rc_family = AF_BLUETOOTH;
-       addr.rc_channel = 1;
-       str2ba(device->addr, &addr.rc_bdaddr);
-
-       status = connect(file->fd,
-                        (struct sockaddr *)&addr,
-                        sizeof(addr));
-       if (status < 0) {
-               altos_set_last_posix_error();
-               goto no_link;
-       }
-       sleep(1);
-
-#ifdef USE_POLL
-       pipe(file->pipe);
-#else
-       file->out_fd = dup(file->fd);
-#endif
-       return file;
-no_link:
-       close(s);
-no_sock:
-       free(file);
-no_file:
-       return NULL;
-}
-
-#endif
-
-#ifdef DARWIN
-
-#include <IOKitLib.h>
-#include <IOKit/usb/USBspec.h>
-#include <sys/param.h>
-#include <paths.h>
-#include <CFNumber.h>
-#include <IOBSD.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-struct altos_list {
-       io_iterator_t iterator;
-};
-
-static int
-get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
-{
-       CFTypeRef entry_as_string;
-       Boolean got_string;
-
-       entry_as_string = IORegistryEntrySearchCFProperty (object,
-                                                          kIOServicePlane,
-                                                          entry,
-                                                          kCFAllocatorDefault,
-                                                          kIORegistryIterateRecursively);
-       if (entry_as_string) {
-               got_string = CFStringGetCString(entry_as_string,
-                                               result, result_len,
-                                               kCFStringEncodingASCII);
-    
-               CFRelease(entry_as_string);
-               if (got_string)
-                       return 1;
-       }
-       return 0;
-}
-
-static int
-get_number(io_object_t object, CFStringRef entry, int *result)
-{
-       CFTypeRef entry_as_number;
-       Boolean got_number;
-       
-       entry_as_number = IORegistryEntrySearchCFProperty (object,
-                                                          kIOServicePlane,
-                                                          entry,
-                                                          kCFAllocatorDefault,
-                                                          kIORegistryIterateRecursively);
-       if (entry_as_number) {
-               got_number = CFNumberGetValue(entry_as_number,
-                                             kCFNumberIntType,
-                                             result);
-               if (got_number)
-                       return 1;
-       }
-       return 0;
-}
-
-PUBLIC struct altos_list *
-altos_list_start(void)
-{
-       struct altos_list *list = calloc (sizeof (struct altos_list), 1);
-       CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
-       io_iterator_t tdIterator;
-       io_object_t tdObject;
-       kern_return_t ret;
-       int i;
-
-       ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
-       if (ret != kIOReturnSuccess)
-               return NULL;
-       return list;
-}
-
-PUBLIC int
-altos_list_next(struct altos_list *list, struct altos_device *device)
-{
-       io_object_t object;
-       char serial_string[128];
-
-       for (;;) {
-               object = IOIteratorNext(list->iterator);
-               if (!object)
-                       return 0;
-  
-               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 (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))) {
-                       device->serial = atoi(serial_string);
-                       return 1;
-               }
-       }
-}
-
-PUBLIC void
-altos_list_finish(struct altos_list *list)
-{
-       IOObjectRelease (list->iterator);
-       free(list);
-}
-
-struct altos_bt_list {
-       int             sock;
-       int             dev_id;
-       int             rsp;
-       int             num_rsp;
-};
-
-#define INQUIRY_MAX_RSP        255
-
-struct altos_bt_list *
-altos_bt_list_start(int inquiry_time)
-{
-       return NULL;
-}
-
-int
-altos_bt_list_next(struct altos_bt_list *bt_list,
-                  struct altos_bt_device *device)
-{
-       return 0;
-}
-
-void
-altos_bt_list_finish(struct altos_bt_list *bt_list)
-{
-}
-
-void
-altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
-{
-       strncpy(device->name, name, sizeof (device->name));
-       device->name[sizeof(device->name)-1] = '\0';
-       strncpy(device->addr, addr, sizeof (device->addr));
-       device->addr[sizeof(device->addr)-1] = '\0';
-}
-
-struct altos_file *
-altos_bt_open(struct altos_bt_device *device)
-{
-       return NULL;
-}
-
-#endif
-
-
-#ifdef WINDOWS
-
-#include <stdlib.h>
-#include <windows.h>
-#include <setupapi.h>
-
-struct altos_list {
-       HDEVINFO        dev_info;
-       int             index;
-};
-
-#define USB_BUF_SIZE   64
-
-struct altos_file {
-       HANDLE                          handle;
-       unsigned char                   out_data[USB_BUF_SIZE];
-       int                             out_used;
-       unsigned char                   in_data[USB_BUF_SIZE];
-       int                             in_used;
-       int                             in_read;
-       OVERLAPPED                      ov_read;
-       BOOL                            pend_read;
-       OVERLAPPED                      ov_write;
-};
-
-static void
-_altos_set_last_windows_error(char *file, int line)
-{
-       DWORD   error = GetLastError();
-       TCHAR   message[1024];
-       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
-                     0,
-                     error,
-                     0,
-                     message,
-                     sizeof (message) / sizeof (TCHAR),
-                     NULL);
-       if (error != ERROR_SUCCESS)
-               printf ("%s:%d %s\n", file, line, message);
-       altos_set_last_error(error, message);
-}
-
-#define altos_set_last_windows_error() _altos_set_last_windows_error(__FILE__, __LINE__)
-
-PUBLIC struct altos_list *
-altos_list_start(void)
-{
-       struct altos_list       *list = calloc(1, sizeof (struct altos_list));
-
-       if (!list)
-               return NULL;
-       list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
-                                            DIGCF_ALLCLASSES|DIGCF_PRESENT);
-       if (list->dev_info == INVALID_HANDLE_VALUE) {
-               altos_set_last_windows_error();
-               free(list);
-               return NULL;
-       }
-       list->index = 0;
-       return list;
-}
-
-PUBLIC int
-altos_list_next(struct altos_list *list, struct altos_device *device)
-{
-       SP_DEVINFO_DATA dev_info_data;
-       BYTE            port[128];
-       DWORD           port_len;
-       char            friendlyname[256];
-       BYTE            symbolic[256];
-       DWORD           symbolic_len;
-       HKEY            dev_key;
-       unsigned int    vid, pid;
-       int             serial;
-       HRESULT         result;
-       DWORD           friendlyname_type;
-       DWORD           friendlyname_len;
-
-       dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
-       while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
-                                   &dev_info_data))
-       {
-               list->index++;
-
-               dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
-                                              DICS_FLAG_GLOBAL, 0, DIREG_DEV,
-                                              KEY_READ);
-               if (dev_key == INVALID_HANDLE_VALUE) {
-                       altos_set_last_windows_error();
-                       printf("cannot open device registry key\n");
-                       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;
-               }
-
-               /* Fetch the com port name */
-               port_len = sizeof (port);
-               result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
-                                        port, &port_len);
-               RegCloseKey(dev_key);
-               if (result != 0) {
-                       altos_set_last_windows_error();
-                       printf("failed to get PortName\n");
-                       continue;
-               }
-
-               /* Fetch the device description which is the device name,
-                * with firmware that has unique USB ids */
-               friendlyname_len = sizeof (friendlyname);
-               if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
-                                                    &dev_info_data,
-                                                    SPDRP_FRIENDLYNAME,
-                                                    &friendlyname_type,
-                                                    (BYTE *)friendlyname,
-                                                    sizeof(friendlyname),
-                                                    &friendlyname_len))
-               {
-                       altos_set_last_windows_error();
-                       printf("Failed to get friendlyname\n");
-                       continue;
-               }
-               device->vendor = vid;
-               device->product = pid;
-               device->serial = serial;
-               strcpy(device->name, friendlyname);
-
-               strcpy(device->path, (char *) port);
-               return 1;
-       }
-       result = GetLastError();
-       if (result != ERROR_NO_MORE_ITEMS) {
-               altos_set_last_windows_error();
-               printf ("SetupDiEnumDeviceInfo failed error %d\n", (int) result);
-       }
-       return 0;
-}
-
-PUBLIC void
-altos_list_finish(struct altos_list *list)
-{
-       SetupDiDestroyDeviceInfoList(list->dev_info);
-       free(list);
-}
-
-static int
-altos_queue_read(struct altos_file *file)
-{
-       DWORD   got;
-       if (file->pend_read)
-               return LIBALTOS_SUCCESS;
-
-       if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
-               if (GetLastError() != ERROR_IO_PENDING) {
-                       altos_set_last_windows_error();
-                       return LIBALTOS_ERROR;
-               }
-               file->pend_read = TRUE;
-       } else {
-               file->pend_read = FALSE;
-               file->in_read = 0;
-               file->in_used = got;
-       }
-       return LIBALTOS_SUCCESS;
-}
-
-static int
-altos_wait_read(struct altos_file *file, int timeout)
-{
-       DWORD   ret;
-       DWORD   got;
-
-       if (!file->pend_read)
-               return LIBALTOS_SUCCESS;
-
-       if (!timeout)
-               timeout = INFINITE;
-
-       ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
-       switch (ret) {
-       case WAIT_OBJECT_0:
-               if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE)) {
-                       altos_set_last_windows_error();
-                       return LIBALTOS_ERROR;
-               }
-               file->pend_read = FALSE;
-               file->in_read = 0;
-               file->in_used = got;
-               break;
-       case WAIT_TIMEOUT:
-               return LIBALTOS_TIMEOUT;
-               break;
-       default:
-               return LIBALTOS_ERROR;
-       }
-       return LIBALTOS_SUCCESS;
-}
-
-static int
-altos_fill(struct altos_file *file, int timeout)
-{
-       int     ret;
-
-       if (file->in_read < file->in_used)
-               return LIBALTOS_SUCCESS;
-
-       file->in_read = file->in_used = 0;
-
-       ret = altos_queue_read(file);
-       if (ret)
-               return ret;
-       ret = altos_wait_read(file, timeout);
-       if (ret)
-               return ret;
-
-       return LIBALTOS_SUCCESS;
-}
-
-PUBLIC int
-altos_flush(struct altos_file *file)
-{
-       DWORD           put;
-       unsigned char   *data = file->out_data;
-       int             used = file->out_used;
-       DWORD           ret;
-
-       while (used) {
-               if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
-                       if (GetLastError() != ERROR_IO_PENDING) {
-                               altos_set_last_windows_error();
-                               printf ("\tflush write error\n");
-                               return LIBALTOS_ERROR;
-                       }
-                       ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
-                       switch (ret) {
-                       case WAIT_OBJECT_0:
-                               if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE)) {
-                                       altos_set_last_windows_error();
-                                       printf ("\tflush result error\n");
-                                       return LIBALTOS_ERROR;
-                               }
-                               break;
-                       default:
-                               altos_set_last_windows_error();
-                               printf ("\tflush wait error\n");
-                               return LIBALTOS_ERROR;
-                       }
-               }
-               data += put;
-               used -= put;
-       }
-       file->out_used = 0;
-       return LIBALTOS_SUCCESS;
-}
-
-PUBLIC struct altos_file *
-altos_open(struct altos_device *device)
-{
-       struct altos_file       *file = calloc (1, sizeof (struct altos_file));
-       char    full_name[64];
-       COMMTIMEOUTS timeouts;
-
-       if (!file)
-               return NULL;
-
-       strcpy(full_name, "\\\\.\\");
-       strcat(full_name, device->path);
-       file->handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
-                                 0, NULL, OPEN_EXISTING,
-                                 FILE_FLAG_OVERLAPPED, NULL);
-       if (file->handle == INVALID_HANDLE_VALUE) {
-               altos_set_last_windows_error();
-               printf ("cannot open %s\n", full_name);
-               free(file);
-               return NULL;
-       }
-       file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-       file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
-       timeouts.ReadIntervalTimeout = MAXDWORD;
-       timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
-       timeouts.ReadTotalTimeoutConstant = 1 << 30;    /* almost forever */
-       timeouts.WriteTotalTimeoutMultiplier = 0;
-       timeouts.WriteTotalTimeoutConstant = 0;
-       SetCommTimeouts(file->handle, &timeouts);
-
-       return file;
-}
-
-PUBLIC void
-altos_close(struct altos_file *file)
-{
-       if (file->handle != INVALID_HANDLE_VALUE) {
-               CloseHandle(file->handle);
-               file->handle = INVALID_HANDLE_VALUE;
-               SetEvent(file->ov_read.hEvent);
-               SetEvent(file->ov_write.hEvent);
-               CloseHandle(file->ov_read.hEvent);
-               CloseHandle(file->ov_write.hEvent);
-       }
-}
-
-PUBLIC void
-altos_free(struct altos_file *file)
-{
-       altos_close(file);
-       free(file);
-}
-
-PUBLIC int
-altos_putchar(struct altos_file *file, char c)
-{
-       int     ret;
-
-       if (file->out_used == USB_BUF_SIZE) {
-               ret = altos_flush(file);
-               if (ret)
-                       return ret;
-       }
-       file->out_data[file->out_used++] = c;
-       if (file->out_used == USB_BUF_SIZE)
-               return altos_flush(file);
-       return LIBALTOS_SUCCESS;
-}
-
-PUBLIC int
-altos_getchar(struct altos_file *file, int timeout)
-{
-       int     ret;
-       while (file->in_read == file->in_used) {
-               if (file->handle == INVALID_HANDLE_VALUE)
-                       return LIBALTOS_ERROR;
-               ret = altos_fill(file, timeout);
-               if (ret)
-                       return ret;
-       }
-       return file->in_data[file->in_read++];
-}
-
-struct altos_bt_list *
-altos_bt_list_start(int inquiry_time)
-{
-       return NULL;
-}
-
-int
-altos_bt_list_next(struct altos_bt_list *bt_list,
-                  struct altos_bt_device *device)
-{
-       return 0;
-}
-
-void
-altos_bt_list_finish(struct altos_bt_list *bt_list)
-{
-       free(bt_list);
-}
-
-void
-altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
-{
-       strncpy(device->name, name, sizeof (device->name));
-       device->name[sizeof(device->name)-1] = '\0';
-       strncpy(device->addr, addr, sizeof (device->addr));
-       device->addr[sizeof(device->addr)-1] = '\0';
-}
-
-struct altos_file *
-altos_bt_open(struct altos_bt_device *device)
-{
-       return NULL;
-}
-
-#endif
diff --git a/altosui/libaltos/libaltos.dylib b/altosui/libaltos/libaltos.dylib
deleted file mode 100755 (executable)
index 1038817..0000000
Binary files a/altosui/libaltos/libaltos.dylib and /dev/null differ
diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h
deleted file mode 100644 (file)
index f90fbb8..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBALTOS_H_
-#define _LIBALTOS_H_
-
-#include <stdlib.h>
-
-#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
-# ifndef BUILD_STATIC
-#  ifdef BUILD_DLL
-#   define PUBLIC __declspec(dllexport)
-#  else
-#   define PUBLIC __declspec(dllimport)
-#  endif
-# endif /* BUILD_STATIC */
-#endif
-
-#ifndef PUBLIC
-# define PUBLIC
-#endif
-
-struct altos_device {
-       //%immutable;
-       int                             vendor;
-       int                             product;
-       int                             serial;
-       char                            name[256];
-       char                            path[256];
-       //%mutable;
-};
-
-struct altos_bt_device {
-       //%immutable;
-       char                            name[256];
-       char                            addr[20];
-       //%mutable;
-};
-
-struct altos_error {
-       int                             code;
-       char                            string[1024];
-};
-
-#define LIBALTOS_SUCCESS       0
-#define LIBALTOS_ERROR         -1
-#define LIBALTOS_TIMEOUT       -2
-
-/* Returns 0 for success, < 0 on error */
-PUBLIC int
-altos_init(void);
-
-PUBLIC void
-altos_fini(void);
-
-PUBLIC void
-altos_get_last_error(struct altos_error *error);
-
-PUBLIC struct altos_list *
-altos_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);
-
-PUBLIC void
-altos_list_finish(struct altos_list *list);
-
-PUBLIC struct altos_file *
-altos_open(struct altos_device *device);
-
-PUBLIC void
-altos_close(struct altos_file *file);
-
-PUBLIC void
-altos_free(struct altos_file *file);
-
-/* Returns < 0 for error */
-PUBLIC int
-altos_putchar(struct altos_file *file, char c);
-
-/* Returns < 0 for error */
-PUBLIC int
-altos_flush(struct altos_file *file);
-
-/* Returns < 0 for error or timeout. timeout of 0 == wait forever */
-PUBLIC int
-altos_getchar(struct altos_file *file, int timeout);
-
-PUBLIC struct altos_bt_list *
-altos_bt_list_start(int inquiry_time);
-
-PUBLIC int
-altos_bt_list_next(struct altos_bt_list *list, struct altos_bt_device *device);
-
-PUBLIC void
-altos_bt_list_finish(struct altos_bt_list *list);
-
-PUBLIC void
-altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device);
-
-PUBLIC struct altos_file *
-altos_bt_open(struct altos_bt_device *device);
-
-#endif /* _LIBALTOS_H_ */
diff --git a/altosui/libaltos/libaltos.i0 b/altosui/libaltos/libaltos.i0
deleted file mode 100644 (file)
index d06468f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-%module libaltos
-%{
-#include "libaltos.h"
-%}
-
diff --git a/altosuilib/AltosDevice.java b/altosuilib/AltosDevice.java
new file mode 100644 (file)
index 0000000..69b025b
--- /dev/null
@@ -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/altosuilib/AltosDeviceDialog.java b/altosuilib/AltosDeviceDialog.java
new file mode 100644 (file)
index 0000000..cde545a
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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 javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+
+public abstract class AltosDeviceDialog extends AltosUIDialog implements ActionListener {
+
+       private AltosDevice     value;
+       private JList           list;
+       private JButton         cancel_button;
+       private JButton         select_button;
+       public Frame            frame;
+       public int              product;
+       public JPanel           buttonPane;
+       
+       public AltosDevice getValue() {
+               return value;
+       }
+
+       public abstract AltosDevice[] devices();
+
+       public void update_devices() {
+               AltosDevice[] devices = devices();
+               list.setListData(devices);
+               select_button.setEnabled(devices.length > 0);
+       }
+
+       public void add_bluetooth() { }
+
+       public AltosDeviceDialog (Frame in_frame, Component location, int in_product) {
+               super(in_frame, "Device Selection", true);
+
+               product = in_product;
+               frame = in_frame;
+               value = null;
+
+               AltosDevice[]   devices = devices();
+
+               cancel_button = new JButton("Cancel");
+               cancel_button.setActionCommand("cancel");
+               cancel_button.addActionListener(this);
+
+               select_button = new JButton("Select");
+               select_button.setActionCommand("select");
+               select_button.addActionListener(this);
+               if (devices.length == 0)
+                       select_button.setEnabled(false);
+               getRootPane().setDefaultButton(select_button);
+
+               list = new JList(devices) {
+                               //Subclass JList to workaround bug 4832765, which can cause the
+                               //scroll pane to not let the user easily scroll up to the beginning
+                               //of the list.  An alternative would be to set the unitIncrement
+                               //of the JScrollBar to a fixed value. You wouldn't get the nice
+                               //aligned scrolling, but it should work.
+                               public int getScrollableUnitIncrement(Rectangle visibleRect,
+                                                                     int orientation,
+                                                                     int direction) {
+                                       int row;
+                                       if (orientation == SwingConstants.VERTICAL &&
+                                           direction < 0 && (row = getFirstVisibleIndex()) != -1) {
+                                               Rectangle r = getCellBounds(row, row);
+                                               if ((r.y == visibleRect.y) && (row != 0))  {
+                                                       Point loc = r.getLocation();
+                                                       loc.y--;
+                                                       int prevIndex = locationToIndex(loc);
+                                                       Rectangle prevR = getCellBounds(prevIndex, prevIndex);
+
+                                                       if (prevR == null || prevR.y >= r.y) {
+                                                               return 0;
+                                                       }
+                                                       return prevR.height;
+                                               }
+                                       }
+                                       return super.getScrollableUnitIncrement(
+                                               visibleRect, orientation, direction);
+                               }
+                       };
+
+               list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+               list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
+               list.setVisibleRowCount(-1);
+               list.addMouseListener(new MouseAdapter() {
+                                public void mouseClicked(MouseEvent e) {
+                                        if (e.getClickCount() == 2) {
+                                                select_button.doClick(); //emulate button click
+                                        }
+                                }
+                       });
+               JScrollPane listScroller = new JScrollPane(list);
+               listScroller.setPreferredSize(new Dimension(400, 80));
+               listScroller.setAlignmentX(LEFT_ALIGNMENT);
+
+               //Create a container so that we can add a title around
+               //the scroll pane.  Can't add a title directly to the
+               //scroll pane because its background would be white.
+               //Lay out the label and scroll pane from top to bottom.
+               JPanel listPane = new JPanel();
+               listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
+
+               JLabel label = new JLabel("Select Device");
+               label.setLabelFor(list);
+               listPane.add(label);
+               listPane.add(Box.createRigidArea(new Dimension(0,5)));
+               listPane.add(listScroller);
+               listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
+
+               //Lay out the buttons from left to right.
+               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)));
+
+               add_bluetooth();
+
+               buttonPane.add(select_button);
+
+               //Put everything together, using the content pane's BorderLayout.
+               Container contentPane = getContentPane();
+               contentPane.add(listPane, BorderLayout.CENTER);
+               contentPane.add(buttonPane, BorderLayout.PAGE_END);
+
+               //Initialize values.
+               if (devices != null && devices.length != 0)
+                       list.setSelectedValue(devices[0], true);
+               pack();
+               setLocationRelativeTo(location);
+       }
+
+       //Handle clicks on the Set and Cancel buttons.
+       public void actionPerformed(ActionEvent e) {
+               if ("select".equals(e.getActionCommand())) {
+                       value = (AltosDevice)(list.getSelectedValue());
+                       setVisible(false);
+               }
+               if ("cancel".equals(e.getActionCommand()))
+                       setVisible(false);
+       }
+
+}
diff --git a/altosuilib/AltosFontListener.java b/altosuilib/AltosFontListener.java
new file mode 100644 (file)
index 0000000..ef54326
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+public interface AltosFontListener {
+       void font_size_changed(int font_size);
+}
diff --git a/altosuilib/AltosUIConfigure.java b/altosuilib/AltosUIConfigure.java
new file mode 100644 (file)
index 0000000..6c9a841
--- /dev/null
@@ -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/altosuilib/AltosUIDialog.java b/altosuilib/AltosUIDialog.java
new file mode 100644 (file)
index 0000000..c0c33ba
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+class AltosUIDialogListener extends WindowAdapter {
+       public void windowClosing (WindowEvent e) {
+               AltosUIPreferences.unregister_ui_listener((AltosUIDialog) e.getWindow());
+       }
+}
+
+public class AltosUIDialog extends JDialog implements AltosUIListener {
+
+       public void ui_changed(String look_and_feel) {
+               SwingUtilities.updateComponentTreeUI(this);
+               this.pack();
+       }
+
+       public AltosUIDialog() {
+               AltosUIPreferences.register_ui_listener(this);
+               addWindowListener(new AltosUIDialogListener());
+       }
+
+       public AltosUIDialog(Frame frame, String label, boolean modal) {
+               super(frame, label, modal);
+               AltosUIPreferences.register_ui_listener(this);
+               addWindowListener(new AltosUIDialogListener());
+       }
+
+       public AltosUIDialog(Dialog dialog, String label, boolean modal) {
+               super(dialog, label, modal);
+               AltosUIPreferences.register_ui_listener(this);
+               addWindowListener(new AltosUIDialogListener());
+       }
+
+       public AltosUIDialog(Frame frame, boolean modal) {
+               super(frame, modal);
+               AltosUIPreferences.register_ui_listener(this);
+               addWindowListener(new AltosUIDialogListener());
+       }
+}
diff --git a/altosuilib/AltosUIFrame.java b/altosuilib/AltosUIFrame.java
new file mode 100644 (file)
index 0000000..409aea2
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.util.*;
+
+class AltosUIFrameListener extends WindowAdapter {
+       public void windowClosing (WindowEvent e) {
+               AltosUIPreferences.unregister_ui_listener((AltosUIFrame) e.getWindow());
+       }
+}
+
+public class AltosUIFrame extends JFrame implements AltosUIListener {
+
+       public void ui_changed(String look_and_feel) {
+               SwingUtilities.updateComponentTreeUI(this);
+               this.pack();
+       }
+
+       static String[] altos_icon_names = {
+               "/altus-metrum-16.png",
+               "/altus-metrum-32.png",
+               "/altus-metrum-48.png",
+               "/altus-metrum-64.png",
+               "/altus-metrum-128.png",
+               "/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 = AltosUIFrame.class.getResource(icon_names[i]);
+                       if (imgURL != null)
+                               icons.add(new ImageIcon(imgURL).getImage());
+               }
+               setIconImages(icons);
+       }
+                       
+
+       public AltosUIFrame() {
+               AltosUIPreferences.register_ui_listener(this);
+               addWindowListener(new AltosUIFrameListener());
+               set_icon();
+       }
+
+       public AltosUIFrame(String name) {
+               super(name);
+               AltosUIPreferences.register_ui_listener(this);
+               addWindowListener(new AltosUIFrameListener());
+               set_icon();
+       }
+}
diff --git a/altosuilib/AltosUILib.java b/altosuilib/AltosUILib.java
new file mode 100644 (file)
index 0000000..5d5f9aa
--- /dev/null
@@ -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/altosuilib/AltosUIListener.java b/altosuilib/AltosUIListener.java
new file mode 100644 (file)
index 0000000..f4127f5
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+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 (file)
index 0000000..485cb58
--- /dev/null
@@ -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 (file)
index 0000000..c6c05e5
--- /dev/null
@@ -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/altosuilib/AltosUIVersion.java.in b/altosuilib/AltosUIVersion.java.in
new file mode 100644 (file)
index 0000000..6fb3b38
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+public class AltosUIVersion {
+       public final static String version = "@VERSION@";
+}
diff --git a/altosuilib/AltosUSBDevice.java b/altosuilib/AltosUSBDevice.java
new file mode 100644 (file)
index 0000000..bab16fb
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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.util.*;
+import libaltosJNI.*;
+
+public class AltosUSBDevice  extends altos_device implements AltosDevice {
+
+       public String toString() {
+               String  name = getName();
+               if (name == null)
+                       name = "Altus Metrum";
+               return String.format("%-20.20s %4d %s",
+                                    name, getSerial(), getPath());
+       }
+
+       public String toShortString() {
+               String  name = getName();
+               if (name == null)
+                       name = "Altus Metrum";
+               return String.format("%s %d %s",
+                                    name, getSerial(), 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);
+       }
+
+       public boolean isAltusMetrum() {
+               if (getVendor() != AltosUILib.vendor_altusmetrum)
+                       return false;
+               if (getProduct() < AltosUILib.product_altusmetrum_min)
+                       return false;
+               if (getProduct() > AltosUILib.product_altusmetrum_max)
+                       return false;
+               return true;
+       }
+
+       public boolean matchProduct(int want_product) {
+
+               if (!isAltusMetrum())
+                       return false;
+
+               if (want_product == AltosUILib.product_any)
+                       return true;
+
+               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 == AltosUILib.product_altimeter)
+                       return matchProduct(AltosUILib.product_telemetrum) ||
+                               matchProduct(AltosUILib.product_megametrum);
+
+               int have_product = getProduct();
+
+               if (have_product == AltosUILib.product_altusmetrum)     /* old devices match any request */
+                       return true;
+
+               if (want_product == have_product)
+                       return true;
+
+               return false;
+       }
+
+       static public java.util.List<AltosDevice> list(int product) {
+               if (!AltosUILib.load_library())
+                       return null;
+
+               SWIGTYPE_p_altos_list list = libaltos.altos_list_start();
+
+               ArrayList<AltosDevice> device_list = new ArrayList<AltosDevice>();
+               if (list != null) {
+                       for (;;) {
+                               AltosUSBDevice device = new AltosUSBDevice();
+                               if (libaltos.altos_list_next(list, device) == 0)
+                                       break;
+                               if (device.matchProduct(product))
+                                       device_list.add(device);
+                       }
+                       libaltos.altos_list_finish(list);
+               }
+
+               return device_list;
+       }
+}
\ No newline at end of file
diff --git a/altosuilib/AltosUnitsListener.java b/altosuilib/AltosUnitsListener.java
new file mode 100644 (file)
index 0000000..22c66cd
--- /dev/null
@@ -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 (file)
index 0000000..da5fb84
--- /dev/null
@@ -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) .
index 0fcd97e27bac6349850b06cc8b8d7e7a509eef1e..ee68534470f84624149eb1581df75ef8e2003bc1 100644 (file)
@@ -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
index e32b4f1e369b54ea59ccb2207703e3d753516af7..bedf04ef7b433635557b3362c1fee6328c5afa8e 100644 (file)
Binary files a/icon/altus-metrum.ico and b/icon/altus-metrum.ico differ
diff --git a/icon/micro-peak.ico b/icon/micro-peak.ico
new file mode 100644 (file)
index 0000000..b672aa0
Binary files /dev/null and b/icon/micro-peak.ico differ
diff --git a/icon/micropeak-128.png b/icon/micropeak-128.png
new file mode 100644 (file)
index 0000000..f045dc6
Binary files /dev/null and b/icon/micropeak-128.png differ
diff --git a/icon/micropeak-16.png b/icon/micropeak-16.png
new file mode 100644 (file)
index 0000000..d814080
Binary files /dev/null and b/icon/micropeak-16.png differ
diff --git a/icon/micropeak-256.png b/icon/micropeak-256.png
new file mode 100644 (file)
index 0000000..b96d470
Binary files /dev/null and b/icon/micropeak-256.png differ
diff --git a/icon/micropeak-32.png b/icon/micropeak-32.png
new file mode 100644 (file)
index 0000000..d34c5c1
Binary files /dev/null and b/icon/micropeak-32.png differ
diff --git a/icon/micropeak-48.png b/icon/micropeak-48.png
new file mode 100644 (file)
index 0000000..86dc4f7
Binary files /dev/null and b/icon/micropeak-48.png differ
diff --git a/icon/micropeak-64.png b/icon/micropeak-64.png
new file mode 100644 (file)
index 0000000..6ca7c2e
Binary files /dev/null and b/icon/micropeak-64.png differ
diff --git a/libaltos/.gitignore b/libaltos/.gitignore
new file mode 100644 (file)
index 0000000..c490e6f
--- /dev/null
@@ -0,0 +1,12 @@
+*.so
+*.lo
+*.la
+*.java
+*.class
+.libs/
+classlibaltos.stamp
+libaltos_wrap.c
+libaltosJNI
+cjnitest
+libaltos.swig
+swig_bindings/
diff --git a/libaltos/Makefile-standalone b/libaltos/Makefile-standalone
new file mode 100644 (file)
index 0000000..a1f9f5b
--- /dev/null
@@ -0,0 +1,137 @@
+OS:=$(shell uname)
+
+#
+# Linux
+#
+ifeq ($(OS),Linux)
+
+JAVA_CFLAGS=-I/usr/lib/jvm/java-6-openjdk/include
+
+OS_LIB_CFLAGS=-DLINUX -DPOSIX_TTY $(JAVA_CFLAGS)
+
+OS_APP_CFLAGS=$(OS_LIB_CFLAGS)
+
+OS_LDFLAGS=
+
+LIBNAME=libaltos.so
+EXEEXT=
+endif
+
+#
+# Darwin (Mac OS X)
+#
+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 -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
+OS_APP_CFLAGS=$(OS_LIB_CFLAGS)
+
+OS_LDFLAGS =\
+       -framework IOKit -framework CoreFoundation
+
+LIBNAME=libaltos.dylib
+EXEEXT=
+
+endif
+
+#
+# Windows
+#
+ifneq (,$(findstring MINGW,$(OS)))
+
+CC=gcc
+
+OS_LIB_CFLAGS = -DWINDOWS -mconsole -DBUILD_DLL
+OS_APP_CFLAGS = -DWINDOWS -mconsole
+
+OS_LDFLAGS = -lgdi32 -luser32 -lcfgmgr32 -lsetupapi -lole32 \
+       -ladvapi32 -lcomctl32 -mconsole -Wl,--add-stdcall-alias
+
+LIBNAME=altos.dll
+
+EXEEXT=.exe
+
+endif
+
+.SUFFIXES: .java .class
+
+CLASSPATH=".:jnitest/*:libaltosJNI:/usr/share/java/*"
+
+SWIG_DIR=swig_bindings/java
+SWIG_FILE=$(SWIG_DIR)/libaltos.swig
+SWIG_WRAP=$(SWIG_DIR)/libaltos_wrap.c
+
+JNI_DIR=libaltosJNI
+JNI_FILE=$(JNI_DIR)/libaltosJNI.java
+JNI_SRCS=$(JNI_FILE) \
+       $(JNI_DIR)/SWIGTYPE_p_altos_file.java \
+       $(JNI_DIR)/SWIGTYPE_p_altos_list.java \
+       $(JNI_DIR)/altos_device.java \
+       $(JNI_DIR)/libaltos.java
+
+JAVAFILES=\
+       $(JNI_SRCS)
+
+CLASSFILES = $(JAVAFILES:%.java=%.class)
+
+JAVAFLAGS=-Xlint:unchecked
+
+CJNITEST=cjnitest$(EXEEXT)
+
+all: $(LIBNAME) $(CJNITEST) $(CLASSFILES)
+
+.java.class:
+       javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
+
+CFLAGS=$(OS_LIB_CFLAGS) -O -I.
+
+LDFLAGS=$(OS_LDFLAGS)
+
+HEADERS=libaltos.h
+SRCS = libaltos.c $(SWIG_WRAP)
+OBJS = $(SRCS:%.c=%.o)
+LIBS = $(DARWIN_LIBS)
+
+$(CJNITEST): cjnitest.c $(LIBNAME)
+       $(CC) -o $@ $(OS_APP_CFLAGS) cjnitest.c $(LIBNAME) $(LIBS) $(LDFLAGS)
+
+$(LIBNAME): $(OBJS)
+       $(CC) -shared $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
+
+clean:
+       rm -f $(CLASSFILES) $(OBJS) $(LIBNAME) $(CJNITEST) cjnitest.o
+       rm -rf swig_bindings libaltosJNI
+
+distclean:     clean
+
+$(JNI_FILE): libaltos.i0 $(HEADERS)
+       mkdir -p $(SWIG_DIR)
+       mkdir -p libaltosJNI
+       sed 's;//%;%;' libaltos.i0 $(HEADERS) > $(SWIG_FILE)
+       swig -java -package libaltosJNI $(SWIG_FILE)
+       cp swig_bindings/java/*.java libaltosJNI
+
+$(SWIG_WRAP): $(JNI_FILE)
+
+ifeq ($(OS),Linux)
+install:       $(LIBNAME)
+       install -c $(LIBNAME) $(DESTDIR)/usr/lib/altos/$(LIBNAME)
+
+endif
+
+.NOTPARALLEL:
diff --git a/libaltos/Makefile.am b/libaltos/Makefile.am
new file mode 100644 (file)
index 0000000..b5ab1dd
--- /dev/null
@@ -0,0 +1,54 @@
+JAVAC=javac
+AM_CFLAGS=-DLINUX -DPOSIX_TTY -I$(JVM_INCLUDE)
+AM_JAVACFLAGS=-encoding UTF-8
+
+altoslibdir=$(libdir)/altos
+
+altoslib_LTLIBRARIES=libaltos.la
+
+libaltos_la_LDFLAGS = -version-info 1:0:1
+
+libaltos_la_SOURCES=\
+       libaltos.c \
+       libaltos_wrap.c
+
+noinst_PROGRAMS=cjnitest
+
+cjnitest_LDADD=libaltos.la
+
+LIBS=-lbluetooth
+
+HFILES=libaltos.h
+
+SWIG_FILE=libaltos.swig
+
+CLASSDIR=libaltosJNI
+
+$(SWIG_FILE): libaltos.i0 $(HFILES)
+       sed 's;//%;%;' libaltos.i0 $(HFILES) > $(SWIG_FILE)
+
+all-local: classlibaltos.stamp
+
+libaltos_wrap.c: classlibaltos.stamp
+
+classlibaltos.stamp: $(SWIG_FILE)
+       swig -java -package libaltosJNI $(SWIG_FILE)
+       mkdir -p libaltosJNI
+       $(JAVAC) -d . $(AM_JAVACFLAGS) $(JAVACFLAGS) *.java && \
+       touch classlibaltos.stamp
+
+MINGCC32=i686-w64-mingw32-gcc
+MINGCC64=x86_64-w64-mingw32-gcc
+MINGFLAGS=-Wall -DWINDOWS -DBUILD_DLL -I$(JVM_INCLUDE)
+MINGLIBS=-lsetupapi
+
+fat: altos.dll altos64.dll
+
+altos.dll: $(libaltos_la_SOURCES)
+       $(MINGCC32) -o $@ $(MINGFLAGS) -shared $(libaltos_la_SOURCES) $(MINGLIBS)
+
+altos64.dll: $(libaltos_la_SOURCES)
+       $(MINGCC64) -o $@ $(MINGFLAGS) -shared $(libaltos_la_SOURCES) $(MINGLIBS)
+
+clean-local:
+       -rm -rf libaltosJNI *.class *.java classlibaltos.stamp $(SWIG_FILE) libaltos_wrap.c altos.dll altos64.dll
diff --git a/libaltos/cjnitest.c b/libaltos/cjnitest.c
new file mode 100644 (file)
index 0000000..f0fe78f
--- /dev/null
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include "libaltos.h"
+
+static void
+altos_puts(struct altos_file *file, char *string)
+{
+       char    c;
+
+       while ((c = *string++))
+               altos_putchar(file, c);
+}
+
+main ()
+{
+       struct altos_device     device;
+       struct altos_list       *list;
+       struct altos_bt_device  bt_device;
+       struct altos_bt_list    *bt_list;
+
+       altos_init();
+       list = altos_list_start();
+       while (altos_list_next(list, &device)) {
+               struct altos_file       *file;
+               int                     c;
+
+               printf ("%04x:%04x %-20s %4d %s\n", device.vendor, device.product,
+                       device.name, device.serial, device.path);
+
+               file = altos_open(&device);
+               if (!file) {
+                       printf("altos_open failed\n");
+                       continue;
+               }
+               altos_puts(file,"v\nc s\n");
+               altos_flush(file);
+               while ((c = altos_getchar(file, 100)) >= 0) {
+                       putchar (c);
+               }
+               if (c != LIBALTOS_TIMEOUT)
+                       printf ("getchar returns %d\n", c);
+               altos_close(file);
+       }
+       altos_list_finish(list);
+#if HAS_BLUETOOTH
+       bt_list = altos_bt_list_start(8);
+       while (altos_bt_list_next(bt_list, &bt_device)) {
+               printf ("%s %s\n", bt_device.name, bt_device.addr);
+               if (strncmp(bt_device.name, "TeleBT", 6) == 0) {
+                       struct altos_file       *file;
+
+                       int                     c;
+                       file = altos_bt_open(&bt_device);
+                       if (!file) {
+                               printf("altos_bt_open failed\n");
+                               continue;
+                       }
+                       altos_puts(file,"v\nc s\n");
+                       altos_flush(file);
+                       while ((c = altos_getchar(file, 100)) >= 0) {
+                               putchar(c);
+                       }
+                       if (c != LIBALTOS_TIMEOUT)
+                               printf("getchar returns %d\n", c);
+                       altos_close(file);
+               }
+       }
+       altos_bt_list_finish(bt_list);
+#endif
+       altos_fini();
+       return 0;
+}
diff --git a/libaltos/libaltos.c b/libaltos/libaltos.c
new file mode 100644 (file)
index 0000000..ca56746
--- /dev/null
@@ -0,0 +1,1376 @@
+/*
+ * 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.
+ */
+
+#include "libaltos.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BLUETOOTH_PRODUCT_TELEBT       "TeleBT"
+
+#define USE_POLL
+
+PUBLIC int
+altos_init(void)
+{
+       return LIBALTOS_SUCCESS;
+}
+
+PUBLIC void
+altos_fini(void)
+{
+}
+
+static struct altos_error last_error;
+
+static void
+altos_set_last_error(int code, char *string)
+{
+       last_error.code = code;
+       strncpy(last_error.string, string, sizeof (last_error.string) -1);
+       last_error.string[sizeof(last_error.string)-1] = '\0';
+}
+
+PUBLIC void
+altos_get_last_error(struct altos_error *error)
+{
+       *error = last_error;
+}
+
+#ifdef DARWIN
+
+#undef USE_POLL
+
+/* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
+static char *
+altos_strndup (const char *s, size_t n)
+{
+    size_t len = strlen (s);
+    char *ret;
+
+    if (len <= n)
+       return strdup (s);
+    ret = malloc(n + 1);
+    strncpy(ret, s, n);
+    ret[n] = '\0';
+    return ret;
+}
+
+#else
+#define altos_strndup strndup
+#endif
+
+#ifdef POSIX_TTY
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
+
+#define USB_BUF_SIZE   64
+
+struct altos_file {
+       int                             fd;
+#ifdef USE_POLL
+       int                             pipe[2];
+#else
+       int                             out_fd;
+#endif
+       unsigned char                   out_data[USB_BUF_SIZE];
+       int                             out_used;
+       unsigned char                   in_data[USB_BUF_SIZE];
+       int                             in_used;
+       int                             in_read;
+};
+
+static void
+altos_set_last_posix_error(void)
+{
+       altos_set_last_error(errno, strerror(errno));
+}
+
+PUBLIC struct altos_file *
+altos_open(struct altos_device *device)
+{
+       struct altos_file       *file = calloc (sizeof (struct altos_file), 1);
+       int                     ret;
+       struct termios          term;
+
+       if (!file) {
+               altos_set_last_posix_error();
+               return NULL;
+       }
+
+//     altos_set_last_error(12, "yeah yeah, failed again");
+//     free(file);
+//     return NULL;
+
+       file->fd = open(device->path, O_RDWR | O_NOCTTY);
+       if (file->fd < 0) {
+               altos_set_last_posix_error();
+               free(file);
+               return NULL;
+       }
+#ifdef USE_POLL
+       pipe(file->pipe);
+#else
+       file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
+       if (file->out_fd < 0) {
+               altos_set_last_posix_error();
+               close(file->fd);
+               free(file);
+               return NULL;
+       }
+#endif
+       ret = tcgetattr(file->fd, &term);
+       if (ret < 0) {
+               altos_set_last_posix_error();
+               close(file->fd);
+#ifndef USE_POLL
+               close(file->out_fd);
+#endif
+               free(file);
+               return NULL;
+       }
+       cfmakeraw(&term);
+       cfsetospeed(&term, B9600);
+       cfsetispeed(&term, B9600);
+#ifdef USE_POLL
+       term.c_cc[VMIN] = 1;
+       term.c_cc[VTIME] = 0;
+#else
+       term.c_cc[VMIN] = 0;
+       term.c_cc[VTIME] = 1;
+#endif
+       ret = tcsetattr(file->fd, TCSAFLUSH, &term);
+       if (ret < 0) {
+               altos_set_last_posix_error();
+               close(file->fd);
+#ifndef USE_POLL
+               close(file->out_fd);
+#endif
+               free(file);
+               return NULL;
+       }
+       return file;
+}
+
+PUBLIC void
+altos_close(struct altos_file *file)
+{
+       if (file->fd != -1) {
+               int     fd = file->fd;
+               file->fd = -1;
+#ifdef USE_POLL
+               write(file->pipe[1], "\r", 1);
+#else
+               close(file->out_fd);
+               file->out_fd = -1;
+#endif
+               close(fd);
+       }
+}
+
+PUBLIC void
+altos_free(struct altos_file *file)
+{
+       altos_close(file);
+       free(file);
+}
+
+PUBLIC int
+altos_flush(struct altos_file *file)
+{
+       if (file->out_used && 0) {
+               printf ("flush \"");
+               fwrite(file->out_data, 1, file->out_used, stdout);
+               printf ("\"\n");
+       }
+       while (file->out_used) {
+               int     ret;
+
+               if (file->fd < 0)
+                       return -EBADF;
+#ifdef USE_POLL
+               ret = write (file->fd, file->out_data, file->out_used);
+#else
+               ret = write (file->out_fd, file->out_data, file->out_used);
+#endif
+               if (ret < 0) {
+                       altos_set_last_posix_error();
+                       return -last_error.code;
+               }
+               if (ret) {
+                       memmove(file->out_data, file->out_data + ret,
+                               file->out_used - ret);
+                       file->out_used -= ret;
+               }
+       }
+       return 0;
+}
+
+PUBLIC int
+altos_putchar(struct altos_file *file, char c)
+{
+       int     ret;
+
+       if (file->out_used == USB_BUF_SIZE) {
+               ret = altos_flush(file);
+               if (ret) {
+                       return ret;
+               }
+       }
+       file->out_data[file->out_used++] = c;
+       ret = 0;
+       if (file->out_used == USB_BUF_SIZE)
+               ret = altos_flush(file);
+       return ret;
+}
+
+#ifdef USE_POLL
+#include <poll.h>
+#endif
+
+static int
+altos_fill(struct altos_file *file, int timeout)
+{
+       int             ret;
+#ifdef USE_POLL
+       struct pollfd   fd[2];
+#endif
+
+       if (timeout == 0)
+               timeout = -1;
+       while (file->in_read == file->in_used) {
+               if (file->fd < 0)
+                       return LIBALTOS_ERROR;
+#ifdef USE_POLL
+               fd[0].fd = file->fd;
+               fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
+               fd[1].fd = file->pipe[0];
+               fd[1].events = POLLIN;
+               ret = poll(fd, 2, timeout);
+               if (ret < 0) {
+                       altos_set_last_posix_error();
+                       return LIBALTOS_ERROR;
+               }
+               if (ret == 0)
+                       return LIBALTOS_TIMEOUT;
+
+               if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
+                       return LIBALTOS_ERROR;
+               if (fd[0].revents & POLLIN)
+#endif
+               {
+                       ret = read(file->fd, file->in_data, USB_BUF_SIZE);
+                       if (ret < 0) {
+                               altos_set_last_posix_error();
+                               return LIBALTOS_ERROR;
+                       }
+                       file->in_read = 0;
+                       file->in_used = ret;
+#ifndef USE_POLL
+                       if (ret == 0 && timeout > 0)
+                               return LIBALTOS_TIMEOUT;
+#endif
+               }
+       }
+       if (file->in_used && 0) {
+               printf ("fill \"");
+               fwrite(file->in_data, 1, file->in_used, stdout);
+               printf ("\"\n");
+       }
+       return 0;
+}
+
+PUBLIC int
+altos_getchar(struct altos_file *file, int timeout)
+{
+       int     ret;
+       while (file->in_read == file->in_used) {
+               if (file->fd < 0)
+                       return LIBALTOS_ERROR;
+               ret = altos_fill(file, timeout);
+               if (ret)
+                       return ret;
+       }
+       return file->in_data[file->in_read++];
+}
+
+#endif /* POSIX_TTY */
+
+/*
+ * Scan for Altus Metrum devices by looking through /sys
+ */
+
+#ifdef LINUX
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/rfcomm.h>
+
+static char *
+cc_fullname (char *dir, char *file)
+{
+       char    *new;
+       int     dlen = strlen (dir);
+       int     flen = strlen (file);
+       int     slen = 0;
+
+       if (dir[dlen-1] != '/')
+               slen = 1;
+       new = malloc (dlen + slen + flen + 1);
+       if (!new)
+               return 0;
+       strcpy(new, dir);
+       if (slen)
+               strcat (new, "/");
+       strcat(new, file);
+       return new;
+}
+
+static char *
+cc_basename(char *file)
+{
+       char *b;
+
+       b = strrchr(file, '/');
+       if (!b)
+               return file;
+       return b + 1;
+}
+
+static char *
+load_string(char *dir, char *file)
+{
+       char    *full = cc_fullname(dir, file);
+       char    line[4096];
+       char    *r;
+       FILE    *f;
+       int     rlen;
+
+       f = fopen(full, "r");
+       free(full);
+       if (!f)
+               return NULL;
+       r = fgets(line, sizeof (line), f);
+       fclose(f);
+       if (!r)
+               return NULL;
+       rlen = strlen(r);
+       if (r[rlen-1] == '\n')
+               r[rlen-1] = '\0';
+       return strdup(r);
+}
+
+static int
+load_hex(char *dir, char *file)
+{
+       char    *line;
+       char    *end;
+       long    i;
+
+       line = load_string(dir, file);
+       if (!line)
+               return -1;
+       i = strtol(line, &end, 16);
+       free(line);
+       if (end == line)
+               return -1;
+       return i;
+}
+
+static int
+load_dec(char *dir, char *file)
+{
+       char    *line;
+       char    *end;
+       long    i;
+
+       line = load_string(dir, file);
+       if (!line)
+               return -1;
+       i = strtol(line, &end, 10);
+       free(line);
+       if (end == line)
+               return -1;
+       return i;
+}
+
+static int
+dir_filter_tty_colon(const struct dirent *d)
+{
+       return strncmp(d->d_name, "tty:", 4) == 0;
+}
+
+static int
+dir_filter_tty(const struct dirent *d)
+{
+       return strncmp(d->d_name, "tty", 3) == 0;
+}
+
+struct altos_usbdev {
+       char    *sys;
+       char    *tty;
+       char    *manufacturer;
+       char    *product_name;
+       int     serial; /* AltOS always uses simple integer serial numbers */
+       int     idProduct;
+       int     idVendor;
+};
+
+static char *
+usb_tty(char *sys)
+{
+       char *base;
+       int num_configs;
+       int config;
+       struct dirent **namelist;
+       int interface;
+       int num_interfaces;
+       char endpoint_base[20];
+       char *endpoint_full;
+       char *tty_dir;
+       int ntty;
+       char *tty;
+
+       base = cc_basename(sys);
+       num_configs = load_hex(sys, "bNumConfigurations");
+       num_interfaces = load_hex(sys, "bNumInterfaces");
+       for (config = 1; config <= num_configs; config++) {
+               for (interface = 0; interface < num_interfaces; interface++) {
+                       sprintf(endpoint_base, "%s:%d.%d",
+                               base, config, interface);
+                       endpoint_full = cc_fullname(sys, endpoint_base);
+
+
+                       /* Check for tty:ttyACMx style names
+                        */
+                       ntty = scandir(endpoint_full, &namelist,
+                                      dir_filter_tty_colon,
+                                      alphasort);
+                       if (ntty > 0) {
+                               free(endpoint_full);
+                               tty = cc_fullname("/dev", namelist[0]->d_name + 4);
+                               free(namelist);
+                               return tty;
+                       }
+
+                       /* Check for tty/ttyACMx style names
+                        */
+                       tty_dir = cc_fullname(endpoint_full, "tty");
+                       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;
+}
+
+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;
+       usbdev->sys = strdup(sys);
+       usbdev->manufacturer = load_string(sys, "manufacturer");
+       usbdev->product_name = load_string(sys, "product");
+       usbdev->serial = load_dec(sys, "serial");
+       usbdev->idProduct = load_hex(sys, "idProduct");
+       usbdev->idVendor = load_hex(sys, "idVendor");
+       usbdev->tty = tty;
+       return usbdev;
+}
+
+static void
+usbdev_free(struct altos_usbdev *usbdev)
+{
+       free(usbdev->sys);
+       free(usbdev->manufacturer);
+       free(usbdev->product_name);
+       /* this can get used as a return value */
+       if (usbdev->tty)
+               free(usbdev->tty);
+       free(usbdev);
+}
+
+#define USB_DEVICES    "/sys/bus/usb/devices"
+
+static int
+dir_filter_dev(const struct dirent *d)
+{
+       const char      *n = d->d_name;
+       char    c;
+
+       while ((c = *n++)) {
+               if (isdigit(c))
+                       continue;
+               if (c == '-')
+                       continue;
+               if (c == '.' && n != d->d_name + 1)
+                       continue;
+               return 0;
+       }
+       return 1;
+}
+
+struct altos_list {
+       struct altos_usbdev     **dev;
+       int                     current;
+       int                     ndev;
+};
+
+struct altos_list *
+altos_list_start(void)
+{
+       int                     e;
+       struct dirent           **ents;
+       char                    *dir;
+       struct altos_usbdev     *dev;
+       struct altos_list       *devs;
+       int                     n;
+
+       devs = calloc(1, sizeof (struct altos_list));
+       if (!devs)
+               return NULL;
+
+       n = scandir (USB_DEVICES, &ents,
+                    dir_filter_dev,
+                    alphasort);
+       if (!n)
+               return 0;
+       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 (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) {
+               return 0;
+       }
+       dev = list->dev[list->current];
+       strcpy(device->name, dev->product_name);
+       device->vendor = dev->idVendor;
+       device->product = dev->idProduct;
+       strcpy(device->path, dev->tty);
+       device->serial = dev->serial;
+       list->current++;
+       return 1;
+}
+
+void
+altos_list_finish(struct altos_list *usbdevs)
+{
+       int     i;
+
+       if (!usbdevs)
+               return;
+       for (i = 0; i < usbdevs->ndev; i++)
+               usbdev_free(usbdevs->dev[i]);
+       free(usbdevs);
+}
+
+struct altos_bt_list {
+       inquiry_info    *ii;
+       int             sock;
+       int             dev_id;
+       int             rsp;
+       int             num_rsp;
+};
+
+#define INQUIRY_MAX_RSP        255
+
+struct altos_bt_list *
+altos_bt_list_start(int inquiry_time)
+{
+       struct altos_bt_list    *bt_list;
+
+       bt_list = calloc(1, sizeof (struct altos_bt_list));
+       if (!bt_list)
+               goto no_bt_list;
+
+       bt_list->ii = calloc(INQUIRY_MAX_RSP, sizeof (inquiry_info));
+       if (!bt_list->ii)
+               goto no_ii;
+       bt_list->dev_id = hci_get_route(NULL);
+       if (bt_list->dev_id < 0)
+               goto no_dev_id;
+
+       bt_list->sock = hci_open_dev(bt_list->dev_id);
+       if (bt_list->sock < 0)
+               goto no_sock;
+
+       bt_list->num_rsp = hci_inquiry(bt_list->dev_id,
+                                      inquiry_time,
+                                      INQUIRY_MAX_RSP,
+                                      NULL,
+                                      &bt_list->ii,
+                                      IREQ_CACHE_FLUSH);
+       if (bt_list->num_rsp < 0)
+               goto no_rsp;
+
+       bt_list->rsp = 0;
+       return bt_list;
+
+no_rsp:
+       close(bt_list->sock);
+no_sock:
+no_dev_id:
+       free(bt_list->ii);
+no_ii:
+       free(bt_list);
+no_bt_list:
+       return NULL;
+}
+
+int
+altos_bt_list_next(struct altos_bt_list *bt_list,
+                  struct altos_bt_device *device)
+{
+       inquiry_info    *ii;
+
+       if (bt_list->rsp >= bt_list->num_rsp)
+               return 0;
+
+       ii = &bt_list->ii[bt_list->rsp];
+       ba2str(&ii->bdaddr, device->addr);
+       memset(&device->name, '\0', sizeof (device->name));
+       if (hci_read_remote_name(bt_list->sock, &ii->bdaddr,
+                                sizeof (device->name),
+                                device->name, 0) < 0) {
+               strcpy(device->name, "[unknown]");
+       }
+       bt_list->rsp++;
+       return 1;
+}
+
+void
+altos_bt_list_finish(struct altos_bt_list *bt_list)
+{
+       close(bt_list->sock);
+       free(bt_list->ii);
+       free(bt_list);
+}
+
+void
+altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
+{
+       strncpy(device->name, name, sizeof (device->name));
+       device->name[sizeof(device->name)-1] = '\0';
+       strncpy(device->addr, addr, sizeof (device->addr));
+       device->addr[sizeof(device->addr)-1] = '\0';
+}
+
+struct altos_file *
+altos_bt_open(struct altos_bt_device *device)
+{
+       struct sockaddr_rc addr = { 0 };
+       int     s, status;
+       struct altos_file *file;
+
+       file = calloc(1, sizeof (struct altos_file));
+       if (!file)
+               goto no_file;
+       file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+       if (file->fd < 0) {
+               altos_set_last_posix_error();
+               goto no_sock;
+       }
+
+       addr.rc_family = AF_BLUETOOTH;
+       addr.rc_channel = 1;
+       str2ba(device->addr, &addr.rc_bdaddr);
+
+       status = connect(file->fd,
+                        (struct sockaddr *)&addr,
+                        sizeof(addr));
+       if (status < 0) {
+               altos_set_last_posix_error();
+               goto no_link;
+       }
+       sleep(1);
+
+#ifdef USE_POLL
+       pipe(file->pipe);
+#else
+       file->out_fd = dup(file->fd);
+#endif
+       return file;
+no_link:
+       close(s);
+no_sock:
+       free(file);
+no_file:
+       return NULL;
+}
+
+#endif
+
+#ifdef DARWIN
+
+#include <IOKitLib.h>
+#include <IOKit/usb/USBspec.h>
+#include <sys/param.h>
+#include <paths.h>
+#include <CFNumber.h>
+#include <IOBSD.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct altos_list {
+       io_iterator_t iterator;
+       int ftdi;
+};
+
+static int
+get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
+{
+       CFTypeRef entry_as_string;
+       Boolean got_string;
+
+       entry_as_string = IORegistryEntrySearchCFProperty (object,
+                                                          kIOServicePlane,
+                                                          entry,
+                                                          kCFAllocatorDefault,
+                                                          kIORegistryIterateRecursively);
+       if (entry_as_string) {
+               got_string = CFStringGetCString(entry_as_string,
+                                               result, result_len,
+                                               kCFStringEncodingASCII);
+    
+               CFRelease(entry_as_string);
+               if (got_string)
+                       return 1;
+       }
+       return 0;
+}
+
+static int
+get_number(io_object_t object, CFStringRef entry, int *result)
+{
+       CFTypeRef entry_as_number;
+       Boolean got_number;
+       
+       entry_as_number = IORegistryEntrySearchCFProperty (object,
+                                                          kIOServicePlane,
+                                                          entry,
+                                                          kCFAllocatorDefault,
+                                                          kIORegistryIterateRecursively);
+       if (entry_as_number) {
+               got_number = CFNumberGetValue(entry_as_number,
+                                             kCFNumberIntType,
+                                             result);
+               if (got_number)
+                       return 1;
+       }
+       return 0;
+}
+
+PUBLIC struct altos_list *
+altos_list_start(void)
+{
+       struct altos_list *list = calloc (sizeof (struct altos_list), 1);
+       CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
+       io_iterator_t tdIterator;
+       io_object_t tdObject;
+       kern_return_t ret;
+       int i;
+
+       ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
+       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;
+}
+
+PUBLIC int
+altos_list_next(struct altos_list *list, struct altos_device *device)
+{
+       io_object_t object;
+       char serial_string[128];
+
+       for (;;) {
+               object = IOIteratorNext(list->iterator);
+               if (!object)
+                       return 0;
+  
+               if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
+                   !get_number (object, CFSTR(kUSBProductID), &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))) {
+                       device->serial = atoi(serial_string);
+                       return 1;
+               }
+       }
+}
+
+PUBLIC void
+altos_list_finish(struct altos_list *list)
+{
+       IOObjectRelease (list->iterator);
+       free(list);
+}
+
+struct altos_bt_list {
+       int             sock;
+       int             dev_id;
+       int             rsp;
+       int             num_rsp;
+};
+
+#define INQUIRY_MAX_RSP        255
+
+struct altos_bt_list *
+altos_bt_list_start(int inquiry_time)
+{
+       return NULL;
+}
+
+int
+altos_bt_list_next(struct altos_bt_list *bt_list,
+                  struct altos_bt_device *device)
+{
+       return 0;
+}
+
+void
+altos_bt_list_finish(struct altos_bt_list *bt_list)
+{
+}
+
+void
+altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
+{
+       strncpy(device->name, name, sizeof (device->name));
+       device->name[sizeof(device->name)-1] = '\0';
+       strncpy(device->addr, addr, sizeof (device->addr));
+       device->addr[sizeof(device->addr)-1] = '\0';
+}
+
+struct altos_file *
+altos_bt_open(struct altos_bt_device *device)
+{
+       return NULL;
+}
+
+#endif
+
+
+#ifdef WINDOWS
+
+#include <stdlib.h>
+#include <windows.h>
+#include <setupapi.h>
+
+struct altos_list {
+       HDEVINFO        dev_info;
+       int             index;
+       int             ftdi;
+};
+
+#define USB_BUF_SIZE   64
+
+struct altos_file {
+       HANDLE                          handle;
+       unsigned char                   out_data[USB_BUF_SIZE];
+       int                             out_used;
+       unsigned char                   in_data[USB_BUF_SIZE];
+       int                             in_used;
+       int                             in_read;
+       OVERLAPPED                      ov_read;
+       BOOL                            pend_read;
+       OVERLAPPED                      ov_write;
+};
+
+static void
+_altos_set_last_windows_error(char *file, int line)
+{
+       DWORD   error = GetLastError();
+       TCHAR   message[1024];
+       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+                     0,
+                     error,
+                     0,
+                     message,
+                     sizeof (message) / sizeof (TCHAR),
+                     NULL);
+       if (error != ERROR_SUCCESS)
+               printf ("%s:%d %s\n", file, line, message);
+       altos_set_last_error(error, message);
+}
+
+#define altos_set_last_windows_error() _altos_set_last_windows_error(__FILE__, __LINE__)
+
+PUBLIC struct altos_list *
+altos_list_start(void)
+{
+       struct altos_list       *list = calloc(1, sizeof (struct altos_list));
+
+       if (!list)
+               return NULL;
+       list->dev_info = SetupDiGetClassDevs(NULL, "USB", 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 = 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;
+}
+
+PUBLIC int
+altos_list_next(struct altos_list *list, struct altos_device *device)
+{
+       SP_DEVINFO_DATA dev_info_data;
+       BYTE            port[128];
+       DWORD           port_len;
+       char            friendlyname[256];
+       BYTE            symbolic[256];
+       DWORD           symbolic_len;
+       HKEY            dev_key;
+       unsigned int    vid, pid;
+       int             serial;
+       HRESULT         result;
+       DWORD           friendlyname_type;
+       DWORD           friendlyname_len;
+
+       dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
+       while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
+                                   &dev_info_data))
+       {
+               list->index++;
+
+               dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
+                                              DICS_FLAG_GLOBAL, 0, DIREG_DEV,
+                                              KEY_READ);
+               if (dev_key == INVALID_HANDLE_VALUE) {
+                       altos_set_last_windows_error();
+                       printf("cannot open device registry key\n");
+                       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 */
+               port_len = sizeof (port);
+               result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
+                                        port, &port_len);
+               RegCloseKey(dev_key);
+               if (result != 0) {
+                       altos_set_last_windows_error();
+                       printf("failed to get PortName\n");
+                       continue;
+               }
+
+               /* Fetch the device description which is the device name,
+                * with firmware that has unique USB ids */
+               friendlyname_len = sizeof (friendlyname);
+               if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
+                                                    &dev_info_data,
+                                                    SPDRP_FRIENDLYNAME,
+                                                    &friendlyname_type,
+                                                    (BYTE *)friendlyname,
+                                                    sizeof(friendlyname),
+                                                    &friendlyname_len))
+               {
+                       altos_set_last_windows_error();
+                       printf("Failed to get friendlyname\n");
+                       continue;
+               }
+               device->vendor = vid;
+               device->product = pid;
+               device->serial = serial;
+               strcpy(device->name, friendlyname);
+
+               strcpy(device->path, (char *) port);
+               return 1;
+       }
+       result = GetLastError();
+       if (result != ERROR_NO_MORE_ITEMS) {
+               altos_set_last_windows_error();
+               printf ("SetupDiEnumDeviceInfo failed error %d\n", (int) result);
+       }
+       return 0;
+}
+
+PUBLIC void
+altos_list_finish(struct altos_list *list)
+{
+       SetupDiDestroyDeviceInfoList(list->dev_info);
+       free(list);
+}
+
+static int
+altos_queue_read(struct altos_file *file)
+{
+       DWORD   got;
+       if (file->pend_read)
+               return LIBALTOS_SUCCESS;
+
+       if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
+               if (GetLastError() != ERROR_IO_PENDING) {
+                       altos_set_last_windows_error();
+                       return LIBALTOS_ERROR;
+               }
+               file->pend_read = TRUE;
+       } else {
+               file->pend_read = FALSE;
+               file->in_read = 0;
+               file->in_used = got;
+       }
+       return LIBALTOS_SUCCESS;
+}
+
+static int
+altos_wait_read(struct altos_file *file, int timeout)
+{
+       DWORD   ret;
+       DWORD   got;
+
+       if (!file->pend_read)
+               return LIBALTOS_SUCCESS;
+
+       if (!timeout)
+               timeout = INFINITE;
+
+       ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
+       switch (ret) {
+       case WAIT_OBJECT_0:
+               if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE)) {
+                       altos_set_last_windows_error();
+                       return LIBALTOS_ERROR;
+               }
+               file->pend_read = FALSE;
+               file->in_read = 0;
+               file->in_used = got;
+               break;
+       case WAIT_TIMEOUT:
+               return LIBALTOS_TIMEOUT;
+               break;
+       default:
+               return LIBALTOS_ERROR;
+       }
+       return LIBALTOS_SUCCESS;
+}
+
+static int
+altos_fill(struct altos_file *file, int timeout)
+{
+       int     ret;
+
+       if (file->in_read < file->in_used)
+               return LIBALTOS_SUCCESS;
+
+       file->in_read = file->in_used = 0;
+
+       ret = altos_queue_read(file);
+       if (ret)
+               return ret;
+       ret = altos_wait_read(file, timeout);
+       if (ret)
+               return ret;
+
+       return LIBALTOS_SUCCESS;
+}
+
+PUBLIC int
+altos_flush(struct altos_file *file)
+{
+       DWORD           put;
+       unsigned char   *data = file->out_data;
+       int             used = file->out_used;
+       DWORD           ret;
+
+       while (used) {
+               if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
+                       if (GetLastError() != ERROR_IO_PENDING) {
+                               altos_set_last_windows_error();
+                               printf ("\tflush write error\n");
+                               return LIBALTOS_ERROR;
+                       }
+                       ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
+                       switch (ret) {
+                       case WAIT_OBJECT_0:
+                               if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE)) {
+                                       altos_set_last_windows_error();
+                                       printf ("\tflush result error\n");
+                                       return LIBALTOS_ERROR;
+                               }
+                               break;
+                       default:
+                               altos_set_last_windows_error();
+                               printf ("\tflush wait error\n");
+                               return LIBALTOS_ERROR;
+                       }
+               }
+               data += put;
+               used -= put;
+       }
+       file->out_used = 0;
+       return LIBALTOS_SUCCESS;
+}
+
+PUBLIC struct altos_file *
+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;
+
+       strcpy(full_name, "\\\\.\\");
+       strcat(full_name, device->path);
+       file->handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
+                                 0, NULL, OPEN_EXISTING,
+                                 FILE_FLAG_OVERLAPPED, NULL);
+       if (file->handle == INVALID_HANDLE_VALUE) {
+               altos_set_last_windows_error();
+               printf ("cannot open %s\n", full_name);
+               free(file);
+               return NULL;
+       }
+       file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+       file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+       timeouts.ReadIntervalTimeout = MAXDWORD;
+       timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
+       timeouts.ReadTotalTimeoutConstant = 1 << 30;    /* almost forever */
+       timeouts.WriteTotalTimeoutMultiplier = 0;
+       timeouts.WriteTotalTimeoutConstant = 0;
+       SetCommTimeouts(file->handle, &timeouts);
+
+       if (GetCommState(file->handle, &dcb)) {
+               dcb.BaudRate = CBR_9600;
+               (void) SetCommState(file->handle, &dcb);
+       }
+
+       return file;
+}
+
+PUBLIC void
+altos_close(struct altos_file *file)
+{
+       if (file->handle != INVALID_HANDLE_VALUE) {
+               CloseHandle(file->handle);
+               file->handle = INVALID_HANDLE_VALUE;
+               SetEvent(file->ov_read.hEvent);
+               SetEvent(file->ov_write.hEvent);
+               CloseHandle(file->ov_read.hEvent);
+               CloseHandle(file->ov_write.hEvent);
+       }
+}
+
+PUBLIC void
+altos_free(struct altos_file *file)
+{
+       altos_close(file);
+       free(file);
+}
+
+PUBLIC int
+altos_putchar(struct altos_file *file, char c)
+{
+       int     ret;
+
+       if (file->out_used == USB_BUF_SIZE) {
+               ret = altos_flush(file);
+               if (ret)
+                       return ret;
+       }
+       file->out_data[file->out_used++] = c;
+       if (file->out_used == USB_BUF_SIZE)
+               return altos_flush(file);
+       return LIBALTOS_SUCCESS;
+}
+
+PUBLIC int
+altos_getchar(struct altos_file *file, int timeout)
+{
+       int     ret;
+       while (file->in_read == file->in_used) {
+               if (file->handle == INVALID_HANDLE_VALUE)
+                       return LIBALTOS_ERROR;
+               ret = altos_fill(file, timeout);
+               if (ret)
+                       return ret;
+       }
+       return file->in_data[file->in_read++];
+}
+
+struct altos_bt_list *
+altos_bt_list_start(int inquiry_time)
+{
+       return NULL;
+}
+
+int
+altos_bt_list_next(struct altos_bt_list *bt_list,
+                  struct altos_bt_device *device)
+{
+       return 0;
+}
+
+void
+altos_bt_list_finish(struct altos_bt_list *bt_list)
+{
+       free(bt_list);
+}
+
+void
+altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
+{
+       strncpy(device->name, name, sizeof (device->name));
+       device->name[sizeof(device->name)-1] = '\0';
+       strncpy(device->addr, addr, sizeof (device->addr));
+       device->addr[sizeof(device->addr)-1] = '\0';
+}
+
+struct altos_file *
+altos_bt_open(struct altos_bt_device *device)
+{
+       return NULL;
+}
+
+#endif
diff --git a/libaltos/libaltos.dylib b/libaltos/libaltos.dylib
new file mode 100755 (executable)
index 0000000..cfbd3f5
Binary files /dev/null and b/libaltos/libaltos.dylib differ
diff --git a/libaltos/libaltos.h b/libaltos/libaltos.h
new file mode 100644 (file)
index 0000000..6d43159
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBALTOS_H_
+#define _LIBALTOS_H_
+
+#include <stdlib.h>
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# ifndef BUILD_STATIC
+#  ifdef BUILD_DLL
+#   define PUBLIC __declspec(dllexport)
+#  else
+#   define PUBLIC __declspec(dllimport)
+#  endif
+# endif /* BUILD_STATIC */
+#endif
+
+#ifndef PUBLIC
+# define PUBLIC
+#endif
+
+struct altos_device {
+       //%immutable;
+       int                             vendor;
+       int                             product;
+       int                             serial;
+       char                            name[256];
+       char                            path[256];
+       //%mutable;
+};
+
+struct altos_bt_device {
+       //%immutable;
+       char                            name[256];
+       char                            addr[20];
+       //%mutable;
+};
+
+struct altos_error {
+       int                             code;
+       char                            string[1024];
+};
+
+#define LIBALTOS_SUCCESS       0
+#define LIBALTOS_ERROR         -1
+#define LIBALTOS_TIMEOUT       -2
+
+/* Returns 0 for success, < 0 on error */
+PUBLIC int
+altos_init(void);
+
+PUBLIC void
+altos_fini(void);
+
+PUBLIC void
+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);
+
+PUBLIC void
+altos_list_finish(struct altos_list *list);
+
+PUBLIC struct altos_file *
+altos_open(struct altos_device *device);
+
+PUBLIC void
+altos_close(struct altos_file *file);
+
+PUBLIC void
+altos_free(struct altos_file *file);
+
+/* Returns < 0 for error */
+PUBLIC int
+altos_putchar(struct altos_file *file, char c);
+
+/* Returns < 0 for error */
+PUBLIC int
+altos_flush(struct altos_file *file);
+
+/* Returns < 0 for error or timeout. timeout of 0 == wait forever */
+PUBLIC int
+altos_getchar(struct altos_file *file, int timeout);
+
+PUBLIC struct altos_bt_list *
+altos_bt_list_start(int inquiry_time);
+
+PUBLIC int
+altos_bt_list_next(struct altos_bt_list *list, struct altos_bt_device *device);
+
+PUBLIC void
+altos_bt_list_finish(struct altos_bt_list *list);
+
+PUBLIC void
+altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device);
+
+PUBLIC struct altos_file *
+altos_bt_open(struct altos_bt_device *device);
+
+#endif /* _LIBALTOS_H_ */
diff --git a/libaltos/libaltos.i0 b/libaltos/libaltos.i0
new file mode 100644 (file)
index 0000000..d06468f
--- /dev/null
@@ -0,0 +1,5 @@
+%module libaltos
+%{
+#include "libaltos.h"
+%}
+
diff --git a/micropeak/.gitignore b/micropeak/.gitignore
new file mode 100644 (file)
index 0000000..fc99b31
--- /dev/null
@@ -0,0 +1,6 @@
+*.jar
+Manifest.txt
+classes
+*.stamp
+micropeak
+micropeak-test
diff --git a/micropeak/FTDI.tar.gz b/micropeak/FTDI.tar.gz
new file mode 100644 (file)
index 0000000..cd08ecf
Binary files /dev/null and b/micropeak/FTDI.tar.gz differ
diff --git a/micropeak/Info.plist.in b/micropeak/Info.plist.in
new file mode 100644 (file)
index 0000000..40984c5
--- /dev/null
@@ -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 (file)
index 0000000..4a7aaaa
--- /dev/null
@@ -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 (file)
index 0000000..71919dd
--- /dev/null
@@ -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 (file)
index 0000000..c58708e
--- /dev/null
@@ -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 (file)
index 0000000..23195da
--- /dev/null
@@ -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 (file)
index 0000000..28a7550
--- /dev/null
@@ -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 (file)
index 0000000..4b83bb4
--- /dev/null
@@ -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 (file)
index 0000000..13d4838
--- /dev/null
@@ -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 (file)
index 0000000..21ddb0f
--- /dev/null
@@ -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 (file)
index 0000000..03e3af0
--- /dev/null
@@ -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 (file)
index 0000000..5aa127b
--- /dev/null
@@ -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/JavaApplicationStub
new file mode 100755 (executable)
index 0000000..c661d3e
Binary files /dev/null and b/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub differ
diff --git a/micropeak/MicroPeak.app/Contents/PkgInfo b/micropeak/MicroPeak.app/Contents/PkgInfo
new file mode 100644 (file)
index 0000000..8a43480
--- /dev/null
@@ -0,0 +1 @@
+APPLAM.O
diff --git a/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns b/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns
new file mode 100644 (file)
index 0000000..9ba83bf
Binary files /dev/null and b/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns differ
diff --git a/micropeak/MicroPeak.java b/micropeak/MicroPeak.java
new file mode 100644 (file)
index 0000000..5d128df
--- /dev/null
@@ -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 (file)
index 0000000..8546cff
--- /dev/null
@@ -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 (file)
index 0000000..7879ff9
--- /dev/null
@@ -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 (file)
index 0000000..15ef858
--- /dev/null
@@ -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 (file)
index 0000000..90e9dd1
--- /dev/null
@@ -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 (file)
index 0000000..f373e25
--- /dev/null
@@ -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 (file)
index 0000000..f56d81d
--- /dev/null
@@ -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 (file)
index 0000000..64bbdeb
--- /dev/null
@@ -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 (executable)
index 0000000..ace7548
--- /dev/null
@@ -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 (file)
index 0000000..425048b
--- /dev/null
@@ -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
index 63d2f95539dd49d5198541e109cffbf83809a632..8068740f91782483e6f83329a4f439d2c778b5a5 100644 (file)
@@ -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);
index 9fc93fb1aaea4ba77452ae190ef6ff52d9586418..c766a48c6d24b46d91fb698a6d4bb0d6a309042c 100644 (file)
 #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
index b1a70ea2ed56180ee1922b65a57f67380967aa3a..64da41a915304f618b6aa0547969701d0dcd2b55 100644 (file)
@@ -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
index 0c48ed66477a3db5b652c05d5da1ceaa8060dcfb..ff0a4499ea0ca9db0fafa6ec969b5ea9c730571f 100644 (file)
@@ -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
 
index 04bba9e81fa7669e5f3347b58077d7a6f68e64fc..3556f54c00d511932baabad43a3d358311233d0f 100644 (file)
 #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();
 }
index a06d2e1a6bde7f07ba3d1f614960e286c5f27da9..1b239712855e3276da9b2b8d75c213f94bf9e5d3 100644 (file)
 #ifndef _AO_ASYNC_H_
 #define _AO_ASYNC_H_
 
+void
+ao_async_start(void);
+
+void
+ao_async_stop(void);
+
 void
 ao_async_byte(uint8_t byte);
 
index eda0d1d277facd497e09f35078e4280f840a790d..d665efb5b56f94e1123afe8df306ad02dc53bbca 100644 (file)
  */
 
 #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
index 15b2d178c726c9170cd84f77a64dc70c81dfee9e..976852ee2acd13c2e5cc561aae8525668b06d641 100644 (file)
 #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);
index 525cfa42bfe529f14fd7c49647048ca65ba2d58b..f361aa26e7d4ef00ad0d710c477a43f70b1d76a3 100644 (file)
  */
 
 #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 (file)
index 0000000..e408d7c
--- /dev/null
@@ -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
+