From 6db192898eebf750c4d51516eff7916bc4da493b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 31 Dec 2012 11:38:53 -0800 Subject: altoslib: Add units change notification list This allows the UI to automatically respond to changes in the preferred units. Signed-off-by: Keith Packard --- altoslib/AltosPreferences.java | 21 +++++++++++++++++++++ altoslib/AltosUnitsListener.java | 22 ++++++++++++++++++++++ altoslib/Makefile.am | 1 + 3 files changed, 44 insertions(+) create mode 100644 altoslib/AltosUnitsListener.java (limited to 'altoslib') diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index 47196d6e..e50b9b5c 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -367,6 +367,8 @@ public class AltosPreferences { set_common_frequencies(new_frequencies); } + static LinkedList 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(); + units_listeners.add(l); + } + } + + public static void unregister_units_listener(AltosUnitsListener l) { + synchronized(backend) { + units_listeners.remove(l); + } } } diff --git a/altoslib/AltosUnitsListener.java b/altoslib/AltosUnitsListener.java new file mode 100644 index 00000000..50a00cdf --- /dev/null +++ b/altoslib/AltosUnitsListener.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +public interface AltosUnitsListener { + public void units_changed(boolean imperial_units); +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 0086bc65..1b03c925 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -69,6 +69,7 @@ AltosLib_JAVA = \ $(SRC)/AltosTelemetryRecordSensor.java \ $(SRC)/AltosTelemetryRecordMegaSensor.java \ $(SRC)/AltosTelemetryRecordMegaData.java \ + $(SRC)/AltosUnitsListener.java \ $(SRC)/AltosMs5607.java \ $(SRC)/AltosIMU.java \ $(SRC)/AltosMag.java \ -- cgit v1.2.3 From d83587c3c66b730cc54ca153714eee520ee40b2c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 1 Jan 2013 15:30:11 -0800 Subject: micropeak is code complete now. Added save and download functionality. Removed 'new' from file menu. Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 1 + altosuilib/AltosDevice.java | 30 +++++++ altosuilib/AltosDeviceDialog.java | 163 ++++++++++++++++++++++++++++++++++++++ altosuilib/AltosUSBDevice.java | 112 ++++++++++++++++++++++++++ altosuilib/Makefile.am | 3 + libaltos/libaltos.c | 4 + micropeak/Makefile.am | 3 + micropeak/MicroData.java | 15 +++- micropeak/MicroDeviceDialog.java | 50 ++++++++++++ micropeak/MicroDownload.java | 139 ++++++++++++++++++++++++++++++++ micropeak/MicroGraph.java | 5 ++ micropeak/MicroPeak.java | 81 +++++++++++++++---- micropeak/MicroSave.java | 102 ++++++++++++++++++++++++ micropeak/MicroSerial.java | 12 ++- micropeak/MicroUSB.java | 19 +++-- 15 files changed, 708 insertions(+), 31 deletions(-) create mode 100644 altosuilib/AltosDevice.java create mode 100644 altosuilib/AltosDeviceDialog.java create mode 100644 altosuilib/AltosUSBDevice.java create mode 100644 micropeak/MicroDeviceDialog.java create mode 100644 micropeak/MicroDownload.java create mode 100644 micropeak/MicroSave.java (limited to 'altoslib') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 07516aeb..67138450 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -97,6 +97,7 @@ public class AltosLib { public final static int product_any = 0x10000; public final static int product_basestation = 0x10000 + 1; public final static int product_altimeter = 0x10000 + 2; + public final static int product_micropeak_serial = 0x10000 + 3; /* Bluetooth "identifier" (bluetooth sucks) */ public final static String bt_product_telebt = "TeleBT"; diff --git a/altosuilib/AltosDevice.java b/altosuilib/AltosDevice.java new file mode 100644 index 00000000..69b025ba --- /dev/null +++ b/altosuilib/AltosDevice.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 index 00000000..82620b8b --- /dev/null +++ b/altosuilib/AltosDeviceDialog.java @@ -0,0 +1,163 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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; + private JButton manage_bluetooth_button; + private Frame frame; + private int product; + + public AltosDevice getValue() { + return value; + } + + public abstract AltosDevice[] devices(); + + private void update_devices() { + AltosDevice[] devices = devices(); + list.setListData(devices); + select_button.setEnabled(devices.length > 0); + } + + 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); + +// 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); + } + +} diff --git a/altosuilib/AltosUSBDevice.java b/altosuilib/AltosUSBDevice.java new file mode 100644 index 00000000..2f4e0dc6 --- /dev/null +++ b/altosuilib/AltosUSBDevice.java @@ -0,0 +1,112 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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); + } + + private 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 java.util.List list(int product) { + if (!AltosUILib.load_library()) + return null; + + SWIGTYPE_p_altos_list list = libaltos.altos_list_start(); + + ArrayList device_list = new ArrayList(); + 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/Makefile.am b/altosuilib/Makefile.am index 26aee7c4..e2ff8cb5 100644 --- a/altosuilib/Makefile.am +++ b/altosuilib/Makefile.am @@ -11,6 +11,9 @@ AltosUILibdir = $(datadir)/java AltosUILib_JAVA = \ AltosConfigureUI.java \ + AltosDevice.java \ + AltosDeviceDialog.java \ + AltosUSBDevice.java \ AltosFontListener.java \ AltosUIDialog.java \ AltosUIFrame.java \ diff --git a/libaltos/libaltos.c b/libaltos/libaltos.c index d7b266cf..6e884c80 100644 --- a/libaltos/libaltos.c +++ b/libaltos/libaltos.c @@ -116,6 +116,7 @@ altos_open(struct altos_device *device) return NULL; } + printf ("open\n"); // altos_set_last_error(12, "yeah yeah, failed again"); // free(file); // return NULL; @@ -148,6 +149,8 @@ altos_open(struct altos_device *device) return NULL; } cfmakeraw(&term); + cfsetospeed(&term, B9600); + cfsetispeed(&term, B9600); #ifdef USE_POLL term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; @@ -609,6 +612,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device) { struct altos_usbdev *dev; if (list->current >= list->ndev) { + printf ("end\n"); return 0; } dev = list->dev[list->current]; diff --git a/micropeak/Makefile.am b/micropeak/Makefile.am index e0de690c..a54b78a5 100644 --- a/micropeak/Makefile.am +++ b/micropeak/Makefile.am @@ -10,12 +10,15 @@ micropeakdir=$(datadir)/java micropeak_JAVA= \ MicroPeak.java \ MicroData.java \ + MicroDownload.java \ MicroFrame.java \ MicroGraph.java \ + MicroSave.java \ MicroSerial.java \ MicroStats.java \ MicroStatsTable.java \ MicroFileChooser.java \ + MicroDeviceDialog.java \ MicroUSB.java JFREECHART_CLASS= \ diff --git a/micropeak/MicroData.java b/micropeak/MicroData.java index ec9b83d8..8ccd5fd8 100644 --- a/micropeak/MicroData.java +++ b/micropeak/MicroData.java @@ -110,6 +110,7 @@ public class MicroData { private double time_step; private double ground_altitude; private ArrayList bytes; + String name; class FileEndedException extends Exception { @@ -310,12 +311,18 @@ public class MicroData { public void save (OutputStream f) throws IOException { for (int c : bytes) f.write(c); + f.write('\n'); } - public MicroData (InputStream f) throws IOException { + public void set_name(String name) { + this.name = name; + } + + public MicroData (InputStream f, String name) throws IOException, InterruptedException { + this.name = name; bytes = new ArrayList(); if (!find_header(f)) - throw new IOException(); + throw new IOException("No MicroPeak data header found"); try { file_crc = 0xffff; ground_pressure = get_32(f); @@ -354,9 +361,9 @@ public class MicroData { time_step = 0.192; } catch (FileEndedException fe) { - throw new IOException(); + throw new IOException("File Ended Unexpectedly"); } catch (NonHexcharException ne) { - throw new IOException(); + throw new IOException("Non hexadecimal character found"); } } diff --git a/micropeak/MicroDeviceDialog.java b/micropeak/MicroDeviceDialog.java new file mode 100644 index 00000000..7b8a630c --- /dev/null +++ b/micropeak/MicroDeviceDialog.java @@ -0,0 +1,50 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 list = MicroUSB.list(); + int num_devices = list.size(); + AltosDevice[] devices = new AltosDevice[num_devices]; + + for (int i = 0; i < num_devices; i++) + devices[i] = list.get(i); + return devices; + } + + public MicroDeviceDialog (Frame in_frame, Component location) { + super(in_frame, location, 0); + } + + public static AltosDevice show (Component frameComp) { + Frame frame = JOptionPane.getFrameForComponent(frameComp); + MicroDeviceDialog dialog; + + dialog = new MicroDeviceDialog (frame, frameComp); + dialog.setVisible(true); + return dialog.getValue(); + } +} diff --git a/micropeak/MicroDownload.java b/micropeak/MicroDownload.java new file mode 100644 index 00000000..2e328b4a --- /dev/null +++ b/micropeak/MicroDownload.java @@ -0,0 +1,139 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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) { + owner = owner.SetData(data); + MicroSave save = new MicroSave(owner, data); + if (save.runDialog()) + owner.SetName(data.name); + } + 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) { + System.out.printf ("command %s\n", ae.getActionCommand()); + if (serial_thread != null) { + System.out.printf ("Interrupting serial_thread\n"); + 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/MicroGraph.java b/micropeak/MicroGraph.java index 38f54fe0..b9b084f8 100644 --- a/micropeak/MicroGraph.java +++ b/micropeak/MicroGraph.java @@ -111,8 +111,13 @@ public class MicroGraph implements AltosUnitsListener { } } + public void setName (String name) { + chart.setTitle(name); + } + public void setData (MicroData data) { this.data = data; + chart.setTitle(data.name); resetData(); } diff --git a/micropeak/MicroPeak.java b/micropeak/MicroPeak.java index c69f7167..5e375057 100644 --- a/micropeak/MicroPeak.java +++ b/micropeak/MicroPeak.java @@ -34,13 +34,36 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene MicroData data; Container container; JTabbedPane pane; + static int number_of_windows; - private void RunFile(InputStream input) { + 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); + setTitle(data.name); + return this; + } + + void SetName(String name) { + graph.setName(name); + setTitle(name); + } + + private void RunFile(InputStream input, String name) { try { - data = new MicroData(input); - graph.setData(data); - stats.setData(data); + MicroData data = new MicroData(input, name); + SetData(data); } catch (IOException ioe) { + JOptionPane.showMessageDialog(this, + ioe.getMessage(), + "File Read Error", + JOptionPane.ERROR_MESSAGE); + } catch (InterruptedException ie) { } try { input.close(); @@ -50,8 +73,12 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene private void OpenFile(File filename) { try { - RunFile (new FileInputStream(filename)); + RunFile (new FileInputStream(filename), filename.getName()); } catch (FileNotFoundException fne) { + JOptionPane.showMessageDialog(this, + fne.getMessage(), + "Cannot open file", + JOptionPane.ERROR_MESSAGE); } } @@ -60,30 +87,44 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene InputStream input = chooser.runDialog(); if (input != null) - RunFile(input); + RunFile(input, chooser.filename); } private void Preferences() { new AltosConfigureUI(this); } - + private void DownloadData() { - java.util.List devices = MicroUSB.list(); - for (MicroUSB device : devices) - System.out.printf("device %s\n", device.toString()); + AltosDevice device = MicroDeviceDialog.show(this); + + if (device != null) + new MicroDownload(this, device); } + private void Save() { + if (data == null) { + JOptionPane.showMessageDialog(this, + "No data available", + "No data", + JOptionPane.INFORMATION_MESSAGE); + return; + } + MicroSave save = new MicroSave (this, data); + if (save.runDialog()) + SetName(data.name); + } + public void actionPerformed(ActionEvent ev) { if ("Exit".equals(ev.getActionCommand())) System.exit(0); else if ("Open".equals(ev.getActionCommand())) SelectFile(); - else if ("New".equals(ev.getActionCommand())) - new MicroPeak(); else if ("Download".equals(ev.getActionCommand())) DownloadData(); else if ("Preferences".equals(ev.getActionCommand())) Preferences(); + else if ("Save a Copy".equals(ev.getActionCommand())) + Save(); } public void itemStateChanged(ItemEvent e) { @@ -91,6 +132,8 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene public MicroPeak() { + ++number_of_windows; + AltosUIPreferences.set_component(this); container = getContentPane(); @@ -104,10 +147,6 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene JMenu fileMenu = new JMenu("File"); menuBar.add(fileMenu); - JMenuItem newAction = new JMenuItem("New"); - fileMenu.add(newAction); - newAction.addActionListener(this); - JMenuItem openAction = new JMenuItem("Open"); fileMenu.add(openAction); openAction.addActionListener(this); @@ -116,6 +155,10 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene fileMenu.add(downloadAction); downloadAction.addActionListener(this); + JMenuItem saveAction = new JMenuItem("Save a Copy"); + fileMenu.add(saveAction); + saveAction.addActionListener(this); + JMenuItem preferencesAction = new JMenuItem("Preferences"); fileMenu.add(preferencesAction); preferencesAction.addActionListener(this); @@ -128,7 +171,11 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { - System.exit(0); + setVisible(false); + dispose(); + --number_of_windows; + if (number_of_windows == 0) + System.exit(0); } }); diff --git a/micropeak/MicroSave.java b/micropeak/MicroSave.java new file mode 100644 index 00000000..cb4b4221 --- /dev/null +++ b/micropeak/MicroSave.java @@ -0,0 +1,102 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 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 { + FileOutputStream fos = new FileOutputStream(file); + data.save(fos); + fos.close(); + 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()); + } +} diff --git a/micropeak/MicroSerial.java b/micropeak/MicroSerial.java index a1a77a1d..15ef8582 100644 --- a/micropeak/MicroSerial.java +++ b/micropeak/MicroSerial.java @@ -27,6 +27,10 @@ public class MicroSerial extends InputStream { 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; @@ -39,12 +43,12 @@ public class MicroSerial extends InputStream { } } - public MicroSerial(MicroUSB usb) throws FileNotFoundException { - file = usb.open(); + public MicroSerial(AltosDevice device) throws FileNotFoundException { + file = device.open(); if (file == null) { - final String message = usb.getErrorString(); + final String message = device.getErrorString(); throw new FileNotFoundException(String.format("%s (%s)", - usb.toShortString(), + device.toShortString(), message)); } } diff --git a/micropeak/MicroUSB.java b/micropeak/MicroUSB.java index d48610fe..244f7bc0 100644 --- a/micropeak/MicroUSB.java +++ b/micropeak/MicroUSB.java @@ -16,10 +16,12 @@ */ package org.altusmetrum.micropeak; + import java.util.*; import libaltosJNI.*; +import org.altusmetrum.altosuilib.*; -public class MicroUSB extends altos_device { +public class MicroUSB extends altos_device implements AltosDevice { static boolean initialized = false; static boolean loaded_library = false; @@ -48,16 +50,16 @@ public class MicroUSB extends altos_device { String name = getName(); if (name == null) name = "Altus Metrum"; - return String.format("%-20.20s %4d %s", - name, getSerial(), getPath()); + return String.format("%-20.20s %s", + name, getPath()); } public String toShortString() { String name = getName(); if (name == null) name = "Altus Metrum"; - return String.format("%s %d %s", - name, getSerial(), getPath()); + return String.format("%s %s", + name, getPath()); } @@ -75,11 +77,15 @@ public class MicroUSB extends altos_device { private boolean isMicro() { if (getVendor() != 0x0403) return false; - if (getProduct() != 0x6001) + if (getProduct() != 0x6015) return false; return true; } + public boolean matchProduct(int product) { + return isMicro(); + } + static java.util.List list() { if (!load_library()) return null; @@ -92,6 +98,7 @@ public class MicroUSB extends altos_device { MicroUSB device = new MicroUSB(); if (libaltos.altos_list_next(list, device) == 0) break; + System.out.printf("Device %s\n", device.toString()); if (device.isMicro()) device_list.add(device); } -- cgit v1.2.3 From 0933f2ed5791cfdc28242cd60be3942556f4ed20 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Jan 2013 10:48:56 -0800 Subject: altoslib: Remove unused fake product_micropeak_serial Code cleanups have made this no longer useful Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altoslib') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 67138450..07516aeb 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -97,7 +97,6 @@ public class AltosLib { public final static int product_any = 0x10000; public final static int product_basestation = 0x10000 + 1; public final static int product_altimeter = 0x10000 + 2; - public final static int product_micropeak_serial = 0x10000 + 3; /* Bluetooth "identifier" (bluetooth sucks) */ public final static String bt_product_telebt = "TeleBT"; -- cgit v1.2.3 From ca284d8bef2f4bd360eaec58048ba9abdafc55bd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 3 Jan 2013 18:14:40 -0800 Subject: micropeak: Use data.export for Raw display. Change to MPH data.export already knows how to format stuff, so use that to construct the raw data presentation for the GUI too. Signed-off-by: Keith Packard --- altoslib/AltosSpeed.java | 6 +++--- micropeak/MicroData.java | 6 +++--- micropeak/MicroRaw.java | 14 ++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosSpeed.java b/altoslib/AltosSpeed.java index af63ed17..4e2daf5a 100644 --- a/altoslib/AltosSpeed.java +++ b/altoslib/AltosSpeed.java @@ -21,19 +21,19 @@ public class AltosSpeed extends AltosUnits { public double value(double v) { if (AltosConvert.imperial_units) - return AltosConvert.meters_to_feet(v); + return AltosConvert.meters_to_mph(v); return v; } public String show_units() { if (AltosConvert.imperial_units) - return "ft/s"; + return "mph"; return "m/s"; } public String say_units() { if (AltosConvert.imperial_units) - return "feet per second"; + return "miles per hour"; return "meters per second"; } diff --git a/micropeak/MicroData.java b/micropeak/MicroData.java index d3c8c43e..f1204e11 100644 --- a/micropeak/MicroData.java +++ b/micropeak/MicroData.java @@ -265,15 +265,15 @@ public class MicroData { 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(ft/s), Speed(mach), Accel(m/s²), Accel(ft/s²), Accel(g)\n"); + 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,%12.2f,%12.4f,%12.2f,%13.2f,%10.4f\n", + 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_feet(point.speed), + AltosConvert.meters_to_mph(point.speed), AltosConvert.meters_to_mach(point.speed), point.accel, AltosConvert.meters_to_feet(point.accel), diff --git a/micropeak/MicroRaw.java b/micropeak/MicroRaw.java index f5bea76f..dd480bfe 100644 --- a/micropeak/MicroRaw.java +++ b/micropeak/MicroRaw.java @@ -18,6 +18,7 @@ package org.altusmetrum.micropeak; import java.awt.*; +import java.io.*; import javax.swing.*; import org.altusmetrum.AltosLib.*; import org.altusmetrum.altosuilib.*; @@ -25,12 +26,13 @@ import org.altusmetrum.altosuilib.*; public class MicroRaw extends JTextArea { public void setData(MicroData data) { - setRows(data.pressures.length); - setText(" Time, Press, Height, Speed, Accel\n"); - for (MicroDataPoint point : data.points()) { - append(String.format( - "%6.3f,%6.0f,%7.1f,%7.2f,%7.2f\n", - point.time, point.pressure, point.height, point.speed, point.accel)); + 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())); } } -- cgit v1.2.3 From 42733d2823b1ecf54c03881fc120067868c0ff4c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 9 Jan 2013 15:23:46 -0800 Subject: altoslib: Don't smash existing GPS pad alt after boost Leave the existing GPS pad altitude value in place after boost by checking to see if it was ever computed before resetting it to the barometric pad altitude. This makes GPS height values relative to the pad. Signed-off-by: Keith Packard --- altoslib/AltosState.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 218c598a..4f59c840 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -200,10 +200,10 @@ public class AltosState { } ngps++; } - } else - pad_alt = ground_altitude; - - data.new_gps = false; + } else { + if (ngps == 0) + pad_alt = ground_altitude; + } gps_waiting = MIN_PAD_SAMPLES - npad; if (gps_waiting < 0) -- cgit v1.2.3 From f715b5da3424adacc5a7f1e001e1dd7fa6f50385 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 9 Jan 2013 15:29:01 -0800 Subject: altoslib: Clean up AltosRecord clone methods Make the AltosRecord version abstract and then implement suitable versions in each subclass by creating copying constructors for each class. Signed-off-by: Keith Packard --- altoslib/AltosRecord.java | 12 ++---------- altoslib/AltosRecordMM.java | 10 +++++++--- altoslib/AltosRecordNone.java | 4 ++++ altoslib/AltosRecordTM.java | 8 +++++--- 4 files changed, 18 insertions(+), 16 deletions(-) (limited to 'altoslib') diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index 09169515..2c4b6fa5 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -126,6 +126,8 @@ public abstract class AltosRecord implements Comparable , 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 , Cloneable kalman_height = old.kalman_height; } - public AltosRecord clone() { - try { - AltosRecord n = (AltosRecord) super.clone(); - n.copy(this); - return n; - } catch (CloneNotSupportedException e) { - return null; - } - } - public AltosRecord() { seen = 0; version = 0; diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java index 9f529234..546f3055 100644 --- a/altoslib/AltosRecordMM.java +++ b/altoslib/AltosRecordMM.java @@ -131,10 +131,10 @@ public class AltosRecordMM extends AltosRecord { mag = old.mag; } + + public AltosRecordMM clone() { - AltosRecordMM n = (AltosRecordMM) super.clone(); - n.copy(this); - return n; + return new AltosRecordMM(this); } void make_missing() { @@ -167,6 +167,10 @@ public class AltosRecordMM extends AltosRecord { make_missing(); } + public AltosRecordMM(AltosRecordMM old) { + copy(old); + } + public AltosRecordMM() { super(); make_missing(); diff --git a/altoslib/AltosRecordNone.java b/altoslib/AltosRecordNone.java index ca0a5fe3..d4ea305f 100644 --- a/altoslib/AltosRecordNone.java +++ b/altoslib/AltosRecordNone.java @@ -28,6 +28,10 @@ public class AltosRecordNone extends AltosRecord { super.copy(old); } + public AltosRecordNone clone() { + return new AltosRecordNone(this); + } + public AltosRecordNone() { super(); } diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java index 9530be31..f6ed4966 100644 --- a/altoslib/AltosRecordTM.java +++ b/altoslib/AltosRecordTM.java @@ -149,9 +149,7 @@ public class AltosRecordTM extends AltosRecord { } public AltosRecordTM clone() { - AltosRecordTM n = (AltosRecordTM) super.clone(); - n.copy(this); - return n; + return new AltosRecordTM(this); } void make_missing() { @@ -177,6 +175,10 @@ public class AltosRecordTM extends AltosRecord { make_missing(); } + public AltosRecordTM(AltosRecordTM old) { + copy(old); + } + public AltosRecordTM() { super(); make_missing(); -- cgit v1.2.3