From 3fbefb3eea981d34a09496cf8abf0119de2e35bf Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 24 Nov 2010 14:57:57 -0800 Subject: Move altosui to the top level, placing libaltos inside it. Signed-off-by: Keith Packard --- altosui/.gitignore | 19 + .../01altosui-contents.xml | 1 + .../01altosui.xml | 1 + .../AltOS Package Configuration.pmdoc/index.xml | 1 + altosui/Altos.java | 218 +++++ altosui/AltosAscent.java | 335 +++++++ altosui/AltosCRCException.java | 26 + altosui/AltosCSV.java | 252 +++++ altosui/AltosCSVUI.java | 108 ++ altosui/AltosChannelMenu.java | 44 + altosui/AltosConfig.java | 295 ++++++ altosui/AltosConfigUI.java | 466 +++++++++ altosui/AltosConfigureUI.java | 187 ++++ altosui/AltosConvert.java | 192 ++++ altosui/AltosDataChooser.java | 79 ++ altosui/AltosDataPoint.java | 29 + altosui/AltosDataPointReader.java | 72 ++ altosui/AltosDebug.java | 267 +++++ altosui/AltosDescent.java | 353 +++++++ altosui/AltosDevice.java | 170 ++++ altosui/AltosDeviceDialog.java | 164 ++++ altosui/AltosDisplayThread.java | 249 +++++ altosui/AltosEepromDownload.java | 285 ++++++ altosui/AltosEepromIterable.java | 423 ++++++++ altosui/AltosEepromMonitor.java | 176 ++++ altosui/AltosEepromRecord.java | 115 +++ altosui/AltosFile.java | 44 + altosui/AltosFlash.java | 344 +++++++ altosui/AltosFlashUI.java | 218 +++++ altosui/AltosFlightDisplay.java | 24 + altosui/AltosFlightInfoTableModel.java | 84 ++ altosui/AltosFlightReader.java | 38 + altosui/AltosFlightStatus.java | 154 +++ altosui/AltosFlightStatusTableModel.java | 61 ++ altosui/AltosFlightUI.java | 221 +++++ altosui/AltosGPS.java | 215 ++++ altosui/AltosGraph.java | 25 + altosui/AltosGraphTime.java | 233 +++++ altosui/AltosGraphUI.java | 274 ++++++ altosui/AltosGreatCircle.java | 100 ++ altosui/AltosHexfile.java | 252 +++++ altosui/AltosIgnite.java | 173 ++++ altosui/AltosIgniteUI.java | 317 ++++++ altosui/AltosInfoTable.java | 190 ++++ altosui/AltosKML.java | 169 ++++ altosui/AltosLanded.java | 212 ++++ altosui/AltosLed.java | 54 + altosui/AltosLights.java | 73 ++ altosui/AltosLine.java | 30 + altosui/AltosLog.java | 115 +++ altosui/AltosPad.java | 269 +++++ altosui/AltosParse.java | 79 ++ altosui/AltosPreferences.java | 205 ++++ altosui/AltosReader.java | 28 + altosui/AltosRecord.java | 219 +++++ altosui/AltosRecordIterable.java | 34 + altosui/AltosReplayReader.java | 57 ++ altosui/AltosRomconfig.java | 147 +++ altosui/AltosRomconfigUI.java | 186 ++++ altosui/AltosSerial.java | 253 +++++ altosui/AltosSerialInUseException.java | 28 + altosui/AltosSerialMonitor.java | 22 + altosui/AltosSiteMap.java | 388 ++++++++ altosui/AltosSiteMapCache.java | 103 ++ altosui/AltosSiteMapTile.java | 112 +++ altosui/AltosState.java | 197 ++++ altosui/AltosTelemetry.java | 143 +++ altosui/AltosTelemetryIterable.java | 82 ++ altosui/AltosTelemetryReader.java | 61 ++ altosui/AltosUI.app/Contents/Info.plist | 38 + .../AltosUI.app/Contents/MacOS/JavaApplicationStub | Bin 0 -> 61296 bytes altosui/AltosUI.app/Contents/PkgInfo | 1 + .../Contents/Resources/AltosUIIcon.icns | Bin 0 -> 129010 bytes altosui/AltosUI.java | 405 ++++++++ altosui/AltosVoice.java | 95 ++ altosui/AltosWriter.java | 32 + altosui/GrabNDrag.java | 54 + altosui/Instdrv/NSIS/Contrib/InstDrv/Example.nsi | 84 ++ .../Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe | Bin 0 -> 51831 bytes altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.c | 704 ++++++++++++++ altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsp | 110 +++ altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsw | 29 + altosui/Instdrv/NSIS/Contrib/InstDrv/Readme.txt | 141 +++ altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.inf | 137 +++ altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys | Bin 0 -> 30464 bytes altosui/Instdrv/NSIS/Plugins/InstDrv.dll | Bin 0 -> 6656 bytes altosui/Makefile-standalone | 184 ++++ altosui/Makefile.am | 272 ++++++ altosui/altos-windows.nsi | 113 +++ altosui/altosui-fat | 4 + altosui/altosui.1 | 46 + altosui/altusmetrum.jpg | Bin 0 -> 72868 bytes altosui/libaltos/.gitignore | 12 + altosui/libaltos/Makefile-standalone | 126 +++ altosui/libaltos/Makefile.am | 41 + altosui/libaltos/altos.dll | Bin 0 -> 31765 bytes altosui/libaltos/cjnitest.c | 43 + altosui/libaltos/libaltos.c | 1028 ++++++++++++++++++++ altosui/libaltos/libaltos.dylib | Bin 0 -> 54176 bytes altosui/libaltos/libaltos.h | 102 ++ altosui/libaltos/libaltos.i0 | 5 + 101 files changed, 14566 insertions(+) create mode 100644 altosui/.gitignore create mode 100644 altosui/AltOS Package Configuration.pmdoc/01altosui-contents.xml create mode 100644 altosui/AltOS Package Configuration.pmdoc/01altosui.xml create mode 100644 altosui/AltOS Package Configuration.pmdoc/index.xml create mode 100644 altosui/Altos.java create mode 100644 altosui/AltosAscent.java create mode 100644 altosui/AltosCRCException.java create mode 100644 altosui/AltosCSV.java create mode 100644 altosui/AltosCSVUI.java create mode 100644 altosui/AltosChannelMenu.java create mode 100644 altosui/AltosConfig.java create mode 100644 altosui/AltosConfigUI.java create mode 100644 altosui/AltosConfigureUI.java create mode 100644 altosui/AltosConvert.java create mode 100644 altosui/AltosDataChooser.java create mode 100644 altosui/AltosDataPoint.java create mode 100644 altosui/AltosDataPointReader.java create mode 100644 altosui/AltosDebug.java create mode 100644 altosui/AltosDescent.java create mode 100644 altosui/AltosDevice.java create mode 100644 altosui/AltosDeviceDialog.java create mode 100644 altosui/AltosDisplayThread.java create mode 100644 altosui/AltosEepromDownload.java create mode 100644 altosui/AltosEepromIterable.java create mode 100644 altosui/AltosEepromMonitor.java create mode 100644 altosui/AltosEepromRecord.java create mode 100644 altosui/AltosFile.java create mode 100644 altosui/AltosFlash.java create mode 100644 altosui/AltosFlashUI.java create mode 100644 altosui/AltosFlightDisplay.java create mode 100644 altosui/AltosFlightInfoTableModel.java create mode 100644 altosui/AltosFlightReader.java create mode 100644 altosui/AltosFlightStatus.java create mode 100644 altosui/AltosFlightStatusTableModel.java create mode 100644 altosui/AltosFlightUI.java create mode 100644 altosui/AltosGPS.java create mode 100644 altosui/AltosGraph.java create mode 100644 altosui/AltosGraphTime.java create mode 100644 altosui/AltosGraphUI.java create mode 100644 altosui/AltosGreatCircle.java create mode 100644 altosui/AltosHexfile.java create mode 100644 altosui/AltosIgnite.java create mode 100644 altosui/AltosIgniteUI.java create mode 100644 altosui/AltosInfoTable.java create mode 100644 altosui/AltosKML.java create mode 100644 altosui/AltosLanded.java create mode 100644 altosui/AltosLed.java create mode 100644 altosui/AltosLights.java create mode 100644 altosui/AltosLine.java create mode 100644 altosui/AltosLog.java create mode 100644 altosui/AltosPad.java create mode 100644 altosui/AltosParse.java create mode 100644 altosui/AltosPreferences.java create mode 100644 altosui/AltosReader.java create mode 100644 altosui/AltosRecord.java create mode 100644 altosui/AltosRecordIterable.java create mode 100644 altosui/AltosReplayReader.java create mode 100644 altosui/AltosRomconfig.java create mode 100644 altosui/AltosRomconfigUI.java create mode 100644 altosui/AltosSerial.java create mode 100644 altosui/AltosSerialInUseException.java create mode 100644 altosui/AltosSerialMonitor.java create mode 100644 altosui/AltosSiteMap.java create mode 100644 altosui/AltosSiteMapCache.java create mode 100644 altosui/AltosSiteMapTile.java create mode 100644 altosui/AltosState.java create mode 100644 altosui/AltosTelemetry.java create mode 100644 altosui/AltosTelemetryIterable.java create mode 100644 altosui/AltosTelemetryReader.java create mode 100644 altosui/AltosUI.app/Contents/Info.plist create mode 100755 altosui/AltosUI.app/Contents/MacOS/JavaApplicationStub create mode 100644 altosui/AltosUI.app/Contents/PkgInfo create mode 100644 altosui/AltosUI.app/Contents/Resources/AltosUIIcon.icns create mode 100644 altosui/AltosUI.java create mode 100644 altosui/AltosVoice.java create mode 100644 altosui/AltosWriter.java create mode 100644 altosui/GrabNDrag.java create mode 100644 altosui/Instdrv/NSIS/Contrib/InstDrv/Example.nsi create mode 100644 altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe create mode 100644 altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.c create mode 100644 altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsp create mode 100644 altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsw create mode 100644 altosui/Instdrv/NSIS/Contrib/InstDrv/Readme.txt create mode 100644 altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.inf create mode 100644 altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys create mode 100644 altosui/Instdrv/NSIS/Plugins/InstDrv.dll create mode 100644 altosui/Makefile-standalone create mode 100644 altosui/Makefile.am create mode 100644 altosui/altos-windows.nsi create mode 100755 altosui/altosui-fat create mode 100644 altosui/altosui.1 create mode 100644 altosui/altusmetrum.jpg create mode 100644 altosui/libaltos/.gitignore create mode 100644 altosui/libaltos/Makefile-standalone create mode 100644 altosui/libaltos/Makefile.am create mode 100755 altosui/libaltos/altos.dll create mode 100644 altosui/libaltos/cjnitest.c create mode 100644 altosui/libaltos/libaltos.c create mode 100755 altosui/libaltos/libaltos.dylib create mode 100644 altosui/libaltos/libaltos.h create mode 100644 altosui/libaltos/libaltos.i0 (limited to 'altosui') diff --git a/altosui/.gitignore b/altosui/.gitignore new file mode 100644 index 00000000..89be1d53 --- /dev/null +++ b/altosui/.gitignore @@ -0,0 +1,19 @@ +windows/ +linux/ +macosx/ +fat/ +Manifest.txt +Manifest-fat.txt +libaltosJNI +classes +altosui +altosui-test +classaltosui.stamp +Altos-Linux-*.tar.bz2 +Altos-Mac-*.zip +Altos-Windows-*.exe +*.dll +*.dylib +*.so +*.jar +*.class diff --git a/altosui/AltOS Package Configuration.pmdoc/01altosui-contents.xml b/altosui/AltOS Package Configuration.pmdoc/01altosui-contents.xml new file mode 100644 index 00000000..18e00fe4 --- /dev/null +++ b/altosui/AltOS Package Configuration.pmdoc/01altosui-contents.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/altosui/AltOS Package Configuration.pmdoc/01altosui.xml b/altosui/AltOS Package Configuration.pmdoc/01altosui.xml new file mode 100644 index 00000000..6170931b --- /dev/null +++ b/altosui/AltOS Package Configuration.pmdoc/01altosui.xml @@ -0,0 +1 @@ +org.altusmetrum.altosUi.AltosUI.pkg0.7AltosUI.app/Applications/AltosUI.appinstallTo.pathinstallFrom.isRelativeTypeversionparentrequireAuthorizationinstallTo01altosui-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/altosui/AltOS Package Configuration.pmdoc/index.xml b/altosui/AltOS Package Configuration.pmdoc/index.xml new file mode 100644 index 00000000..fabe54a6 --- /dev/null +++ b/altosui/AltOS Package Configuration.pmdoc/index.xml @@ -0,0 +1 @@ +AltOS UI/Users/keithp/altos/ao-tools/altosui/AltosUI.pkgorg.altusmetrumInstall AltOS User Interfacealtusmetrum.jpg01altosui.xmlproperties.anywhereDomainproperties.titleproperties.customizeOptiondescriptionproperties.userDomainproperties.systemDomain \ No newline at end of file diff --git a/altosui/Altos.java b/altosui/Altos.java new file mode 100644 index 00000000..8ee94e04 --- /dev/null +++ b/altosui/Altos.java @@ -0,0 +1,218 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.util.*; +import java.text.*; + +public class Altos { + /* EEProm command letters */ + static final int AO_LOG_FLIGHT = 'F'; + static final int AO_LOG_SENSOR = 'A'; + static final int AO_LOG_TEMP_VOLT = 'T'; + static final int AO_LOG_DEPLOY = 'D'; + static final int AO_LOG_STATE = 'S'; + static final int AO_LOG_GPS_TIME = 'G'; + static final int AO_LOG_GPS_LAT = 'N'; + static final int AO_LOG_GPS_LON = 'W'; + static final int AO_LOG_GPS_ALT = 'H'; + static final int AO_LOG_GPS_SAT = 'V'; + static final int AO_LOG_GPS_DATE = 'Y'; + + /* Added for header fields in eeprom files */ + static final int AO_LOG_CONFIG_VERSION = 1000; + static final int AO_LOG_MAIN_DEPLOY = 1001; + static final int AO_LOG_APOGEE_DELAY = 1002; + static final int AO_LOG_RADIO_CHANNEL = 1003; + static final int AO_LOG_CALLSIGN = 1004; + static final int AO_LOG_ACCEL_CAL = 1005; + static final int AO_LOG_RADIO_CAL = 1006; + static final int AO_LOG_MANUFACTURER = 1007; + static final int AO_LOG_PRODUCT = 1008; + static final int AO_LOG_SERIAL_NUMBER = 1009; + static final int AO_LOG_SOFTWARE_VERSION = 1010; + + /* Added to flag invalid records */ + static final int AO_LOG_INVALID = -1; + + /* Flight state numbers and names */ + static final int ao_flight_startup = 0; + static final int ao_flight_idle = 1; + static final int ao_flight_pad = 2; + static final int ao_flight_boost = 3; + static final int ao_flight_fast = 4; + static final int ao_flight_coast = 5; + static final int ao_flight_drogue = 6; + static final int ao_flight_main = 7; + static final int ao_flight_landed = 8; + static final int ao_flight_invalid = 9; + + static HashMap string_to_state = new HashMap(); + + static boolean map_initialized = false; + + static final int tab_elt_pad = 5; + + static final Font label_font = new Font("Dialog", Font.PLAIN, 22); + static final Font value_font = new Font("Monospaced", Font.PLAIN, 22); + static final Font status_font = new Font("SansSerif", Font.BOLD, 24); + + static final int text_width = 16; + + static void initialize_map() + { + string_to_state.put("startup", ao_flight_startup); + string_to_state.put("idle", ao_flight_idle); + string_to_state.put("pad", ao_flight_pad); + string_to_state.put("boost", ao_flight_boost); + string_to_state.put("fast", ao_flight_fast); + string_to_state.put("coast", ao_flight_coast); + string_to_state.put("drogue", ao_flight_drogue); + string_to_state.put("main", ao_flight_main); + string_to_state.put("landed", ao_flight_landed); + string_to_state.put("invalid", ao_flight_invalid); + map_initialized = true; + } + + static String[] state_to_string = { + "startup", + "idle", + "pad", + "boost", + "fast", + "coast", + "drogue", + "main", + "landed", + "invalid", + }; + + static public int state(String state) { + if (!map_initialized) + initialize_map(); + if (string_to_state.containsKey(state)) + return string_to_state.get(state); + return ao_flight_invalid; + } + + static public String state_name(int state) { + if (state < 0 || state_to_string.length <= state) + return "invalid"; + return state_to_string[state]; + } + + static final int AO_GPS_VALID = (1 << 4); + static final int AO_GPS_RUNNING = (1 << 5); + static final int AO_GPS_DATE_VALID = (1 << 6); + static final int AO_GPS_NUM_SAT_SHIFT = 0; + static final int AO_GPS_NUM_SAT_MASK = 0xf; + + static boolean isspace(int c) { + switch (c) { + case ' ': + case '\t': + return true; + } + return false; + } + + static boolean ishex(int c) { + if ('0' <= c && c <= '9') + return true; + if ('a' <= c && c <= 'f') + return true; + if ('A' <= c && c <= 'F') + return true; + return false; + } + + static boolean ishex(String s) { + for (int i = 0; i < s.length(); i++) + if (!ishex(s.charAt(i))) + return false; + return true; + } + + static int fromhex(int c) { + 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; + return -1; + } + + static int fromhex(String s) throws NumberFormatException { + int c, v = 0; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (!ishex(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + return v; + } + v = v * 16 + fromhex(c); + } + return v; + } + + static boolean isdec(int c) { + if ('0' <= c && c <= '9') + return true; + return false; + } + + static boolean isdec(String s) { + for (int i = 0; i < s.length(); i++) + if (!isdec(s.charAt(i))) + return false; + return true; + } + + static int fromdec(int c) { + if ('0' <= c && c <= '9') + return c - '0'; + return -1; + } + + static int fromdec(String s) throws NumberFormatException { + int c, v = 0; + int sign = 1; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (i == 0 && c == '-') { + sign = -1; + } else if (!isdec(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid number \"%s\"", s)); + return v; + } else + v = v * 10 + fromdec(c); + } + return v * sign; + } + + static String replace_extension(String input, String extension) { + int dot = input.lastIndexOf("."); + if (dot > 0) + input = input.substring(0,dot); + return input.concat(extension); + } +} diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java new file mode 100644 index 00000000..64bdcf30 --- /dev/null +++ b/altosui/AltosAscent.java @@ -0,0 +1,335 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosAscent extends JComponent implements AltosFlightDisplay { + GridBagLayout layout; + + public class AscentStatus { + JLabel label; + JTextField value; + AltosLights lights; + + void show(AltosState state, int crc_errors) {} + void reset() { + value.setText(""); + lights.set(false); + } + + public AscentStatus (GridBagLayout layout, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.weighty = 1; + + lights = new AltosLights(); + c.gridx = 0; c.gridy = y; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(lights, c); + add(lights); + + label = new JLabel(text); + label.setFont(Altos.label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = 1; c.gridy = y; + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(label, c); + add(label); + + value = new JTextField(Altos.text_width); + value.setFont(Altos.value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = 2; c.gridy = y; + c.gridwidth = 2; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + layout.setConstraints(value, c); + add(value); + + } + } + + public class AscentValue { + JLabel label; + JTextField value; + void show(AltosState state, int crc_errors) {} + + void reset() { + value.setText(""); + } + public AscentValue (GridBagLayout layout, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.weighty = 1; + + label = new JLabel(text); + label.setFont(Altos.label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = 1; c.gridy = y; + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(label, c); + add(label); + + value = new JTextField(Altos.text_width); + value.setFont(Altos.value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = 2; c.gridy = y; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.BOTH; + c.gridwidth = 2; + c.weightx = 1; + layout.setConstraints(value, c); + add(value); + } + } + + public class AscentValueHold { + JLabel label; + JTextField value; + JTextField max_value; + double max; + + void show(AltosState state, int crc_errors) {} + + void reset() { + value.setText(""); + max_value.setText(""); + max = 0; + } + + void show(String format, double v) { + value.setText(String.format(format, v)); + if (v > max) { + max_value.setText(String.format(format, v)); + max = v; + } + } + public AscentValueHold (GridBagLayout layout, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.weighty = 1; + + label = new JLabel(text); + label.setFont(Altos.label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = 1; c.gridy = y; + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(label, c); + add(label); + + value = new JTextField(Altos.text_width); + value.setFont(Altos.value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = 2; c.gridy = y; + c.anchor = GridBagConstraints.EAST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + layout.setConstraints(value, c); + add(value); + + max_value = new JTextField(Altos.text_width); + max_value.setFont(Altos.value_font); + max_value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = 3; c.gridy = y; + c.anchor = GridBagConstraints.EAST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + layout.setConstraints(max_value, c); + add(max_value); + } + } + + + class Height extends AscentValueHold { + void show (AltosState state, int crc_errors) { + show("%6.0f m", state.height); + } + public Height (GridBagLayout layout, int y) { + super (layout, y, "Height"); + } + } + + Height height; + + class Speed extends AscentValueHold { + void show (AltosState state, int crc_errors) { + double speed = state.speed; + if (!state.ascent) + speed = state.baro_speed; + show("%6.0f m/s", speed); + } + public Speed (GridBagLayout layout, int y) { + super (layout, y, "Speed"); + } + } + + Speed speed; + + class Accel extends AscentValueHold { + void show (AltosState state, int crc_errors) { + show("%6.0f m/s²", state.acceleration); + } + public Accel (GridBagLayout layout, int y) { + super (layout, y, "Acceleration"); + } + } + + Accel accel; + + String pos(double p, String pos, String neg) { + String h = pos; + if (p < 0) { + h = neg; + p = -p; + } + int deg = (int) Math.floor(p); + double min = (p - Math.floor(p)) * 60.0; + return String.format("%s %4d° %9.6f", h, deg, min); + } + + class Apogee extends AscentStatus { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4.2f V", state.drogue_sense)); + lights.set(state.drogue_sense > 3.2); + } + public Apogee (GridBagLayout layout, int y) { + super(layout, y, "Apogee Igniter Voltage"); + } + } + + Apogee apogee; + + class Main extends AscentStatus { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4.2f V", state.main_sense)); + lights.set(state.main_sense > 3.2); + } + public Main (GridBagLayout layout, int y) { + super(layout, y, "Main Igniter Voltage"); + } + } + + Main main; + + class Lat extends AscentValue { + void show (AltosState state, int crc_errors) { + if (state.gps != null) + value.setText(pos(state.gps.lat,"N", "S")); + else + value.setText("???"); + } + public Lat (GridBagLayout layout, int y) { + super (layout, y, "Latitude"); + } + } + + Lat lat; + + class Lon extends AscentValue { + void show (AltosState state, int crc_errors) { + if (state.gps != null) + value.setText(pos(state.gps.lon,"E", "W")); + else + value.setText("???"); + } + public Lon (GridBagLayout layout, int y) { + super (layout, y, "Longitude"); + } + } + + Lon lon; + + public void reset() { + lat.reset(); + lon.reset(); + main.reset(); + apogee.reset(); + height.reset(); + speed.reset(); + accel.reset(); + } + + public void show(AltosState state, int crc_errors) { + lat.show(state, crc_errors); + lon.show(state, crc_errors); + height.show(state, crc_errors); + main.show(state, crc_errors); + apogee.show(state, crc_errors); + speed.show(state, crc_errors); + accel.show(state, crc_errors); + } + + public void labels(GridBagLayout layout, int y) { + GridBagConstraints c; + JLabel cur, max; + + cur = new JLabel("Current"); + cur.setFont(Altos.label_font); + c = new GridBagConstraints(); + c.gridx = 2; c.gridy = y; + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + layout.setConstraints(cur, c); + add(cur); + + max = new JLabel("Maximum"); + max.setFont(Altos.label_font); + c.gridx = 3; c.gridy = y; + layout.setConstraints(max, c); + add(max); + } + + public AltosAscent() { + layout = new GridBagLayout(); + + setLayout(layout); + + /* Elements in ascent display: + * + * lat + * lon + * height + */ + labels(layout, 0); + height = new Height(layout, 1); + speed = new Speed(layout, 2); + accel = new Accel(layout, 3); + lat = new Lat(layout, 4); + lon = new Lon(layout, 5); + apogee = new Apogee(layout, 6); + main = new Main(layout, 7); + } +} diff --git a/altosui/AltosCRCException.java b/altosui/AltosCRCException.java new file mode 100644 index 00000000..4a529bcf --- /dev/null +++ b/altosui/AltosCRCException.java @@ -0,0 +1,26 @@ +/* + * 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 altosui; + +public class AltosCRCException extends Exception { + public int rssi; + + public AltosCRCException (int in_rssi) { + rssi = in_rssi; + } +} diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java new file mode 100644 index 00000000..df98b2b4 --- /dev/null +++ b/altosui/AltosCSV.java @@ -0,0 +1,252 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.io.*; +import java.text.*; +import java.util.*; + +public class AltosCSV implements AltosWriter { + File name; + PrintStream out; + boolean header_written; + boolean seen_boost; + int boost_tick; + LinkedList pad_records; + AltosState state; + + static final int ALTOS_CSV_VERSION = 2; + + /* Version 2 format: + * + * General info + * version number + * serial number + * flight number + * callsign + * time (seconds since boost) + * rssi + * link quality + * + * Flight status + * state + * state name + * + * Basic sensors + * acceleration (m/s²) + * pressure (mBar) + * altitude (m) + * height (m) + * accelerometer speed (m/s) + * barometer speed (m/s) + * temp (°C) + * battery (V) + * drogue (V) + * main (V) + * + * GPS data + * connected (1/0) + * locked (1/0) + * nsat (used for solution) + * latitude (°) + * longitude (°) + * altitude (m) + * year (e.g. 2010) + * month (1-12) + * day (1-31) + * hour (0-23) + * minute (0-59) + * second (0-59) + * from_pad_dist (m) + * from_pad_azimuth (deg true) + * from_pad_range (m) + * from_pad_elevation (deg from horizon) + * hdop + * + * GPS Sat data + * C/N0 data for all 32 valid SDIDs + */ + + void write_general_header() { + out.printf("version,serial,flight,call,time,rssi,lqi"); + } + + void write_general(AltosRecord record) { + out.printf("%s, %d, %d, %s, %8.2f, %4d, %3d", + ALTOS_CSV_VERSION, record.serial, record.flight, record.callsign, + (double) record.time, + record.rssi, + record.status & 0x7f); + } + + void write_flight_header() { + out.printf("state,state_name"); + } + + void write_flight(AltosRecord record) { + out.printf("%d,%8s", record.state, record.state()); + } + + void write_basic_header() { + out.printf("acceleration,pressure,altitude,height,accel_speed,baro_speed,temperature,battery_voltage,drogue_voltage,main_voltage"); + } + + void write_basic(AltosRecord record) { + out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f", + record.acceleration(), + record.raw_pressure(), + record.raw_altitude(), + record.raw_height(), + record.accel_speed(), + state.baro_speed, + record.temperature(), + record.battery_voltage(), + record.drogue_voltage(), + record.main_voltage()); + } + + void write_gps_header() { + out.printf("connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,hdop"); + } + + void write_gps(AltosRecord record) { + AltosGPS gps = record.gps; + if (gps == null) + gps = new AltosGPS(); + + AltosGreatCircle from_pad = state.from_pad; + if (from_pad == null) + from_pad = new AltosGreatCircle(); + + out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%6d,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f", + gps.connected?1:0, + gps.locked?1:0, + gps.nsat, + gps.lat, + gps.lon, + gps.alt, + gps.year, + gps.month, + gps.day, + gps.hour, + gps.minute, + gps.second, + from_pad.distance, + state.range, + from_pad.bearing, + state.elevation, + gps.hdop); + } + + void write_gps_sat_header() { + for(int i = 1; i <= 32; i++) { + out.printf("sat%02d", i); + if (i != 32) + out.printf(","); + } + } + + void write_gps_sat(AltosRecord record) { + AltosGPS gps = record.gps; + for(int i = 1; i <= 32; i++) { + int c_n0 = 0; + if (gps != null && gps.cc_gps_sat != null) { + for(int j = 0; j < gps.cc_gps_sat.length; j++) + if (gps.cc_gps_sat[j].svid == i) { + c_n0 = gps.cc_gps_sat[j].c_n0; + break; + } + } + out.printf ("%3d", c_n0); + if (i != 32) + out.printf(","); + } + } + + void write_header() { + out.printf("#"); write_general_header(); + out.printf(","); write_flight_header(); + out.printf(","); write_basic_header(); + out.printf(","); write_gps_header(); + out.printf(","); write_gps_sat_header(); + out.printf ("\n"); + } + + void write_one(AltosRecord record) { + state = new AltosState(record, state); + write_general(record); out.printf(","); + write_flight(record); out.printf(","); + write_basic(record); out.printf(","); + write_gps(record); out.printf(","); + write_gps_sat(record); + out.printf ("\n"); + } + + void flush_pad() { + while (!pad_records.isEmpty()) { + write_one (pad_records.remove()); + } + } + + public void write(AltosRecord record) { + if (!header_written) { + write_header(); + header_written = true; + } + if (!seen_boost) { + if (record.state >= Altos.ao_flight_boost) { + seen_boost = true; + boost_tick = record.tick; + flush_pad(); + } + } + if (seen_boost) + write_one(record); + else + pad_records.add(record); + } + + public PrintStream out() { + return out; + } + + public void close() { + if (!pad_records.isEmpty()) { + boost_tick = pad_records.element().tick; + flush_pad(); + } + out.close(); + } + + public void write(AltosRecordIterable iterable) { + iterable.write_comments(out()); + for (AltosRecord r : iterable) + write(r); + } + + public AltosCSV(File in_name) throws FileNotFoundException { + name = in_name; + out = new PrintStream(name); + pad_records = new LinkedList(); + } + + public AltosCSV(String in_string) throws FileNotFoundException { + this(new File(in_string)); + } +} diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java new file mode 100644 index 00000000..e1b6002d --- /dev/null +++ b/altosui/AltosCSVUI.java @@ -0,0 +1,108 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosCSVUI + extends JDialog + implements ActionListener +{ + JFileChooser csv_chooser; + JPanel accessory; + JComboBox combo_box; + AltosRecordIterable iterable; + AltosWriter writer; + + static String[] combo_box_items = { "Comma Separated Values (.CSV)", "Googleearth Data (.KML)" }; + + void set_default_file() { + File current = csv_chooser.getSelectedFile(); + String current_name = current.getName(); + String new_name = null; + String selected = (String) combo_box.getSelectedItem(); + + if (selected.contains("CSV")) + new_name = Altos.replace_extension(current_name, ".csv"); + else if (selected.contains("KML")) + new_name = Altos.replace_extension(current_name, ".kml"); + if (new_name != null) + csv_chooser.setSelectedFile(new File(new_name)); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("comboBoxChanged")) + set_default_file(); + } + + public AltosCSVUI(JFrame frame, AltosRecordIterable in_iterable, File source_file) { + iterable = in_iterable; + csv_chooser = new JFileChooser(source_file); + + accessory = new JPanel(); + accessory.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.NONE; + c.weightx = 1; + c.weighty = 0; + c.insets = new Insets (4, 4, 4, 4); + + JLabel accessory_label = new JLabel("Export File Type"); + c.gridx = 0; + c.gridy = 0; + accessory.add(accessory_label, c); + + combo_box = new JComboBox(combo_box_items); + combo_box.addActionListener(this); + c.gridx = 0; + c.gridy = 1; + accessory.add(combo_box, c); + + csv_chooser.setAccessory(accessory); + csv_chooser.setSelectedFile(source_file); + set_default_file(); + int ret = csv_chooser.showSaveDialog(frame); + if (ret == JFileChooser.APPROVE_OPTION) { + File file = csv_chooser.getSelectedFile(); + String type = (String) combo_box.getSelectedItem(); + try { + if (type.contains("CSV")) + writer = new AltosCSV(file); + else + writer = new AltosKML(file); + writer.write(iterable); + writer.close(); + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(frame, + file.getName(), + "Cannot open file", + JOptionPane.ERROR_MESSAGE); + } + } + } +} diff --git a/altosui/AltosChannelMenu.java b/altosui/AltosChannelMenu.java new file mode 100644 index 00000000..abbb86f4 --- /dev/null +++ b/altosui/AltosChannelMenu.java @@ -0,0 +1,44 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosChannelMenu extends JComboBox implements ActionListener { + int channel; + + public AltosChannelMenu(int current_channel) { + + channel = current_channel; + + for (int c = 0; c <= 9; c++) + addItem(String.format("Channel %1d (%7.3fMHz)", c, 434.550 + c * 0.1)); + setSelectedIndex(channel); + setMaximumRowCount(10); + } + +} diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java new file mode 100644 index 00000000..1c42870f --- /dev/null +++ b/altosui/AltosConfig.java @@ -0,0 +1,295 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosConfig implements Runnable, ActionListener { + + class int_ref { + int value; + + public int get() { + return value; + } + public void set(int i) { + value = i; + } + public int_ref(int i) { + value = i; + } + } + + class string_ref { + String value; + + public String get() { + return value; + } + public void set(String i) { + value = i; + } + public string_ref(String i) { + value = i; + } + } + + JFrame owner; + AltosDevice device; + AltosSerial serial_line; + boolean remote; + Thread config_thread; + int_ref serial; + int_ref main_deploy; + int_ref apogee_delay; + int_ref radio_channel; + int_ref radio_calibration; + string_ref version; + string_ref product; + string_ref callsign; + AltosConfigUI config_ui; + boolean serial_started; + + boolean get_int(String line, String label, int_ref x) { + if (line.startsWith(label)) { + try { + String tail = line.substring(label.length()).trim(); + String[] tokens = tail.split("\\s+"); + if (tokens.length > 0) { + int i = Integer.parseInt(tokens[0]); + x.set(i); + return true; + } + } catch (NumberFormatException ne) { + } + } + return false; + } + + boolean get_string(String line, String label, string_ref s) { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + s.set(quoted); + return true; + } else { + return false; + } + } + + void start_serial() throws InterruptedException { + serial_started = true; + if (remote) { + serial_line.set_radio(); + serial_line.printf("p\nE 0\n"); + serial_line.flush_input(); + } + } + + void stop_serial() throws InterruptedException { + if (!serial_started) + return; + serial_started = false; + if (remote) { + serial_line.printf("~"); + serial_line.flush_output(); + } + } + + void get_data() throws InterruptedException, TimeoutException { + try { + start_serial(); + serial_line.printf("c s\nv\n"); + for (;;) { + String line = serial_line.get_reply(5000); + if (line == null) + throw new TimeoutException(); + get_int(line, "serial-number", serial); + get_int(line, "Main deploy:", main_deploy); + get_int(line, "Apogee delay:", apogee_delay); + get_int(line, "Radio channel:", radio_channel); + get_int(line, "Radio cal:", radio_calibration); + get_string(line, "Callsign:", callsign); + get_string(line,"software-version", version); + get_string(line,"product", product); + + /* signals the end of the version info */ + if (line.startsWith("software-version")) + break; + } + } finally { + stop_serial(); + } + } + + void init_ui () throws InterruptedException, TimeoutException { + config_ui = new AltosConfigUI(owner, remote); + config_ui.addActionListener(this); + set_ui(); + } + + void abort() { + JOptionPane.showMessageDialog(owner, + String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); + try { + stop_serial(); + } catch (InterruptedException ie) { + } + serial_line.close(); + serial_line = null; + } + + void set_ui() throws InterruptedException, TimeoutException { + if (serial_line != null) + get_data(); + config_ui.set_serial(serial.get()); + config_ui.set_product(product.get()); + config_ui.set_version(version.get()); + config_ui.set_main_deploy(main_deploy.get()); + config_ui.set_apogee_delay(apogee_delay.get()); + config_ui.set_radio_channel(radio_channel.get()); + config_ui.set_radio_calibration(radio_calibration.get()); + config_ui.set_callsign(callsign.get()); + config_ui.set_clean(); + } + + void run_dialog() { + } + + void save_data() { + main_deploy.set(config_ui.main_deploy()); + apogee_delay.set(config_ui.apogee_delay()); + radio_channel.set(config_ui.radio_channel()); + radio_calibration.set(config_ui.radio_calibration()); + callsign.set(config_ui.callsign()); + try { + start_serial(); + serial_line.printf("c m %d\n", main_deploy.get()); + serial_line.printf("c d %d\n", apogee_delay.get()); + if (!remote) { + serial_line.printf("c r %d\n", radio_channel.get()); + serial_line.printf("c f %d\n", radio_calibration.get()); + } + serial_line.printf("c c %s\n", callsign.get()); + serial_line.printf("c w\n"); + } catch (InterruptedException ie) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + try { + if (cmd.equals("Save")) { + save_data(); + set_ui(); + } else if (cmd.equals("Reset")) { + set_ui(); + } else if (cmd.equals("Reboot")) { + if (serial_line != null) { + start_serial(); + serial_line.printf("r eboot\n"); + serial_line.flush_output(); + stop_serial(); + serial_line.close(); + } + } else if (cmd.equals("Close")) { + if (serial_line != null) + serial_line.close(); + } + } catch (InterruptedException ie) { + abort(); + } catch (TimeoutException te) { + abort(); + } + } + + public void run () { + try { + init_ui(); + config_ui.make_visible(); + } catch (InterruptedException ie) { + abort(); + } catch (TimeoutException te) { + abort(); + } + } + + public AltosConfig(JFrame given_owner) { + owner = given_owner; + + serial = new int_ref(0); + main_deploy = new int_ref(250); + apogee_delay = new int_ref(0); + radio_channel = new int_ref(0); + radio_calibration = new int_ref(1186611); + callsign = new string_ref("N0CALL"); + version = new string_ref("unknown"); + product = new string_ref("unknown"); + + device = AltosDeviceDialog.show(owner, AltosDevice.product_any); + if (device != null) { + try { + serial_line = new AltosSerial(device); + if (!device.matchProduct(AltosDevice.product_telemetrum)) + remote = true; + config_thread = new Thread(this); + config_thread.start(); + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(owner, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(owner, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException ee) { + JOptionPane.showMessageDialog(owner, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } + } + } +} \ No newline at end of file diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java new file mode 100644 index 00000000..cfa5d7b9 --- /dev/null +++ b/altosui/AltosConfigUI.java @@ -0,0 +1,466 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +import libaltosJNI.*; + +public class AltosConfigUI + extends JDialog + implements ActionListener, ItemListener, DocumentListener +{ + + Container pane; + Box box; + JLabel product_label; + JLabel version_label; + JLabel serial_label; + JLabel main_deploy_label; + JLabel apogee_delay_label; + JLabel radio_channel_label; + JLabel radio_calibration_label; + JLabel callsign_label; + + public boolean dirty; + + JFrame owner; + JLabel product_value; + JLabel version_value; + JLabel serial_value; + JComboBox main_deploy_value; + JComboBox apogee_delay_value; + JComboBox radio_channel_value; + JTextField radio_calibration_value; + JTextField callsign_value; + + JButton save; + JButton reset; + JButton reboot; + JButton close; + + ActionListener listener; + + static String[] main_deploy_values = { + "100", "150", "200", "250", "300", "350", + "400", "450", "500" + }; + + static String[] apogee_delay_values = { + "0", "1", "2", "3", "4", "5" + }; + + static String[] radio_channel_values = new String[10]; + { + for (int i = 0; i <= 9; i++) + radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)", + i, 434.550 + i * 0.1); + } + + /* A window listener to catch closing events and tell the config code */ + class ConfigListener extends WindowAdapter { + AltosConfigUI ui; + + public ConfigListener(AltosConfigUI this_ui) { + ui = this_ui; + } + + public void windowClosing(WindowEvent e) { + ui.actionPerformed(new ActionEvent(e.getSource(), + ActionEvent.ACTION_PERFORMED, + "Close")); + } + } + + /* Build the UI using a grid bag */ + public AltosConfigUI(JFrame in_owner, boolean remote) { + super (in_owner, "Configure TeleMetrum", false); + + owner = in_owner; + GridBagConstraints c; + + Insets il = new Insets(4,4,4,4); + Insets ir = new Insets(4,4,4,4); + + pane = getContentPane(); + pane.setLayout(new GridBagLayout()); + + /* Product */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 0; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + product_label = new JLabel("Product:"); + pane.add(product_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 0; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + product_value = new JLabel(""); + pane.add(product_value, c); + + /* Version */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 1; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + version_label = new JLabel("Software version:"); + pane.add(version_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 1; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + version_value = new JLabel(""); + pane.add(version_value, c); + + /* Serial */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 2; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + serial_label = new JLabel("Serial:"); + pane.add(serial_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 2; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + serial_value = new JLabel(""); + pane.add(serial_value, c); + + /* Main deploy */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 3; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + main_deploy_label = new JLabel("Main Deploy Altitude(m):"); + pane.add(main_deploy_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 3; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + main_deploy_value = new JComboBox(main_deploy_values); + main_deploy_value.setEditable(true); + main_deploy_value.addItemListener(this); + pane.add(main_deploy_value, c); + + /* Apogee delay */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 4; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + apogee_delay_label = new JLabel("Apogee Delay(s):"); + pane.add(apogee_delay_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 4; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + apogee_delay_value = new JComboBox(apogee_delay_values); + apogee_delay_value.setEditable(true); + apogee_delay_value.addItemListener(this); + pane.add(apogee_delay_value, c); + + /* Radio channel */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 5; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + radio_channel_label = new JLabel("Radio Channel:"); + pane.add(radio_channel_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 5; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + radio_channel_value = new JComboBox(radio_channel_values); + radio_channel_value.setEditable(false); + radio_channel_value.addItemListener(this); + if (remote) + radio_channel_value.setEnabled(false); + pane.add(radio_channel_value, c); + + /* Radio Calibration */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 6; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + radio_calibration_label = new JLabel("RF Calibration:"); + pane.add(radio_calibration_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 6; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + radio_calibration_value = new JTextField(String.format("%d", 1186611)); + radio_calibration_value.getDocument().addDocumentListener(this); + if (remote) + radio_calibration_value.setEnabled(false); + pane.add(radio_calibration_value, c); + + /* Callsign */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 7; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + callsign_label = new JLabel("Callsign:"); + pane.add(callsign_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 7; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + callsign_value = new JTextField(AltosPreferences.callsign()); + callsign_value.getDocument().addDocumentListener(this); + pane.add(callsign_value, c); + + /* Buttons */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 8; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + save = new JButton("Save"); + pane.add(save, c); + save.addActionListener(this); + save.setActionCommand("Save"); + + c = new GridBagConstraints(); + c.gridx = 2; c.gridy = 8; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = il; + reset = new JButton("Reset"); + pane.add(reset, c); + reset.addActionListener(this); + reset.setActionCommand("Reset"); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 8; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = il; + reboot = new JButton("Reboot"); + pane.add(reboot, c); + reboot.addActionListener(this); + reboot.setActionCommand("Reboot"); + + c = new GridBagConstraints(); + c.gridx = 6; c.gridy = 8; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + c.insets = il; + close = new JButton("Close"); + pane.add(close, c); + close.addActionListener(this); + close.setActionCommand("Close"); + + addWindowListener(new ConfigListener(this)); + } + + /* Once the initial values are set, the config code will show the dialog */ + public void make_visible() { + pack(); + setLocationRelativeTo(owner); + setVisible(true); + } + + /* If any values have been changed, confirm before closing */ + public boolean check_dirty(String operation) { + if (dirty) { + Object[] options = { String.format("%s anyway", operation), "Keep editing" }; + int i; + i = JOptionPane.showOptionDialog(this, + String.format("Configuration modified. %s anyway?", operation), + "Configuration Modified", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, options, options[1]); + if (i != 0) + return false; + } + return true; + } + + /* Listen for events from our buttons */ + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if (cmd.equals("Close") || cmd.equals("Reboot")) + if (!check_dirty(cmd)) + return; + listener.actionPerformed(e); + if (cmd.equals("Close") || cmd.equals("Reboot")) { + setVisible(false); + dispose(); + } + dirty = false; + } + + /* ItemListener interface method */ + public void itemStateChanged(ItemEvent e) { + dirty = true; + } + + /* DocumentListener interface methods */ + public void changedUpdate(DocumentEvent e) { + dirty = true; + } + + public void insertUpdate(DocumentEvent e) { + dirty = true; + } + + public void removeUpdate(DocumentEvent e) { + dirty = true; + } + + /* Let the config code hook on a listener */ + public void addActionListener(ActionListener l) { + listener = l; + } + + /* set and get all of the dialog values */ + public void set_product(String product) { + product_value.setText(product); + } + + public void set_version(String version) { + version_value.setText(version); + } + + public void set_serial(int serial) { + serial_value.setText(String.format("%d", serial)); + } + + public void set_main_deploy(int new_main_deploy) { + main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy)); + } + + public int main_deploy() { + return Integer.parseInt(main_deploy_value.getSelectedItem().toString()); + } + + public void set_apogee_delay(int new_apogee_delay) { + apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay)); + } + + public int apogee_delay() { + return Integer.parseInt(apogee_delay_value.getSelectedItem().toString()); + } + + public void set_radio_channel(int new_radio_channel) { + radio_channel_value.setSelectedIndex(new_radio_channel); + } + + public int radio_channel() { + return radio_channel_value.getSelectedIndex(); + } + + public void set_radio_calibration(int new_radio_calibration) { + radio_calibration_value.setText(String.format("%d", new_radio_calibration)); + } + + public int radio_calibration() { + return Integer.parseInt(radio_calibration_value.getText()); + } + + public void set_callsign(String new_callsign) { + callsign_value.setText(new_callsign); + } + + public String callsign() { + return callsign_value.getText(); + } + + public void set_clean() { + dirty = false; + } + + } \ No newline at end of file diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java new file mode 100644 index 00000000..153c59fd --- /dev/null +++ b/altosui/AltosConfigureUI.java @@ -0,0 +1,187 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosConfigureUI + extends JDialog + 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; + + /* DocumentListener interface methods */ + public void changedUpdate(DocumentEvent e) { + AltosPreferences.set_callsign(callsign_value.getText()); + } + + public void insertUpdate(DocumentEvent e) { + changedUpdate(e); + } + + public void removeUpdate(DocumentEvent e) { + 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); + + 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 = 0; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + pane.add(new JLabel ("Configure AltOS UI"), c); + + /* Voice settings */ + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(new JLabel("Voice"), c); + + enable_voice = new JRadioButton("Enable", AltosPreferences.voice()); + enable_voice.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JRadioButton item = (JRadioButton) e.getSource(); + boolean enabled = item.isSelected(); + AltosPreferences.set_voice(enabled); + if (enabled) + voice.speak_always("Enable voice."); + else + voice.speak_always("Disable voice."); + } + }); + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 1; + c.weightx = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(enable_voice, c); + + c.gridx = 2; + c.gridy = 1; + c.gridwidth = 1; + c.weightx = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.EAST; + 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); + + /* Log directory settings */ + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(new JLabel("Log Directory"), c); + + configure_log = new JButton(AltosPreferences.logdir().getPath()); + configure_log.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + AltosPreferences.ConfigureLog(); + configure_log.setText(AltosPreferences.logdir().getPath()); + } + }); + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 2; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.WEST; + pane.add(configure_log, c); + + /* Callsign setting */ + c.gridx = 0; + c.gridy = 3; + c.gridwidth = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(new JLabel("Callsign"), c); + + callsign_value = new JTextField(AltosPreferences.callsign()); + callsign_value.getDocument().addDocumentListener(this); + c.gridx = 1; + c.gridy = 3; + c.gridwidth = 2; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.WEST; + pane.add(callsign_value, c); + + /* 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 = 4; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + pane.add(close, c); + + pack(); + setLocationRelativeTo(owner); + setVisible(true); + } +} diff --git a/altosui/AltosConvert.java b/altosui/AltosConvert.java new file mode 100644 index 00000000..8cc1df27 --- /dev/null +++ b/altosui/AltosConvert.java @@ -0,0 +1,192 @@ +/* + * 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. + */ + +/* + * Sensor data conversion functions + */ +package altosui; + +public class AltosConvert { + /* + * Pressure Sensor Model, version 1.1 + * + * written by Holly Grimes + * + * Uses the International Standard Atmosphere as described in + * "A Quick Derivation relating altitude to air pressure" (version 1.03) + * from the Portland State Aerospace Society, except that the atmosphere + * is divided into layers with each layer having a different lapse rate. + * + * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 + * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ + return 0; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted altitude */ + for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + base_pressure *= Math.pow(base, exponent); + } + base_temperature += delta_z * lapse_rate[layer_number]; + } + + /* calculate the pressure at the inputted altitude */ + delta_z = altitude - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + pressure = base_pressure * Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + pressure = base_pressure * Math.pow(base, exponent); + } + + return pressure; + } + + +/* outputs the altitude associated with the given pressure. the altitude + returned is measured with respect to the mean sea level */ + static double + pressure_to_altitude(double pressure) + { + + double next_base_temperature = LAYER0_BASE_TEMPERATURE; + double next_base_pressure = LAYER0_BASE_PRESSURE; + + double altitude; + double base_pressure; + double base_temperature; + double base; /* base for function to determine base pressure of next layer */ + double exponent; /* exponent for function to determine base pressure + of next layer */ + double coefficient; + int layer_number; /* identifies layer in the atmosphere */ + int delta_z; /* difference between two altitudes */ + + if (pressure < 0) /* illegal pressure */ + return -1; + if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ + return MAXIMUM_ALTITUDE; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted pressure. */ + layer_number = -1; + do { + layer_number++; + base_pressure = next_base_pressure; + base_temperature = next_base_temperature; + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + next_base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + next_base_pressure *= Math.pow(base, exponent); + } + next_base_temperature += delta_z * lapse_rate[layer_number]; + } + while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); + + /* calculate the altitude associated with the inputted pressure */ + if (lapse_rate[layer_number] == 0.0) { + coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) + * base_temperature; + altitude = base_altitude[layer_number] + + coefficient * Math.log(pressure / base_pressure); + } + else { + base = pressure / base_pressure; + exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] + / GRAVITATIONAL_ACCELERATION; + coefficient = base_temperature / lapse_rate[layer_number]; + altitude = base_altitude[layer_number] + + coefficient * (Math.pow(base, exponent) - 1); + } + + return altitude; + } + + static double + cc_battery_to_voltage(double battery) + { + return battery / 32767.0 * 5.0; + } + + static double + cc_ignitor_to_voltage(double ignite) + { + return ignite / 32767 * 15.0; + } +} diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java new file mode 100644 index 00000000..15de05c2 --- /dev/null +++ b/altosui/AltosDataChooser.java @@ -0,0 +1,79 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; + +public class AltosDataChooser extends JFileChooser { + JFrame frame; + String filename; + File file; + + public String filename() { + return filename; + } + + public File file() { + return file; + } + + public AltosRecordIterable runDialog() { + int ret; + + ret = showOpenDialog(frame); + if (ret == APPROVE_OPTION) { + file = getSelectedFile(); + if (file == null) + return null; + filename = file.getName(); + try { + if (filename.endsWith("eeprom")) { + FileInputStream in = new FileInputStream(file); + return new AltosEepromIterable(in); + } else if (filename.endsWith("telem")) { + FileInputStream in = new FileInputStream(file); + return new AltosTelemetryIterable(in); + } else { + throw new FileNotFoundException(); + } + } catch (FileNotFoundException fe) { + JOptionPane.showMessageDialog(frame, + filename, + "Cannot open file", + JOptionPane.ERROR_MESSAGE); + } + } + return null; + } + + public AltosDataChooser(JFrame in_frame) { + frame = in_frame; + setDialogTitle("Select Flight Record File"); + setFileFilter(new FileNameExtensionFilter("Flight data file", + "telem", "eeprom")); + setCurrentDirectory(AltosPreferences.logdir()); + } +} diff --git a/altosui/AltosDataPoint.java b/altosui/AltosDataPoint.java new file mode 100644 index 00000000..66313e03 --- /dev/null +++ b/altosui/AltosDataPoint.java @@ -0,0 +1,29 @@ + +// Copyright (c) 2010 Anthony Towns +// GPL v2 or later + +package altosui; + +interface AltosDataPoint { + int version(); + int serial(); + int flight(); + String callsign(); + double time(); + double rssi(); + + int state(); + String state_name(); + + double acceleration(); + double pressure(); + double altitude(); + double height(); + double accel_speed(); + double baro_speed(); + double temperature(); + double battery_voltage(); + double drogue_voltage(); + double main_voltage(); +} + diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java new file mode 100644 index 00000000..7704310b --- /dev/null +++ b/altosui/AltosDataPointReader.java @@ -0,0 +1,72 @@ + +// Copyright (c) 2010 Anthony Towns +// GPL v2 or later + +package altosui; + +import java.io.IOException; +import java.text.ParseException; +import java.lang.UnsupportedOperationException; +import java.util.NoSuchElementException; +import java.util.Iterator; + +class AltosDataPointReader implements Iterable { + Iterator iter; + AltosState state; + AltosRecord record; + + public AltosDataPointReader(Iterable reader) { + this.iter = reader.iterator(); + this.state = null; + } + + private void read_next_record() + throws NoSuchElementException + { + record = iter.next(); + state = new AltosState(record, state); + } + + private AltosDataPoint current_dp() { + assert this.record != null; + + return new AltosDataPoint() { + public int version() { return record.version; } + public int serial() { return record.serial; } + public int flight() { return record.flight; } + public String callsign() { return record.callsign; } + public double time() { return record.time; } + public double rssi() { return record.rssi; } + + public int state() { return record.state; } + public String state_name() { return record.state(); } + + public double acceleration() { return record.acceleration(); } + public double pressure() { return record.raw_pressure(); } + public double altitude() { return record.raw_altitude(); } + public double height() { return record.raw_height(); } + public double accel_speed() { return record.accel_speed(); } + public double baro_speed() { return state.baro_speed; } + public double temperature() { return record.temperature(); } + public double battery_voltage() { return record.battery_voltage(); } + public double drogue_voltage() { return record.drogue_voltage(); } + public double main_voltage() { return record.main_voltage(); } + }; + } + + public Iterator iterator() { + return new Iterator() { + public void remove() { + throw new UnsupportedOperationException(); + } + public boolean hasNext() { + return iter.hasNext(); + } + public AltosDataPoint next() { + read_next_record(); + return current_dp(); + } + }; + } +} + diff --git a/altosui/AltosDebug.java b/altosui/AltosDebug.java new file mode 100644 index 00000000..8d435b66 --- /dev/null +++ b/altosui/AltosDebug.java @@ -0,0 +1,267 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; + +import libaltosJNI.*; + +public class AltosDebug extends AltosSerial { + + public static final byte WR_CONFIG = 0x1d; + public static final byte RD_CONFIG = 0x24; + public static final byte CONFIG_TIMERS_OFF = (1 << 3); + public static final byte CONFIG_DMA_PAUSE = (1 << 2); + public static final byte CONFIG_TIMER_SUSPEND = (1 << 1); + public static final byte SET_FLASH_INFO_PAGE = (1 << 0); + + public static final byte GET_PC = 0x28; + public static final byte READ_STATUS = 0x34; + public static final byte STATUS_CHIP_ERASE_DONE = (byte) (1 << 7); + public static final byte STATUS_PCON_IDLE = (1 << 6); + public static final byte STATUS_CPU_HALTED = (1 << 5); + public static final byte STATUS_POWER_MODE_0 = (1 << 4); + public static final byte STATUS_HALT_STATUS = (1 << 3); + public static final byte STATUS_DEBUG_LOCKED = (1 << 2); + public static final byte STATUS_OSCILLATOR_STABLE = (1 << 1); + public static final byte STATUS_STACK_OVERFLOW = (1 << 0); + + public static final byte SET_HW_BRKPNT = 0x3b; + public static byte HW_BRKPNT_N(byte n) { return (byte) ((n) << 3); } + public static final byte HW_BRKPNT_N_MASK = (0x3 << 3); + public static final byte HW_BRKPNT_ENABLE = (1 << 2); + + public static final byte HALT = 0x44; + public static final byte RESUME = 0x4c; + public static byte DEBUG_INSTR(byte n) { return (byte) (0x54|(n)); } + public static final byte STEP_INSTR = 0x5c; + public static byte STEP_REPLACE(byte n) { return (byte) (0x64|(n)); } + public static final byte GET_CHIP_ID = 0x68; + + + boolean debug_mode; + + void ensure_debug_mode() { + if (!debug_mode) { + printf("D\n"); + flush_input(); + debug_mode = true; + } + } + + void dump_memory(String header, int address, byte[] bytes, int start, int len) { + System.out.printf("%s\n", header); + for (int j = 0; j < len; j++) { + if ((j & 15) == 0) { + if (j != 0) + System.out.printf("\n"); + System.out.printf ("%04x:", address + j); + } + System.out.printf(" %02x", bytes[start + j]); + } + System.out.printf("\n"); + } + + /* + * Write target memory + */ + public void write_memory(int address, byte[] bytes, int start, int len) { + ensure_debug_mode(); +// dump_memory("write_memory", address, bytes, start, len); + printf("O %x %x\n", len, address); + for (int i = 0; i < len; i++) + printf("%02x", bytes[start + i]); + } + + public void write_memory(int address, byte[] bytes) { + write_memory(address, bytes, 0, bytes.length); + } + + /* + * Read target memory + */ + public byte[] read_memory(int address, int length) + throws IOException, InterruptedException { + byte[] data = new byte[length]; + + flush_input(); + ensure_debug_mode(); + printf("I %x %x\n", length, address); + int i = 0; + int start = 0; + while (i < length) { + String line = get_reply().trim(); + if (!Altos.ishex(line) || line.length() % 2 != 0) + throw new IOException( + String.format + ("Invalid reply \"%s\"", line)); + int this_time = line.length() / 2; + for (int j = 0; j < this_time; j++) + data[start + j] = (byte) ((Altos.fromhex(line.charAt(j*2)) << 4) + + Altos.fromhex(line.charAt(j*2+1))); + start += this_time; + i += this_time; + } +// dump_memory("read_memory", address, data, 0, length); + + return data; + } + + /* + * Write raw bytes to the debug link using the 'P' command + */ + public void write_bytes(byte[] bytes) throws IOException { + int i = 0; + ensure_debug_mode(); + while (i < bytes.length) { + int this_time = bytes.length - i; + if (this_time > 8) + this_time = 0; + printf("P"); + for (int j = 0; j < this_time; j++) + printf(" %02x", bytes[i+j]); + printf("\n"); + i += this_time; + } + } + + public void write_byte(byte b) throws IOException { + byte[] bytes = { b }; + write_bytes(bytes); + } + + /* + * Read raw bytes from the debug link using the 'G' command + */ + public byte[] read_bytes(int length) + throws IOException, InterruptedException { + + flush_input(); + ensure_debug_mode(); + printf("G %x\n", length); + int i = 0; + byte[] data = new byte[length]; + while (i < length) { + String line = get_reply().trim(); + String tokens[] = line.split("\\s+"); + for (int j = 0; j < tokens.length; j++) { + if (!Altos.ishex(tokens[j]) || + tokens[j].length() != 2) + throw new IOException( + String.format + ("Invalid read_bytes reply \"%s\"", line)); + try { + data[i + j] = (byte) Integer.parseInt(tokens[j], 16); + } catch (NumberFormatException ne) { + throw new IOException( + String.format + ("Invalid read_bytes reply \"%s\"", line)); + } + } + i += tokens.length; + } + return data; + } + + public byte read_byte() throws IOException, InterruptedException { + return read_bytes(1)[0]; + } + + public byte debug_instr(byte[] instruction) throws IOException, InterruptedException { + byte[] command = new byte[1 + instruction.length]; + command[0] = DEBUG_INSTR((byte) instruction.length); + for (int i = 0; i < instruction.length; i++) + command[i+1] = instruction[i]; + write_bytes(command); + return read_byte(); + } + + public byte resume() throws IOException, InterruptedException { + write_byte(RESUME); + return read_byte(); + } + + public int read_uint16() throws IOException, InterruptedException { + byte[] d = read_bytes(2); + return ((int) (d[0] & 0xff) << 8) | (d[1] & 0xff); + } + + public int read_uint8() throws IOException, InterruptedException { + byte[] d = read_bytes(1); + return (int) (d[0] & 0xff); + } + + public int get_chip_id() throws IOException, InterruptedException { + write_byte(GET_CHIP_ID); + return read_uint16(); + } + + public int get_pc() throws IOException, InterruptedException { + write_byte(GET_PC); + return read_uint16(); + } + + public byte read_status() throws IOException, InterruptedException { + write_byte(READ_STATUS); + return read_byte(); + } + + static final byte LJMP = 0x02; + + public void set_pc(int pc) throws IOException, InterruptedException { + byte high = (byte) (pc >> 8); + byte low = (byte) pc; + byte[] jump_mem = { LJMP, high, low }; + debug_instr(jump_mem); + } + + public boolean check_connection() throws IOException, InterruptedException { + byte reply = read_status(); + if ((reply & STATUS_CHIP_ERASE_DONE) == 0) + return false; + if ((reply & STATUS_PCON_IDLE) != 0) + return false; + if ((reply & STATUS_POWER_MODE_0) == 0) + return false; + return true; + } + + public AltosRomconfig romconfig() { + try { + byte[] bytes = read_memory(0xa0, 10); + return new AltosRomconfig(bytes, 0); + } catch (IOException ie) { + } catch (InterruptedException ie) { + } + return new AltosRomconfig(); + } + + /* + * Reset target + */ + public void reset() { + printf ("R\n"); + } + + public AltosDebug (AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { + super(in_device); + } +} \ No newline at end of file diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java new file mode 100644 index 00000000..16ccd458 --- /dev/null +++ b/altosui/AltosDescent.java @@ -0,0 +1,353 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosDescent extends JComponent implements AltosFlightDisplay { + GridBagLayout layout; + + public abstract class DescentStatus { + JLabel label; + JTextField value; + AltosLights lights; + + abstract void show(AltosState state, int crc_errors); + void reset() { + value.setText(""); + lights.set(false); + } + + public DescentStatus (GridBagLayout layout, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.weighty = 1; + + lights = new AltosLights(); + c.gridx = 0; c.gridy = y; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(lights, c); + add(lights); + + label = new JLabel(text); + label.setFont(Altos.label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = 1; c.gridy = y; + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.VERTICAL; + c.gridwidth = 3; + c.weightx = 0; + layout.setConstraints(label, c); + add(label); + + value = new JTextField(Altos.text_width); + value.setFont(Altos.value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = 4; c.gridy = y; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + layout.setConstraints(value, c); + add(value); + + } + } + + public abstract class DescentValue { + JLabel label; + JTextField value; + + void reset() { + value.setText(""); + } + + abstract void show(AltosState state, int crc_errors); + + void show(String format, double v) { + value.setText(String.format(format, v)); + } + + void show(String v) { + value.setText(v); + } + + public DescentValue (GridBagLayout layout, int x, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.weighty = 1; + + label = new JLabel(text); + label.setFont(Altos.label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = x + 1; c.gridy = y; + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + add(label, c); + + value = new JTextField(Altos.text_width); + value.setFont(Altos.value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = x + 2; c.gridy = y; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + add(value, c); + } + } + + public abstract class DescentDualValue { + JLabel label; + JTextField value1; + JTextField value2; + + void reset() { + value1.setText(""); + value2.setText(""); + } + + abstract void show(AltosState state, int crc_errors); + void show(String v1, String v2) { + value1.setText(v1); + value2.setText(v2); + } + void show(String f1, double v1, String f2, double v2) { + value1.setText(String.format(f1, v1)); + value2.setText(String.format(f2, v2)); + } + + public DescentDualValue (GridBagLayout layout, int x, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.weighty = 1; + + label = new JLabel(text); + label.setFont(Altos.label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = x + 1; c.gridy = y; + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(label, c); + add(label); + + value1 = new JTextField(Altos.text_width); + value1.setFont(Altos.value_font); + value1.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = x + 2; c.gridy = y; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + layout.setConstraints(value1, c); + add(value1); + + value2 = new JTextField(Altos.text_width); + value2.setFont(Altos.value_font); + value2.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = x + 4; c.gridy = y; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.gridwidth = 1; + layout.setConstraints(value2, c); + add(value2); + } + } + + class Height extends DescentValue { + void show (AltosState state, int crc_errors) { + show("%6.0f m", state.height); + } + public Height (GridBagLayout layout, int x, int y) { + super (layout, x, y, "Height"); + } + } + + Height height; + + class Speed extends DescentValue { + void show (AltosState state, int crc_errors) { + double speed = state.speed; + if (!state.ascent) + speed = state.baro_speed; + show("%6.0f m/s", speed); + } + public Speed (GridBagLayout layout, int x, int y) { + super (layout, x, y, "Speed"); + } + } + + Speed speed; + + String pos(double p, String pos, String neg) { + String h = pos; + if (p < 0) { + h = neg; + p = -p; + } + int deg = (int) Math.floor(p); + double min = (p - Math.floor(p)) * 60.0; + return String.format("%s %d° %9.6f", h, deg, min); + } + + class Lat extends DescentValue { + void show (AltosState state, int crc_errors) { + if (state.gps != null) + show(pos(state.gps.lat,"N", "S")); + else + show("???"); + } + public Lat (GridBagLayout layout, int x, int y) { + super (layout, x, y, "Latitude"); + } + } + + Lat lat; + + class Lon extends DescentValue { + void show (AltosState state, int crc_errors) { + if (state.gps != null) + show(pos(state.gps.lon,"W", "E")); + else + show("???"); + } + public Lon (GridBagLayout layout, int x, int y) { + super (layout, x, y, "Longitude"); + } + } + + Lon lon; + + class Apogee extends DescentStatus { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4.2f V", state.drogue_sense)); + lights.set(state.drogue_sense > 3.2); + } + public Apogee (GridBagLayout layout, int y) { + super(layout, y, "Apogee Igniter Voltage"); + } + } + + Apogee apogee; + + class Main extends DescentStatus { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4.2f V", state.main_sense)); + lights.set(state.main_sense > 3.2); + } + public Main (GridBagLayout layout, int y) { + super(layout, y, "Main Igniter Voltage"); + } + } + + Main main; + + class Bearing extends DescentDualValue { + void show (AltosState state, int crc_errors) { + if (state.from_pad != null) { + show( String.format("%3.0f°", state.from_pad.bearing), + state.from_pad.bearing_words( + AltosGreatCircle.BEARING_LONG)); + } else { + show("???", "???"); + } + } + public Bearing (GridBagLayout layout, int x, int y) { + super (layout, x, y, "Bearing"); + } + } + + Bearing bearing; + + class Range extends DescentValue { + void show (AltosState state, int crc_errors) { + show("%6.0f m", state.range); + } + public Range (GridBagLayout layout, int x, int y) { + super (layout, x, y, "Range"); + } + } + + Range range; + + class Elevation extends DescentValue { + void show (AltosState state, int crc_errors) { + show("%3.0f°", state.elevation); + } + public Elevation (GridBagLayout layout, int x, int y) { + super (layout, x, y, "Elevation"); + } + } + + Elevation elevation; + + public void reset() { + lat.reset(); + lon.reset(); + height.reset(); + speed.reset(); + bearing.reset(); + range.reset(); + elevation.reset(); + main.reset(); + apogee.reset(); + } + + public void show(AltosState state, int crc_errors) { + height.show(state, crc_errors); + speed.show(state, crc_errors); + bearing.show(state, crc_errors); + range.show(state, crc_errors); + elevation.show(state, crc_errors); + lat.show(state, crc_errors); + lon.show(state, crc_errors); + main.show(state, crc_errors); + apogee.show(state, crc_errors); + } + + public AltosDescent() { + layout = new GridBagLayout(); + + setLayout(layout); + + /* Elements in descent display */ + speed = new Speed(layout, 0, 0); + height = new Height(layout, 2, 0); + elevation = new Elevation(layout, 0, 1); + range = new Range(layout, 2, 1); + bearing = new Bearing(layout, 0, 2); + lat = new Lat(layout, 0, 3); + lon = new Lon(layout, 2, 3); + + apogee = new Apogee(layout, 4); + main = new Main(layout, 5); + } +} diff --git a/altosui/AltosDevice.java b/altosui/AltosDevice.java new file mode 100644 index 00000000..f0fda57b --- /dev/null +++ b/altosui/AltosDevice.java @@ -0,0 +1,170 @@ +/* + * 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 altosui; +import java.lang.*; +import java.util.*; +import libaltosJNI.*; + +public class AltosDevice extends altos_device { + + 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) { + loaded_library = false; + } + initialized = true; + } + return loaded_library; + } + + static int usb_vendor_altusmetrum() { + if (load_library()) + return libaltosConstants.USB_VENDOR_ALTUSMETRUM; + return 0x000a; + } + + static int usb_product_altusmetrum() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_ALTUSMETRUM; + return 0x000a; + } + + static int usb_product_altusmetrum_min() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MIN; + return 0x000a; + } + + static int usb_product_altusmetrum_max() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MAX; + return 0x000d; + } + + static int usb_product_telemetrum() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_TELEMETRUM; + return 0x000b; + } + + static int usb_product_teledongle() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_TELEDONGLE; + return 0x000c; + } + + static int usb_product_teleterra() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_TELETERRA; + return 0x000d; + } + + public final static int vendor_altusmetrum = usb_vendor_altusmetrum(); + public final static int product_altusmetrum = usb_product_altusmetrum(); + public final static int product_telemetrum = usb_product_telemetrum(); + public final static int product_teledongle = usb_product_teledongle(); + public final static int product_teleterra = usb_product_teleterra(); + public final static int product_altusmetrum_min = usb_product_altusmetrum_min(); + public final static int product_altusmetrum_max = usb_product_altusmetrum_max(); + + + public final static int product_any = 0x10000; + public final static int product_basestation = 0x10000 + 1; + + public String toString() { + String name = getName(); + if (name == null) + name = "Altus Metrum"; + return String.format("%-20.20s %4d %s", + getName(), getSerial(), getPath()); + } + + public String toShortString() { + String name = getName(); + if (name == null) + name = "Altus Metrum"; + return String.format("%s %d %s", + name, getSerial(), getPath()); + + } + + public boolean isAltusMetrum() { + if (getVendor() != vendor_altusmetrum) + return false; + if (getProduct() < product_altusmetrum_min) + return false; + if (getProduct() > product_altusmetrum_max) + return false; + return true; + } + + public boolean matchProduct(int want_product) { + + if (!isAltusMetrum()) + return false; + + if (want_product == product_any) + return true; + + if (want_product == product_basestation) + return matchProduct(product_teledongle) || matchProduct(product_teleterra); + + int have_product = getProduct(); + + if (have_product == product_altusmetrum) /* old devices match any request */ + return true; + + if (want_product == have_product) + return true; + + return false; + } + + static AltosDevice[] list(int product) { + if (!load_library()) + return null; + + SWIGTYPE_p_altos_list list = libaltos.altos_list_start(); + + ArrayList device_list = new ArrayList(); + if (list != null) { + SWIGTYPE_p_altos_file file; + + for (;;) { + AltosDevice device = new AltosDevice(); + if (libaltos.altos_list_next(list, device) == 0) + break; + if (device.matchProduct(product)) + device_list.add(device); + } + libaltos.altos_list_finish(list); + } + + AltosDevice[] devices = new AltosDevice[device_list.size()]; + for (int i = 0; i < device_list.size(); i++) + devices[i] = device_list.get(i); + return devices; + } +} \ No newline at end of file diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java new file mode 100644 index 00000000..2966ad1e --- /dev/null +++ b/altosui/AltosDeviceDialog.java @@ -0,0 +1,164 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.util.*; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import libaltosJNI.libaltos; +import libaltosJNI.altos_device; +import libaltosJNI.SWIGTYPE_p_altos_file; +import libaltosJNI.SWIGTYPE_p_altos_list; + +public class AltosDeviceDialog extends JDialog implements ActionListener { + + private static AltosDeviceDialog dialog; + private static AltosDevice value = null; + private JList list; + + public static AltosDevice show (Component frameComp, int product) { + + Frame frame = JOptionPane.getFrameForComponent(frameComp); + AltosDevice[] devices; + devices = AltosDevice.list(product); + + if (devices != null && devices.length > 0) { + value = null; + dialog = new AltosDeviceDialog(frame, frameComp, + devices, + devices[0]); + + dialog.setVisible(true); + return value; + } else { + /* check for missing altos JNI library, which + * will put up its own error dialog + */ + if (AltosUI.load_library(frame)) { + JOptionPane.showMessageDialog(frame, + "No AltOS devices available", + "No AltOS devices", + JOptionPane.ERROR_MESSAGE); + } + return null; + } + } + + private AltosDeviceDialog (Frame frame, Component location, + AltosDevice[] devices, + AltosDevice initial) { + super(frame, "Device Selection", true); + + value = null; + + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(this); + + final JButton selectButton = new JButton("Select"); + selectButton.setActionCommand("select"); + selectButton.addActionListener(this); + getRootPane().setDefaultButton(selectButton); + + 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) { + selectButton.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(cancelButton); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(selectButton); + + //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. + list.setSelectedValue(initial, true); + pack(); + setLocationRelativeTo(location); + } + + //Handle clicks on the Set and Cancel buttons. + public void actionPerformed(ActionEvent e) { + if ("select".equals(e.getActionCommand())) + AltosDeviceDialog.value = (AltosDevice)(list.getSelectedValue()); + AltosDeviceDialog.dialog.setVisible(false); + } + +} diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java new file mode 100644 index 00000000..3e719130 --- /dev/null +++ b/altosui/AltosDisplayThread.java @@ -0,0 +1,249 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosDisplayThread extends Thread { + + Frame parent; + IdleThread idle_thread; + AltosVoice voice; + String name; + AltosFlightReader reader; + int crc_errors; + AltosFlightDisplay display; + + synchronized void show(AltosState state, int crc_errors) { + if (state != null) + display.show(state, crc_errors); + } + + class IdleThread extends Thread { + + boolean started; + private AltosState state; + int reported_landing; + int report_interval; + long report_time; + + public synchronized void report(boolean last) { + if (state == null) + return; + + /* reset the landing count once we hear about a new flight */ + if (state.state < Altos.ao_flight_drogue) + reported_landing = 0; + + /* Shut up once the rocket is on the ground */ + if (reported_landing > 2) { + return; + } + + /* If the rocket isn't on the pad, then report height */ + if (Altos.ao_flight_drogue <= state.state && + state.state < Altos.ao_flight_landed && + state.range >= 0) + { + voice.speak("Height %d, bearing %s %d, elevation %d, range %d.\n", + (int) (state.height + 0.5), + state.from_pad.bearing_words( + AltosGreatCircle.BEARING_VOICE), + (int) (state.from_pad.bearing + 0.5), + (int) (state.elevation + 0.5), + (int) (state.range + 0.5)); + } else if (state.state > Altos.ao_flight_pad) { + voice.speak("%d meters", (int) (state.height + 0.5)); + } else { + reported_landing = 0; + } + + /* If the rocket is coming down, check to see if it has landed; + * either we've got a landed report or we haven't heard from it in + * a long time + */ + if (state.state >= Altos.ao_flight_drogue && + (last || + System.currentTimeMillis() - state.report_time >= 15000 || + state.state == Altos.ao_flight_landed)) + { + if (Math.abs(state.baro_speed) < 20 && state.height < 100) + voice.speak("rocket landed safely"); + else + voice.speak("rocket may have crashed"); + if (state.from_pad != null) + voice.speak("Bearing %d degrees, range %d meters.", + (int) (state.from_pad.bearing + 0.5), + (int) (state.from_pad.distance + 0.5)); + ++reported_landing; + if (state.state != Altos.ao_flight_landed) { + state.state = Altos.ao_flight_landed; + show(state, 0); + } + } + } + + long now () { + return System.currentTimeMillis(); + } + + void set_report_time() { + report_time = now() + report_interval; + } + + public void run () { + try { + for (;;) { + set_report_time(); + for (;;) { + voice.drain(); + synchronized (this) { + long sleep_time = report_time - now(); + if (sleep_time <= 0) + break; + wait(sleep_time); + } + } + report(false); + } + } catch (InterruptedException ie) { + try { + voice.drain(); + } catch (InterruptedException iie) { } + } + } + + public synchronized void notice(AltosState new_state, boolean spoken) { + AltosState old_state = state; + state = new_state; + if (!started && state.state > Altos.ao_flight_pad) { + started = true; + start(); + } + + if (state.state < Altos.ao_flight_drogue) + report_interval = 10000; + else + report_interval = 20000; + if (old_state != null && old_state.state != state.state) { + report_time = now(); + this.notify(); + } else if (spoken) + set_report_time(); + } + + public IdleThread() { + state = null; + reported_landing = 0; + report_interval = 10000; + } + } + + boolean tell(AltosState state, AltosState old_state) { + boolean ret = false; + if (old_state == null || old_state.state != state.state) { + voice.speak(state.data.state()); + if ((old_state == null || old_state.state <= Altos.ao_flight_boost) && + state.state > Altos.ao_flight_boost) { + voice.speak("max speed: %d meters per second.", + (int) (state.max_speed + 0.5)); + ret = true; + } else if ((old_state == null || old_state.state < Altos.ao_flight_drogue) && + state.state >= Altos.ao_flight_drogue) { + voice.speak("max height: %d meters.", + (int) (state.max_height + 0.5)); + ret = true; + } + } + if (old_state == null || old_state.gps_ready != state.gps_ready) { + if (state.gps_ready) { + voice.speak("GPS ready"); + ret = true; + } + else if (old_state != null) { + voice.speak("GPS lost"); + ret = true; + } + } + old_state = state; + return ret; + } + + public void run() { + boolean interrupted = false; + String line; + AltosState state = null; + AltosState old_state = null; + boolean told; + + idle_thread = new IdleThread(); + + display.reset(); + try { + for (;;) { + try { + AltosRecord record = reader.read(); + if (record == null) + break; + old_state = state; + state = new AltosState(record, state); + reader.update(state); + show(state, crc_errors); + told = tell(state, old_state); + idle_thread.notice(state, told); + } catch (ParseException pp) { + System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); + } catch (AltosCRCException ce) { + ++crc_errors; + show(state, crc_errors); + } + } + } catch (InterruptedException ee) { + interrupted = true; + } catch (IOException ie) { + JOptionPane.showMessageDialog(parent, + String.format("Error reading from \"%s\"", name), + "Telemetry Read Error", + JOptionPane.ERROR_MESSAGE); + } finally { + if (!interrupted) + idle_thread.report(true); + reader.close(interrupted); + idle_thread.interrupt(); + try { + idle_thread.join(); + } catch (InterruptedException ie) {} + } + } + + public AltosDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) { + parent = in_parent; + voice = in_voice; + display = in_display; + reader = in_reader; + } +} diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java new file mode 100644 index 00000000..02fc36f2 --- /dev/null +++ b/altosui/AltosEepromDownload.java @@ -0,0 +1,285 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosEepromDownload implements Runnable { + + static final String[] state_names = { + "startup", + "idle", + "pad", + "boost", + "fast", + "coast", + "drogue", + "main", + "landed", + "invalid", + }; + + int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + int checksum(int[] line) { + int csum = 0x5a; + for (int i = 1; i < line.length; i++) + csum += line[i]; + return csum & 0xff; + } + + void FlushPending(FileWriter file, LinkedList pending) throws IOException { + while (!pending.isEmpty()) { + file.write(pending.remove()); + } + } + + JFrame frame; + AltosDevice device; + AltosSerial serial_line; + boolean remote; + Thread eeprom_thread; + AltosEepromMonitor monitor; + + void CaptureLog() throws IOException, InterruptedException, TimeoutException { + int serial = 0; + int block, state_block = 0; + int addr; + int flight = 0; + int year = 0, month = 0, day = 0; + int state = 0; + boolean done = false; + boolean want_file = false; + boolean any_valid; + FileWriter eeprom_file = null; + AltosFile eeprom_name; + LinkedList eeprom_pending = new LinkedList(); + + serial_line.printf("\nc s\nv\n"); + + /* Pull the serial number out of the version information */ + + for (;;) { + String line = serial_line.get_reply(5000); + + if (line == null) + throw new TimeoutException(); + if (line.startsWith("serial-number")) { + try { + serial = Integer.parseInt(line.substring(13).trim()); + } catch (NumberFormatException ne) { + serial = 0; + } + } + + eeprom_pending.add(String.format("%s\n", line)); + + /* signals the end of the version info */ + if (line.startsWith("software-version")) + break; + } + if (serial == 0) + throw new IOException("no serial number found"); + + monitor.set_serial(serial); + /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */ + + state = 0; state_block = 0; + for (block = 0; !done && block < 511; block++) { + serial_line.printf("e %x\n", block); + any_valid = false; + monitor.set_value(state_names[state], state, block - state_block); + for (addr = 0; addr < 0x100;) { + String line = serial_line.get_reply(5000); + if (line == null) + throw new TimeoutException(); + int[] values = ParseHex(line); + + if (values == null) { + System.out.printf("invalid line: %s\n", line); + continue; + } else if (values[0] != addr) { + System.out.printf("data address out of sync at 0x%x\n", + block * 256 + values[0]); + } else if (checksum(values) != 0) { + System.out.printf("invalid checksum at 0x%x\n", + block * 256 + values[0]); + } else { + any_valid = true; + int cmd = values[1]; + int tick = values[3] + (values[4] << 8); + int a = values[5] + (values[6] << 8); + int b = values[7] + (values[8] << 8); + + if (cmd == Altos.AO_LOG_FLIGHT) { + flight = b; + monitor.set_flight(flight); + } + + /* Monitor state transitions to update display */ + if (cmd == Altos.AO_LOG_STATE && a <= Altos.ao_flight_landed) { + if (a > Altos.ao_flight_pad) + want_file = true; + if (a > state) + state_block = block; + state = a; + } + + if (cmd == Altos.AO_LOG_GPS_DATE) { + year = 2000 + (a & 0xff); + month = (a >> 8) & 0xff; + day = (b & 0xff); + want_file = true; + } + + if (eeprom_file == null) { + if (serial != 0 && flight != 0 && want_file) { + if (year != 0 && month != 0 && day != 0) + eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom"); + else + eeprom_name = new AltosFile(serial, flight, "eeprom"); + + monitor.set_file(eeprom_name.getName()); + eeprom_file = new FileWriter(eeprom_name); + if (eeprom_file != null) { + FlushPending(eeprom_file, eeprom_pending); + eeprom_pending = null; + } + } + } + + String log_line = String.format("%c %4x %4x %4x\n", + cmd, tick, a, b); + if (eeprom_file != null) + eeprom_file.write(log_line); + else + eeprom_pending.add(log_line); + + if (cmd == Altos.AO_LOG_STATE && a == Altos.ao_flight_landed) { + done = true; + } + } + addr += 8; + } + if (!any_valid) + done = true; + } + if (eeprom_file == null) { + eeprom_name = new AltosFile(serial,flight,"eeprom"); + eeprom_file = new FileWriter(eeprom_name); + if (eeprom_file != null) { + FlushPending(eeprom_file, eeprom_pending); + } + } + if (eeprom_file != null) { + eeprom_file.flush(); + eeprom_file.close(); + } + } + + public void run () { + if (remote) { + serial_line.set_radio(); + serial_line.printf("p\nE 0\n"); + serial_line.flush_input(); + } + + monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed); + monitor.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + eeprom_thread.interrupt(); + } + }); + try { + CaptureLog(); + } catch (IOException ee) { + JOptionPane.showMessageDialog(frame, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + JOptionPane.showMessageDialog(frame, + String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); + } + if (remote) + serial_line.printf("~"); + monitor.done(); + serial_line.flush_output(); + serial_line.close(); + } + + public AltosEepromDownload(JFrame given_frame) { + frame = given_frame; + device = AltosDeviceDialog.show(frame, AltosDevice.product_any); + + remote = false; + + if (device != null) { + try { + serial_line = new AltosSerial(device); + if (!device.matchProduct(AltosDevice.product_telemetrum)) + remote = true; + eeprom_thread = new Thread(this); + eeprom_thread.start(); + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(frame, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(frame, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException ee) { + JOptionPane.showMessageDialog(frame, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } + } + } +} diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java new file mode 100644 index 00000000..f8e6d7e5 --- /dev/null +++ b/altosui/AltosEepromIterable.java @@ -0,0 +1,423 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * AltosRecords with an index field so they can be sorted by tick while preserving + * the original ordering for elements with matching ticks + */ +class AltosOrderedRecord extends AltosEepromRecord implements Comparable { + + public int index; + + public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) + throws ParseException { + super(line); + if (prev_tick_valid) { + tick |= (prev_tick & ~0xffff); + if (tick < prev_tick) { + if (prev_tick - tick > 0x8000) + tick += 0x10000; + } else { + if (tick - prev_tick > 0x8000) + tick -= 0x10000; + } + } + index = in_index; + } + + public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { + super(in_cmd, in_tick, in_a, in_b); + index = in_index; + } + + public int compareTo(AltosOrderedRecord o) { + int tick_diff = tick - o.tick; + if (tick_diff != 0) + return tick_diff; + return index - o.index; + } +} + +public class AltosEepromIterable extends AltosRecordIterable { + + static final int seen_flight = 1; + static final int seen_sensor = 2; + static final int seen_temp_volt = 4; + static final int seen_deploy = 8; + static final int seen_gps_time = 16; + static final int seen_gps_lat = 32; + static final int seen_gps_lon = 64; + + static final int seen_basic = seen_flight|seen_sensor|seen_temp_volt|seen_deploy; + + AltosEepromRecord flight_record; + AltosEepromRecord gps_date_record; + + TreeSet records; + + LinkedList list; + + class EepromState { + int seen; + int n_pad_samples; + double ground_pres; + int gps_tick; + int boost_tick; + + EepromState() { + seen = 0; + n_pad_samples = 0; + ground_pres = 0.0; + gps_tick = 0; + } + } + + void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { + state.tick = record.tick; + switch (record.cmd) { + case Altos.AO_LOG_FLIGHT: + eeprom.seen |= seen_flight; + state.ground_accel = record.a; + state.flight_accel = record.a; + state.flight = record.b; + eeprom.boost_tick = record.tick; + break; + case Altos.AO_LOG_SENSOR: + state.accel = record.a; + state.pres = record.b; + if (state.state < Altos.ao_flight_boost) { + eeprom.n_pad_samples++; + eeprom.ground_pres += state.pres; + state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); + state.flight_pres = state.ground_pres; + } else { + state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; + state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; + state.flight_vel += (state.accel_plus_g - state.accel); + } + eeprom.seen |= seen_sensor; + break; + case Altos.AO_LOG_TEMP_VOLT: + state.temp = record.a; + state.batt = record.b; + eeprom.seen |= seen_temp_volt; + break; + case Altos.AO_LOG_DEPLOY: + state.drogue = record.a; + state.main = record.b; + eeprom.seen |= seen_deploy; + break; + case Altos.AO_LOG_STATE: + state.state = record.a; + break; + case Altos.AO_LOG_GPS_TIME: + eeprom.gps_tick = state.tick; + AltosGPS old = state.gps; + state.gps = new AltosGPS(); + + /* GPS date doesn't get repeated through the file */ + if (old != null) { + state.gps.year = old.year; + state.gps.month = old.month; + state.gps.day = old.day; + } + state.gps.hour = (record.a & 0xff); + state.gps.minute = (record.a >> 8); + state.gps.second = (record.b & 0xff); + + int flags = (record.b >> 8); + state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0; + state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0; + state.gps.date_valid = (flags & Altos.AO_GPS_DATE_VALID) != 0; + state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >> + Altos.AO_GPS_NUM_SAT_SHIFT; + break; + case Altos.AO_LOG_GPS_LAT: + int lat32 = record.a | (record.b << 16); + state.gps.lat = (double) lat32 / 1e7; + break; + case Altos.AO_LOG_GPS_LON: + int lon32 = record.a | (record.b << 16); + state.gps.lon = (double) lon32 / 1e7; + break; + case Altos.AO_LOG_GPS_ALT: + state.gps.alt = record.a; + break; + case Altos.AO_LOG_GPS_SAT: + if (state.tick == eeprom.gps_tick) { + int svid = record.a; + int c_n0 = record.b >> 8; + state.gps.add_sat(svid, c_n0); + } + break; + case Altos.AO_LOG_GPS_DATE: + state.gps.year = (record.a & 0xff) + 2000; + state.gps.month = record.a >> 8; + state.gps.day = record.b & 0xff; + break; + + case Altos.AO_LOG_CONFIG_VERSION: + break; + case Altos.AO_LOG_MAIN_DEPLOY: + break; + case Altos.AO_LOG_APOGEE_DELAY: + break; + case Altos.AO_LOG_RADIO_CHANNEL: + break; + case Altos.AO_LOG_CALLSIGN: + state.callsign = record.data; + break; + case Altos.AO_LOG_ACCEL_CAL: + state.accel_plus_g = record.a; + state.accel_minus_g = record.b; + break; + case Altos.AO_LOG_RADIO_CAL: + break; + case Altos.AO_LOG_MANUFACTURER: + break; + case Altos.AO_LOG_PRODUCT: + break; + case Altos.AO_LOG_SERIAL_NUMBER: + state.serial = record.a; + break; + case Altos.AO_LOG_SOFTWARE_VERSION: + break; + } + } + + LinkedList make_list() { + LinkedList list = new LinkedList(); + Iterator iterator = records.iterator(); + AltosOrderedRecord record = null; + AltosRecord state = new AltosRecord(); + boolean last_reported = false; + EepromState eeprom = new EepromState(); + + state.state = Altos.ao_flight_pad; + state.accel_plus_g = 15758; + state.accel_minus_g = 16294; + + /* Pull in static data from the flight and gps_date records */ + if (flight_record != null) + update_state(state, flight_record, eeprom); + if (gps_date_record != null) + update_state(state, gps_date_record, eeprom); + + while (iterator.hasNext()) { + record = iterator.next(); + if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + } + update_state(state, record, eeprom); + } + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + return list; + } + + public Iterator iterator() { + if (list == null) + list = make_list(); + return list.iterator(); + } + + public void write_comments(PrintStream out) { + Iterator iterator = records.iterator(); + out.printf("# Comments\n"); + while (iterator.hasNext()) { + AltosOrderedRecord record = iterator.next(); + switch (record.cmd) { + case Altos.AO_LOG_CONFIG_VERSION: + out.printf("# Config version: %s\n", record.data); + break; + case Altos.AO_LOG_MAIN_DEPLOY: + out.printf("# Main deploy: %s\n", record.a); + break; + case Altos.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", record.a); + break; + case Altos.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", record.a); + break; + case Altos.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", record.data); + break; + case Altos.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", record.a, record.b); + break; + case Altos.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", record.a); + break; + case Altos.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", record.data); + break; + case Altos.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", record.data); + break; + case Altos.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", record.a); + break; + case Altos.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", record.data); + break; + } + } + } + + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + /* Make sure this looks like a good GPS value */ + if ((flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT < 4) + flags = (flags & ~Altos.AO_GPS_NUM_SAT_MASK) | (4 << Altos.AO_GPS_NUM_SAT_SHIFT); + flags |= Altos.AO_GPS_RUNNING; + flags |= Altos.AO_GPS_VALID; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + + /* + * Read the whole file, dumping records into a RB tree so + * we can enumerate them in time order -- the eeprom data + * are sometimes out of order with GPS data getting timestamps + * matching the first packet out of the GPS unit but not + * written until the final GPS packet has been received. + */ + public AltosEepromIterable (FileInputStream input) { + records = new TreeSet(); + + AltosOrderedRecord last_gps_time = null; + + int index = 0; + int prev_tick = 0; + boolean prev_tick_valid = false; + boolean missing_time = false; + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) + break; + AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); + if (record == null) + break; + if (record.cmd == Altos.AO_LOG_INVALID) + continue; + prev_tick = record.tick; + if (record.cmd < Altos.AO_LOG_CONFIG_VERSION) + prev_tick_valid = true; + if (record.cmd == Altos.AO_LOG_FLIGHT) { + flight_record = record; + continue; + } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == Altos.AO_LOG_GPS_DATE) { + gps_date_record = record; + continue; + } + + /* go back and fix up any missing time values */ + if (record.cmd == Altos.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedRecord old = iterator.next(); + if (old.cmd == Altos.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == Altos.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedRecord add_gps_time = new AltosOrderedRecord(Altos.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == Altos.AO_LOG_STATE && + record.a == Altos.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java new file mode 100644 index 00000000..7ff00ead --- /dev/null +++ b/altosui/AltosEepromMonitor.java @@ -0,0 +1,176 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosEepromMonitor extends JDialog { + + Container pane; + Box box; + JLabel serial_label; + JLabel flight_label; + JLabel file_label; + JLabel serial_value; + JLabel flight_value; + JLabel file_value; + JButton cancel; + JProgressBar pbar; + int min_state, max_state; + + public AltosEepromMonitor(JFrame owner, int in_min_state, int in_max_state) { + super (owner, "Download Flight Data", false); + + GridBagConstraints c; + Insets il = new Insets(4,4,4,4); + Insets ir = new Insets(4,4,4,4); + + 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; + serial_label = new JLabel("Serial:"); + pane.add(serial_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; + serial_value = new JLabel(""); + pane.add(serial_value, c); + + c = new GridBagConstraints(); + c.fill = GridBagConstraints.NONE; + c.gridx = 0; c.gridy = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + flight_label = new JLabel("Flight:"); + pane.add(flight_label, c); + + c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.gridx = 1; c.gridy = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + flight_value = new JLabel(""); + pane.add(flight_value, c); + + c = new GridBagConstraints(); + c.fill = GridBagConstraints.NONE; + c.gridx = 0; c.gridy = 2; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + file_label = new JLabel("File:"); + pane.add(file_label, c); + + c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.gridx = 1; c.gridy = 2; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + file_value = new JLabel(""); + pane.add(file_value, c); + + min_state = in_min_state; + max_state = in_max_state; + pbar = new JProgressBar(); + pbar.setMinimum(0); + pbar.setMaximum((max_state - min_state) * 100); + pbar.setValue(0); + pbar.setString("startup"); + pbar.setStringPainted(true); + pbar.setPreferredSize(new Dimension(600, 20)); + c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 0; c.gridy = 3; + c.gridwidth = GridBagConstraints.REMAINDER; + Insets ib = new Insets(4,4,4,4); + c.insets = ib; + pane.add(pbar, c); + + + cancel = new JButton("Cancel"); + c = new GridBagConstraints(); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 0; c.gridy = 4; + c.gridwidth = GridBagConstraints.REMAINDER; + Insets ic = new Insets(4,4,4,4); + c.insets = ic; + pane.add(cancel, c); + + pack(); + setLocationRelativeTo(owner); + setVisible(true); + } + + public void addActionListener (ActionListener l) { + cancel.addActionListener(l); + } + + public void set_value(String state_name, int in_state, int in_block) { + int block = in_block; + int state = in_state; + + if (block > 100) + block = 100; + if (state < min_state) state = min_state; + if (state >= max_state) state = max_state - 1; + state -= min_state; + + int pos = state * 100 + block; + + pbar.setString(state_name); + pbar.setValue(pos); + } + + public void set_serial(int serial) { + serial_value.setText(String.format("%d", serial)); + } + + public void set_flight(int flight) { + flight_value.setText(String.format("%d", flight)); + } + + public void set_file(String file) { + file_value.setText(String.format("%s", file)); + } + + public void done() { + setVisible(false); + dispose(); + } +} diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java new file mode 100644 index 00000000..5a673817 --- /dev/null +++ b/altosui/AltosEepromRecord.java @@ -0,0 +1,115 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosEepromRecord { + public int cmd; + public int tick; + public int a; + public int b; + public String data; + public boolean tick_valid; + + public AltosEepromRecord (String line) { + tick_valid = false; + tick = 0; + a = 0; + b = 0; + data = null; + if (line == null) { + cmd = Altos.AO_LOG_INVALID; + data = ""; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 4) { + cmd = Altos.AO_LOG_INVALID; + data = line; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + tick_valid = true; + a = Integer.parseInt(tokens[2],16); + b = Integer.parseInt(tokens[3],16); + } + } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { + cmd = Altos.AO_LOG_CONFIG_VERSION; + data = tokens[2]; + } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { + cmd = Altos.AO_LOG_MAIN_DEPLOY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { + cmd = Altos.AO_LOG_APOGEE_DELAY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { + cmd = Altos.AO_LOG_RADIO_CHANNEL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Callsign:")) { + cmd = Altos.AO_LOG_CALLSIGN; + data = tokens[1].replaceAll("\"",""); + } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { + cmd = Altos.AO_LOG_ACCEL_CAL; + a = Integer.parseInt(tokens[3]); + b = Integer.parseInt(tokens[5]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { + cmd = Altos.AO_LOG_RADIO_CAL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("manufacturer")) { + cmd = Altos.AO_LOG_MANUFACTURER; + data = tokens[1]; + } else if (tokens[0].equals("product")) { + cmd = Altos.AO_LOG_PRODUCT; + data = tokens[1]; + } else if (tokens[0].equals("serial-number")) { + cmd = Altos.AO_LOG_SERIAL_NUMBER; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("software-version")) { + cmd = Altos.AO_LOG_SOFTWARE_VERSION; + data = tokens[1]; + } else { + cmd = Altos.AO_LOG_INVALID; + data = line; + } + } catch (NumberFormatException ne) { + cmd = Altos.AO_LOG_INVALID; + data = line; + } + } + } + + public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) { + tick_valid = true; + cmd = in_cmd; + tick = in_tick; + a = in_a; + b = in_b; + } +} diff --git a/altosui/AltosFile.java b/altosui/AltosFile.java new file mode 100644 index 00000000..06360572 --- /dev/null +++ b/altosui/AltosFile.java @@ -0,0 +1,44 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.io.File; +import java.util.*; + +class AltosFile extends File { + + public AltosFile(int year, int month, int day, int serial, int flight, String extension) { + super (AltosPreferences.logdir(), + String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", + year, month, day, serial, flight, extension)); + } + + public AltosFile(int serial, int flight, String extension) { + this(Calendar.getInstance().get(Calendar.YEAR), + Calendar.getInstance().get(Calendar.MONTH) + 1, + Calendar.getInstance().get(Calendar.DAY_OF_MONTH), + serial, + flight, + extension); + } + + public AltosFile(AltosTelemetry telem) { + this(telem.serial, telem.flight, "telem"); + } +} diff --git a/altosui/AltosFlash.java b/altosui/AltosFlash.java new file mode 100644 index 00000000..3af25c23 --- /dev/null +++ b/altosui/AltosFlash.java @@ -0,0 +1,344 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosFlash { + File file; + FileInputStream input; + AltosHexfile image; + JFrame frame; + AltosDevice debug_dongle; + AltosDebug debug; + AltosRomconfig rom_config; + ActionListener listener; + boolean aborted; + + static final byte MOV_direct_data = (byte) 0x75; + static final byte MOV_DPTR_data16 = (byte) 0x90; + static final byte MOV_A_data = (byte) 0x74; + static final byte MOVX_atDPTR_A = (byte) 0xf0; + static final byte MOVX_A_atDPTR = (byte) 0xe0; + static final byte INC_DPTR = (byte) 0xa3; + static final byte TRAP = (byte) 0xa5; + + static final byte JB = (byte) 0x20; + + static final byte MOV_A_direct = (byte) 0xe5; + static final byte MOV_direct1_direct2 = (byte) 0x85; + static final byte MOV_direct_A = (byte) 0xf5; + static final byte MOV_R0_data = (byte) (0x78 | 0); + static final byte MOV_R1_data = (byte) (0x78 | 1); + static final byte MOV_R2_data = (byte) (0x78 | 2); + static final byte MOV_R3_data = (byte) (0x78 | 3); + static final byte MOV_R4_data = (byte) (0x78 | 4); + static final byte MOV_R5_data = (byte) (0x78 | 5); + static final byte MOV_R6_data = (byte) (0x78 | 6); + static final byte MOV_R7_data = (byte) (0x78 | 7); + static final byte DJNZ_R0_rel = (byte) (0xd8 | 0); + static final byte DJNZ_R1_rel = (byte) (0xd8 | 1); + static final byte DJNZ_R2_rel = (byte) (0xd8 | 2); + static final byte DJNZ_R3_rel = (byte) (0xd8 | 3); + static final byte DJNZ_R4_rel = (byte) (0xd8 | 4); + static final byte DJNZ_R5_rel = (byte) (0xd8 | 5); + static final byte DJNZ_R6_rel = (byte) (0xd8 | 6); + static final byte DJNZ_R7_rel = (byte) (0xd8 | 7); + + static final byte P1DIR = (byte) 0xFE; + static final byte P1 = (byte) 0x90; + + /* flash controller */ + static final byte FWT = (byte) 0xAB; + static final byte FADDRL = (byte) 0xAC; + static final byte FADDRH = (byte) 0xAD; + static final byte FCTL = (byte) 0xAE; + static final byte FCTL_BUSY = (byte) 0x80; + static final byte FCTL_BUSY_BIT = (byte) 7; + static final byte FCTL_SWBSY = (byte) 0x40; + static final byte FCTL_SWBSY_BIT = (byte) 6; + static final byte FCTL_CONTRD = (byte) 0x10; + static final byte FCTL_WRITE = (byte) 0x02; + static final byte FCTL_ERASE = (byte) 0x01; + static final byte FWDATA = (byte) 0xAF; + + static final byte ACC = (byte) 0xE0; + + /* offsets within the flash_page program */ + static final int FLASH_ADDR_HIGH = 8; + static final int FLASH_ADDR_LOW = 11; + static final int RAM_ADDR_HIGH = 13; + static final int RAM_ADDR_LOW = 14; + static final int FLASH_WORDS_HIGH = 16; + static final int FLASH_WORDS_LOW = 18; + static final int FLASH_TIMING = 21; + + /* sleep mode control */ + static final int SLEEP = (byte) 0xbe; + static final int SLEEP_USB_EN = (byte) 0x80; + static final int SLEEP_XOSC_STB = (byte) 0x40; + static final int SLEEP_HFRC_STB = (byte) 0x20; + static final int SLEEP_RST_MASK = (byte) 0x18; + static final int SLEEP_RST_POWERON = (byte) 0x00; + static final int SLEEP_RST_EXTERNAL = (byte) 0x10; + static final int SLEEP_RST_WATCHDOG = (byte) 0x08; + static final int SLEEP_OSC_PD = (byte) 0x04; + static final int SLEEP_MODE_MASK = (byte) 0x03; + static final int SLEEP_MODE_PM0 = (byte) 0x00; + static final int SLEEP_MODE_PM1 = (byte) 0x01; + static final int SLEEP_MODE_PM2 = (byte) 0x02; + static final int SLEEP_MODE_PM3 = (byte) 0x03; + + /* clock controller */ + static final byte CLKCON = (byte) 0xC6; + static final byte CLKCON_OSC32K = (byte) 0x80; + static final byte CLKCON_OSC = (byte) 0x40; + static final byte CLKCON_TICKSPD = (byte) 0x38; + static final byte CLKCON_CLKSPD = (byte) 0x07; + + static final byte[] flash_page_proto = { + + MOV_direct_data, P1DIR, (byte) 0x02, + MOV_direct_data, P1, (byte) 0xFF, + + MOV_direct_data, FADDRH, 0, /* FLASH_ADDR_HIGH */ + + MOV_direct_data, FADDRL, 0, /* FLASH_ADDR_LOW */ + + MOV_DPTR_data16, 0, 0, /* RAM_ADDR_HIGH, RAM_ADDR_LOW */ + + MOV_R7_data, 0, /* FLASH_WORDS_HIGH */ + + MOV_R6_data, 0, /* FLASH_WORDS_LOW */ + + + MOV_direct_data, FWT, 0x20, /* FLASH_TIMING */ + + MOV_direct_data, FCTL, FCTL_ERASE, +/* eraseWaitLoop: */ + MOV_A_direct, FCTL, + JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb, + + MOV_direct_data, P1, (byte) 0xfd, + + MOV_direct_data, FCTL, FCTL_WRITE, +/* writeLoop: */ + MOV_R5_data, 2, +/* writeWordLoop: */ + MOVX_A_atDPTR, + INC_DPTR, + MOV_direct_A, FWDATA, + DJNZ_R5_rel, (byte) 0xfa, /* writeWordLoop */ +/* writeWaitLoop: */ + MOV_A_direct, FCTL, + JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb, /* writeWaitLoop */ + DJNZ_R6_rel, (byte) 0xf1, /* writeLoop */ + DJNZ_R7_rel, (byte) 0xef, /* writeLoop */ + + MOV_direct_data, P1DIR, (byte) 0x00, + MOV_direct_data, P1, (byte) 0xFF, + TRAP, + }; + + public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) { + int flash_word_addr = flash_addr >> 1; + int flash_word_count = ((byte_count + 1) >> 1); + + byte[] flash_page = new byte[flash_page_proto.length]; + for (int i = 0; i < flash_page.length; i++) + flash_page[i] = flash_page_proto[i]; + + flash_page[FLASH_ADDR_HIGH] = (byte) (flash_word_addr >> 8); + flash_page[FLASH_ADDR_LOW] = (byte) (flash_word_addr); + flash_page[RAM_ADDR_HIGH] = (byte) (ram_addr >> 8); + flash_page[RAM_ADDR_LOW] = (byte) (ram_addr); + + byte flash_words_low = (byte) (flash_word_count); + byte flash_words_high = (byte) (flash_word_count >> 8); + /* the flashing code has a minor 'bug' */ + if (flash_words_low != 0) + flash_words_high++; + + flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high; + flash_page[FLASH_WORDS_LOW] = (byte) flash_words_low; + return flash_page; + } + + static byte[] set_clkcon_fast = { + MOV_direct_data, CLKCON, 0x00 + }; + + static byte[] get_sleep = { + MOV_A_direct, SLEEP + }; + + public void clock_init() throws IOException, InterruptedException { + debug.debug_instr(set_clkcon_fast); + + byte status; + for (int times = 0; times < 20; times++) { + Thread.sleep(1); + status = debug.debug_instr(get_sleep); + if ((status & SLEEP_XOSC_STB) != 0) + return; + } + throw new IOException("Failed to initialize target clock"); + } + + void action(String s, int percent) { + if (listener != null && !aborted) + listener.actionPerformed(new ActionEvent(this, + percent, + s)); + } + + void action(int part, int total) { + int percent = 100 * part / total; + action(String.format("%d/%d (%d%%)", + part, total, percent), + percent); + } + + void run(int pc) throws IOException, InterruptedException { + debug.set_pc(pc); + int set_pc = debug.get_pc(); + if (pc != set_pc) + throw new IOException("Failed to set target program counter"); + debug.resume(); + + for (int times = 0; times < 20; times++) { + byte status = debug.read_status(); + if ((status & AltosDebug.STATUS_CPU_HALTED) != 0) + return; + } + + throw new IOException("Failed to execute program on target"); + } + + public void flash() throws IOException, FileNotFoundException, InterruptedException { + if (!check_rom_config()) + throw new IOException("Invalid rom config settings"); + if (image.address + image.data.length > 0x8000) + throw new IOException(String.format("Flash image too long %d", + image.address + + image.data.length)); + if ((image.address & 0x3ff) != 0) + throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)", + image.address)); + int ram_address = 0xf000; + int flash_prog = 0xf400; + + /* + * Store desired config values into image + */ + rom_config.write(image); + /* + * Bring up the clock + */ + clock_init(); + + int remain = image.data.length; + int flash_addr = image.address; + int image_start = 0; + + action("start", 0); + action(0, image.data.length); + while (remain > 0 && !aborted) { + int this_time = remain; + if (this_time > 0x400) + this_time = 0x400; + + /* write the data */ + debug.write_memory(ram_address, image.data, + image_start, this_time); + + /* write the flash program */ + byte[] flash_page = make_flash_page(flash_addr, + ram_address, + this_time); + debug.write_memory(flash_prog, flash_page); + + run(flash_prog); + + byte[] check = debug.read_memory(flash_addr, this_time); + for (int i = 0; i < this_time; i++) + if (check[i] != image.data[image_start + i]) + throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)", + image.address + image_start + i, + check[i], image.data[image_start + i])); + remain -= this_time; + flash_addr += this_time; + image_start += this_time; + + action(image.data.length - remain, image.data.length); + } + if (!aborted) { + action("done", 100); + debug.set_pc(image.address); + debug.resume(); + } + debug.close(); + } + + public void abort() { + aborted = true; + debug.close(); + } + + public void addActionListener(ActionListener l) { + listener = l; + } + + public boolean check_rom_config() { + if (rom_config == null) + rom_config = debug.romconfig(); + return rom_config != null && rom_config.valid(); + } + + public void set_romconfig (AltosRomconfig romconfig) { + rom_config = romconfig; + } + + public AltosRomconfig romconfig() { + if (!check_rom_config()) + return null; + return rom_config; + } + + public AltosFlash(File in_file, AltosDevice in_debug_dongle) + throws IOException, FileNotFoundException, AltosSerialInUseException, InterruptedException { + file = in_file; + debug_dongle = in_debug_dongle; + debug = new AltosDebug(in_debug_dongle); + input = new FileInputStream(file); + image = new AltosHexfile(input); + if (!debug.check_connection()) { + debug.close(); + throw new IOException("Debug port not connected"); + } + } +} \ No newline at end of file diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java new file mode 100644 index 00000000..f63097ac --- /dev/null +++ b/altosui/AltosFlashUI.java @@ -0,0 +1,218 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosFlashUI + extends JDialog + implements Runnable, ActionListener +{ + Container pane; + Box box; + JLabel serial_label; + JLabel serial_value; + JLabel file_label; + JLabel file_value; + JProgressBar pbar; + JButton cancel; + + File file; + Thread thread; + JFrame frame; + AltosDevice debug_dongle; + AltosFlash flash; + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == cancel) { + abort(); + dispose(); + } else { + String cmd = e.getActionCommand(); + if (cmd.equals("done")) + ; + else if (cmd.equals("start")) { + setVisible(true); + } else { + pbar.setValue(e.getID()); + pbar.setString(cmd); + } + } + } + + public void run() { + try { + flash = new AltosFlash(file, debug_dongle); + flash.addActionListener(this); + AltosRomconfigUI romconfig_ui = new AltosRomconfigUI (frame); + + romconfig_ui.set(flash.romconfig()); + AltosRomconfig romconfig = romconfig_ui.showDialog(); + + if (romconfig != null && romconfig.valid()) { + flash.set_romconfig(romconfig); + serial_value.setText(String.format("%d", + flash.romconfig().serial_number)); + file_value.setText(file.toString()); + setVisible(true); + flash.flash(); + flash = null; + } + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(frame, + "Cannot open image", + file.toString(), + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(frame, + String.format("Device \"%s\" already in use", + debug_dongle.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException e) { + JOptionPane.showMessageDialog(frame, + e.getMessage(), + file.toString(), + JOptionPane.ERROR_MESSAGE); + } catch (InterruptedException ie) { + } finally { + abort(); + } + dispose(); + } + + public void abort() { + if (flash != null) + flash.abort(); + } + + public void build_dialog() { + GridBagConstraints c; + Insets il = new Insets(4,4,4,4); + Insets ir = new Insets(4,4,4,4); + + 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; + serial_label = new JLabel("Serial:"); + pane.add(serial_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; + serial_value = new JLabel(""); + pane.add(serial_value, c); + + c = new GridBagConstraints(); + c.fill = GridBagConstraints.NONE; + c.gridx = 0; c.gridy = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + file_label = new JLabel("File:"); + pane.add(file_label, c); + + c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.gridx = 1; c.gridy = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + file_value = new JLabel(""); + pane.add(file_value, c); + + pbar = new JProgressBar(); + pbar.setMinimum(0); + pbar.setMaximum(100); + pbar.setValue(0); + pbar.setString(""); + pbar.setStringPainted(true); + pbar.setPreferredSize(new Dimension(600, 20)); + c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 0; c.gridy = 2; + c.gridwidth = GridBagConstraints.REMAINDER; + Insets ib = new Insets(4,4,4,4); + c.insets = ib; + pane.add(pbar, c); + + cancel = new JButton("Cancel"); + c = new GridBagConstraints(); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 0; c.gridy = 3; + c.gridwidth = GridBagConstraints.REMAINDER; + Insets ic = new Insets(4,4,4,4); + c.insets = ic; + pane.add(cancel, c); + cancel.addActionListener(this); + pack(); + setLocationRelativeTo(frame); + } + + public AltosFlashUI(JFrame in_frame) { + super(in_frame, "Program Altusmetrum Device", false); + + frame = in_frame; + + build_dialog(); + + debug_dongle = AltosDeviceDialog.show(frame, AltosDevice.product_any); + + if (debug_dongle == null) + return; + + JFileChooser hexfile_chooser = new JFileChooser(); + + File firmwaredir = AltosPreferences.firmwaredir(); + if (firmwaredir != null) + hexfile_chooser.setCurrentDirectory(firmwaredir); + + hexfile_chooser.setDialogTitle("Select Flash Image"); + hexfile_chooser.setFileFilter(new FileNameExtensionFilter("Flash Image", "ihx")); + int returnVal = hexfile_chooser.showOpenDialog(frame); + + if (returnVal != JFileChooser.APPROVE_OPTION) + return; + + file = hexfile_chooser.getSelectedFile(); + + if (file != null) + AltosPreferences.set_firmwaredir(file.getParentFile()); + + thread = new Thread(this); + thread.start(); + } +} \ No newline at end of file diff --git a/altosui/AltosFlightDisplay.java b/altosui/AltosFlightDisplay.java new file mode 100644 index 00000000..d18d1d1f --- /dev/null +++ b/altosui/AltosFlightDisplay.java @@ -0,0 +1,24 @@ +/* + * 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 altosui; + +public interface AltosFlightDisplay { + void reset(); + + void show(AltosState state, int crc_errors); +} diff --git a/altosui/AltosFlightInfoTableModel.java b/altosui/AltosFlightInfoTableModel.java new file mode 100644 index 00000000..e23eff68 --- /dev/null +++ b/altosui/AltosFlightInfoTableModel.java @@ -0,0 +1,84 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosFlightInfoTableModel extends AbstractTableModel { + final static private String[] columnNames = {"Field", "Value"}; + + int rows; + int cols; + private String[][] data; + + public int getColumnCount() { return cols; } + public int getRowCount() { return rows; } + public String getColumnName(int col) { return columnNames[col & 1]; } + + public Object getValueAt(int row, int col) { + if (row >= rows || col >= cols) + return ""; + return data[row][col]; + } + + int[] current_row; + + public void reset() { + for (int i = 0; i < cols / 2; i++) + current_row[i] = 0; + } + + public void clear() { + reset(); + for (int c = 0; c < cols; c++) + for (int r = 0; r < rows; r++) + data[r][c] = ""; + fireTableDataChanged(); + } + + public void addRow(int col, String name, String value) { + if (current_row[col] < rows) { + data[current_row[col]][col * 2] = name; + data[current_row[col]][col * 2 + 1] = value; + } + current_row[col]++; + } + + public void finish() { + for (int c = 0; c < cols / 2; c++) + while (current_row[c] < rows) + addRow(c, "", ""); + fireTableDataChanged(); + } + + public AltosFlightInfoTableModel (int in_rows, int in_cols) { + rows = in_rows; + cols = in_cols * 2; + data = new String[rows][cols]; + current_row = new int[in_cols]; + } +} diff --git a/altosui/AltosFlightReader.java b/altosui/AltosFlightReader.java new file mode 100644 index 00000000..3d59de9a --- /dev/null +++ b/altosui/AltosFlightReader.java @@ -0,0 +1,38 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.io.*; + +public class AltosFlightReader { + String name; + + int serial; + + void init() { } + + AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } + + void close(boolean interrupted) { } + + void set_channel(int channel) { } + + void update(AltosState state) throws InterruptedException { } +} diff --git a/altosui/AltosFlightStatus.java b/altosui/AltosFlightStatus.java new file mode 100644 index 00000000..59c9e9db --- /dev/null +++ b/altosui/AltosFlightStatus.java @@ -0,0 +1,154 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosFlightStatus extends JComponent implements AltosFlightDisplay { + GridBagLayout layout; + + public class FlightValue { + JLabel label; + JTextField value; + + void show(AltosState state, int crc_errors) {} + + void reset() { + value.setText(""); + } + public FlightValue (GridBagLayout layout, int x, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(5, 5, 5, 5); + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + + label = new JLabel(text); + label.setFont(Altos.status_font); + label.setHorizontalAlignment(SwingConstants.CENTER); + c.gridx = x; c.gridy = 0; + layout.setConstraints(label, c); + add(label); + + value = new JTextField(""); + value.setFont(Altos.status_font); + value.setHorizontalAlignment(SwingConstants.CENTER); + c.gridx = x; c.gridy = 1; + layout.setConstraints(value, c); + add(value); + } + } + + class Call extends FlightValue { + void show(AltosState state, int crc_errors) { + value.setText(state.data.callsign); + } + public Call (GridBagLayout layout, int x) { + super (layout, x, "Callsign"); + } + } + + Call call; + + class Serial extends FlightValue { + void show(AltosState state, int crc_errors) { + value.setText(String.format("%d", state.data.serial)); + } + public Serial (GridBagLayout layout, int x) { + super (layout, x, "Serial"); + } + } + + Serial serial; + + class Flight extends FlightValue { + void show(AltosState state, int crc_errors) { + value.setText(String.format("%d", state.data.flight)); + } + public Flight (GridBagLayout layout, int x) { + super (layout, x, "Flight"); + } + } + + Flight flight; + + class FlightState extends FlightValue { + void show(AltosState state, int crc_errors) { + value.setText(state.data.state()); + } + public FlightState (GridBagLayout layout, int x) { + super (layout, x, "State"); + } + } + + FlightState flight_state; + + class RSSI extends FlightValue { + void show(AltosState state, int crc_errors) { + value.setText(String.format("%d", state.data.rssi)); + } + public RSSI (GridBagLayout layout, int x) { + super (layout, x, "RSSI (dBm)"); + } + } + + RSSI rssi; + + public void reset () { + call.reset(); + serial.reset(); + flight.reset(); + flight_state.reset(); + rssi.reset(); + } + + public void show (AltosState state, int crc_errors) { + call.show(state, crc_errors); + serial.show(state, crc_errors); + flight.show(state, crc_errors); + flight_state.show(state, crc_errors); + rssi.show(state, crc_errors); + } + + public int height() { + Dimension d = layout.preferredLayoutSize(this); + return d.height; + } + + public AltosFlightStatus() { + layout = new GridBagLayout(); + + setLayout(layout); + + call = new Call(layout, 0); + serial = new Serial(layout, 1); + flight = new Flight(layout, 2); + flight_state = new FlightState(layout, 3); + rssi = new RSSI(layout, 4); + } +} diff --git a/altosui/AltosFlightStatusTableModel.java b/altosui/AltosFlightStatusTableModel.java new file mode 100644 index 00000000..4c24b6ac --- /dev/null +++ b/altosui/AltosFlightStatusTableModel.java @@ -0,0 +1,61 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosFlightStatusTableModel extends AbstractTableModel { + private String[] columnNames = {"Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" }; + private Object[] data = { 0, "idle", 0, 0 }; + + public int getColumnCount() { return columnNames.length; } + public int getRowCount() { return 2; } + public Object getValueAt(int row, int col) { + if (row == 0) + return columnNames[col]; + return data[col]; + } + + public void setValueAt(Object value, int col) { + data[col] = value; + fireTableCellUpdated(1, col); + } + + public void setValueAt(Object value, int row, int col) { + setValueAt(value, col); + } + + public void set(AltosState state) { + setValueAt(String.format("%1.0f", state.height), 0); + setValueAt(state.data.state(), 1); + setValueAt(state.data.rssi, 2); + double speed = state.baro_speed; + if (state.ascent) + speed = state.speed; + setValueAt(String.format("%1.0f", speed), 3); + } +} diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java new file mode 100644 index 00000000..24d25bd7 --- /dev/null +++ b/altosui/AltosFlightUI.java @@ -0,0 +1,221 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosFlightUI extends JFrame implements AltosFlightDisplay { + String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" }; + Object[][] statusData = { { "0", "pad", "-50", "0" } }; + + AltosVoice voice; + AltosFlightReader reader; + AltosDisplayThread thread; + + JTabbedPane pane; + + AltosPad pad; + AltosAscent ascent; + AltosDescent descent; + AltosLanded landed; + AltosSiteMap sitemap; + + private AltosFlightStatus flightStatus; + private AltosInfoTable flightInfo; + + static final int tab_pad = 1; + static final int tab_ascent = 2; + static final int tab_descent = 3; + static final int tab_landed = 4; + + int cur_tab = 0; + + boolean exit_on_close = false; + + int which_tab(AltosState state) { + if (state.state < Altos.ao_flight_boost) + return tab_pad; + if (state.state <= Altos.ao_flight_coast) + return tab_ascent; + if (state.state <= Altos.ao_flight_main) + return tab_descent; + return tab_landed; + } + + void stop_display() { + if (thread != null && thread.isAlive()) { + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException ie) {} + } + thread = null; + } + + void disconnect() { + stop_display(); + } + + public void reset() { + pad.reset(); + ascent.reset(); + descent.reset(); + landed.reset(); + flightInfo.clear(); + sitemap.reset(); + } + + public void show(AltosState state, int crc_errors) { + int tab = which_tab(state); + pad.show(state, crc_errors); + ascent.show(state, crc_errors); + descent.show(state, crc_errors); + landed.show(state, crc_errors); + if (tab != cur_tab) { + switch (tab) { + case tab_pad: + pane.setSelectedComponent(pad); + break; + case tab_ascent: + pane.setSelectedComponent(ascent); + break; + case tab_descent: + pane.setSelectedComponent(descent); + break; + case tab_landed: + pane.setSelectedComponent(landed); + } + cur_tab = tab; + } + flightStatus.show(state, crc_errors); + flightInfo.show(state, crc_errors); + sitemap.show(state, crc_errors); + } + + public void set_exit_on_close() { + exit_on_close = true; + } + + Container bag; + JComboBox channels; + + public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) { + AltosPreferences.init(this); + + voice = in_voice; + reader = in_reader; + + bag = getContentPane(); + bag.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + + java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg"); + if (imgURL != null) + setIconImage(new ImageIcon(imgURL).getImage()); + + setTitle(String.format("AltOS %s", reader.name)); + + /* Stick channel selector at top of table for telemetry monitoring */ + if (serial >= 0) { + // Channel menu + channels = new AltosChannelMenu(AltosPreferences.channel(serial)); + channels.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int channel = channels.getSelectedIndex(); + reader.set_channel(channel); + } + }); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.WEST; + bag.add (channels, c); + } + + /* Flight status is always visible */ + flightStatus = new AltosFlightStatus(); + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + bag.add(flightStatus, c); + + /* The rest of the window uses a tabbed pane to + * show one of the alternate data views + */ + pane = new JTabbedPane(); + + pad = new AltosPad(); + pane.add("Launch Pad", pad); + + ascent = new AltosAscent(); + pane.add("Ascent", ascent); + + descent = new AltosDescent(); + pane.add("Descent", descent); + + landed = new AltosLanded(); + pane.add("Landed", landed); + + flightInfo = new AltosInfoTable(); + pane.add("Table", new JScrollPane(flightInfo)); + + sitemap = new AltosSiteMap(); + pane.add("Site Map", sitemap); + + /* Make the tabbed pane use the rest of the window space */ + c.gridx = 0; + c.gridy = 2; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + bag.add(pane, c); + + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + disconnect(); + setVisible(false); + dispose(); + if (exit_on_close) + System.exit(0); + } + }); + + pack(); + setVisible(true); + + thread = new AltosDisplayThread(this, voice, this, reader); + + thread.start(); + } + + public AltosFlightUI (AltosVoice in_voice, AltosFlightReader in_reader) { + this(in_voice, in_reader, -1); + } +} diff --git a/altosui/AltosGPS.java b/altosui/AltosGPS.java new file mode 100644 index 00000000..83821842 --- /dev/null +++ b/altosui/AltosGPS.java @@ -0,0 +1,215 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; + +public class AltosGPS { + public class AltosGPSSat { + int svid; + int c_n0; + } + + int nsat; + boolean locked; + boolean connected; + boolean date_valid; + double lat; /* degrees (+N -S) */ + double lon; /* degrees (+E -W) */ + int alt; /* m */ + int year; + int month; + int day; + int hour; + int minute; + int second; + + int gps_extended; /* has extra data */ + double ground_speed; /* m/s */ + int course; /* degrees */ + double climb_rate; /* m/s */ + double hdop; /* unitless? */ + int h_error; /* m */ + int v_error; /* m */ + + AltosGPSSat[] cc_gps_sat; /* tracking data */ + + void ParseGPSDate(String date) throws ParseException { + String[] ymd = date.split("-"); + if (ymd.length != 3) + throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); + year = AltosParse.parse_int(ymd[0]); + month = AltosParse.parse_int(ymd[1]); + day = AltosParse.parse_int(ymd[2]); + } + + void ParseGPSTime(String time) throws ParseException { + String[] hms = time.split(":"); + if (hms.length != 3) + throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); + hour = AltosParse.parse_int(hms[0]); + minute = AltosParse.parse_int(hms[1]); + second = AltosParse.parse_int(hms[2]); + } + + void ClearGPSTime() { + year = month = day = 0; + hour = minute = second = 0; + } + + public AltosGPS(String[] words, int i, int version) throws ParseException { + AltosParse.word(words[i++], "GPS"); + nsat = AltosParse.parse_int(words[i++]); + AltosParse.word(words[i++], "sat"); + + connected = false; + locked = false; + lat = lon = 0; + alt = 0; + ClearGPSTime(); + if ((words[i]).equals("unlocked")) { + connected = true; + i++; + } else if ((words[i]).equals("not-connected")) { + i++; + } else if (words.length >= 40) { + locked = true; + connected = true; + + if (version > 1) + ParseGPSDate(words[i++]); + else + year = month = day = 0; + ParseGPSTime(words[i++]); + lat = AltosParse.parse_coord(words[i++]); + lon = AltosParse.parse_coord(words[i++]); + alt = AltosParse.parse_int(words[i++]); + if (version > 1 || (i < words.length && !words[i].equals("SAT"))) { + ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)")); + course = AltosParse.parse_int(words[i++]); + climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)")); + hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)")); + h_error = AltosParse.parse_int(words[i++]); + v_error = AltosParse.parse_int(words[i++]); + } + } else { + i++; + } + if (i < words.length) { + AltosParse.word(words[i++], "SAT"); + int tracking_channels = 0; + if (words[i].equals("not-connected")) + tracking_channels = 0; + else + tracking_channels = AltosParse.parse_int(words[i]); + i++; + cc_gps_sat = new AltosGPS.AltosGPSSat[tracking_channels]; + for (int chan = 0; chan < tracking_channels; chan++) { + cc_gps_sat[chan] = new AltosGPS.AltosGPSSat(); + cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); + /* Older versions included SiRF status bits */ + if (version < 2) + i++; + cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); + } + } else + cc_gps_sat = new AltosGPS.AltosGPSSat[0]; + } + + public void set_latitude(int in_lat) { + lat = in_lat / 10.0e7; + } + + public void set_longitude(int in_lon) { + lon = in_lon / 10.0e7; + } + + public void set_time(int hour, int minute, int second) { + hour = hour; + minute = minute; + second = second; + } + + public void set_date(int year, int month, int day) { + year = year; + month = month; + day = day; + } + + public void set_flags(int flags) { + flags = flags; + } + + public void set_altitude(int altitude) { + altitude = altitude; + } + + public void add_sat(int svid, int c_n0) { + if (cc_gps_sat == null) { + cc_gps_sat = new AltosGPS.AltosGPSSat[1]; + } else { + AltosGPSSat[] new_gps_sat = new AltosGPS.AltosGPSSat[cc_gps_sat.length + 1]; + for (int i = 0; i < cc_gps_sat.length; i++) + new_gps_sat[i] = cc_gps_sat[i]; + cc_gps_sat = new_gps_sat; + } + AltosGPS.AltosGPSSat sat = new AltosGPS.AltosGPSSat(); + sat.svid = svid; + sat.c_n0 = c_n0; + cc_gps_sat[cc_gps_sat.length - 1] = sat; + } + + public AltosGPS() { + ClearGPSTime(); + cc_gps_sat = null; + } + + public AltosGPS(AltosGPS old) { + nsat = old.nsat; + locked = old.locked; + connected = old.connected; + date_valid = old.date_valid; + lat = old.lat; /* degrees (+N -S) */ + lon = old.lon; /* degrees (+E -W) */ + alt = old.alt; /* m */ + year = old.year; + month = old.month; + day = old.day; + hour = old.hour; + minute = old.minute; + second = old.second; + + gps_extended = old.gps_extended; /* has extra data */ + ground_speed = old.ground_speed; /* m/s */ + course = old.course; /* degrees */ + climb_rate = old.climb_rate; /* m/s */ + hdop = old.hdop; /* unitless? */ + h_error = old.h_error; /* m */ + v_error = old.v_error; /* m */ + + if (old.cc_gps_sat != null) { + cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; + for (int i = 0; i < old.cc_gps_sat.length; i++) { + cc_gps_sat[i] = new AltosGPSSat(); + cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; + cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; + } + } + } +} diff --git a/altosui/AltosGraph.java b/altosui/AltosGraph.java new file mode 100644 index 00000000..58c27979 --- /dev/null +++ b/altosui/AltosGraph.java @@ -0,0 +1,25 @@ + +// Copyright (c) 2010 Anthony Towns +// GPL v2 or later + +package altosui; + +import java.io.*; + +import org.jfree.chart.JFreeChart; +import org.jfree.chart.ChartUtilities; + +abstract class AltosGraph { + public String filename; + public abstract void addData(AltosDataPoint d); + public abstract JFreeChart createChart(); + public void toPNG() throws java.io.IOException { toPNG(300, 500); } + public void toPNG(int width, int height) + throws java.io.IOException + { + File pngout = new File(filename); + JFreeChart chart = createChart(); + ChartUtilities.saveChartAsPNG(pngout, chart, width, height); + System.out.println("Created " + filename); + } +} diff --git a/altosui/AltosGraphTime.java b/altosui/AltosGraphTime.java new file mode 100644 index 00000000..a5451280 --- /dev/null +++ b/altosui/AltosGraphTime.java @@ -0,0 +1,233 @@ + +// Copyright (c) 2010 Anthony Towns +// GPL v2 or later + +package altosui; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.HashMap; + +import org.jfree.chart.ChartUtilities; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.AxisLocation; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.labels.StandardXYToolTipGenerator; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.plot.ValueMarker; +import org.jfree.chart.renderer.xy.StandardXYItemRenderer; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.ui.RectangleAnchor; +import org.jfree.ui.TextAnchor; + +class AltosGraphTime extends AltosGraph { + static interface Element { + void attachGraph(AltosGraphTime g); + void gotTimeData(double time, AltosDataPoint d); + void addToPlot(AltosGraphTime g, XYPlot plot); + } + + static class TimeAxis implements Element { + private int axis; + private Color color; + private String label; + private AxisLocation locn; + private double min_y = Double.NaN; + + public TimeAxis(int axis, String label, Color color, AxisLocation locn) + { + this.axis = axis; + this.color = color; + this.label = label; + this.locn = locn; + } + + public void setLowerBound(double min_y) { + this.min_y = min_y; + } + + public void attachGraph(AltosGraphTime g) { return; } + public void gotTimeData(double time, AltosDataPoint d) { return; } + + public void addToPlot(AltosGraphTime g, XYPlot plot) { + NumberAxis numAxis = new NumberAxis(label); + if (!Double.isNaN(min_y)) + numAxis.setLowerBound(min_y); + plot.setRangeAxis(axis, numAxis); + plot.setRangeAxisLocation(axis, locn); + numAxis.setLabelPaint(color); + numAxis.setTickLabelPaint(color); + numAxis.setAutoRangeIncludesZero(false); + } + } + + abstract static class TimeSeries implements Element { + protected XYSeries series; + private String axisName; + private Color color; + + public TimeSeries(String axisName, String label, Color color) { + this.series = new XYSeries(label); + this.axisName = axisName; + this.color = color; + } + + public void attachGraph(AltosGraphTime g) { + g.setAxis(this, axisName, color); + } + abstract public void gotTimeData(double time, AltosDataPoint d); + + public void addToPlot(AltosGraphTime g, XYPlot plot) { + XYSeriesCollection dataset = new XYSeriesCollection(); + dataset.addSeries(this.series); + + XYItemRenderer renderer = new StandardXYItemRenderer(); + renderer.setSeriesPaint(0, color); + + int dataNum = g.getDataNum(this); + int axisNum = g.getAxisNum(this); + + plot.setDataset(dataNum, dataset); + plot.mapDatasetToRangeAxis(dataNum, axisNum); + plot.setRenderer(dataNum, renderer); + } + } + + static class StateMarker implements Element { + private double val = Double.NaN; + private String name; + private int state; + + StateMarker(int state, String name) { + this.state = state; + this.name = name; + } + + public void attachGraph(AltosGraphTime g) { return; } + public void gotTimeData(double time, AltosDataPoint d) { + if (Double.isNaN(val) || time < val) { + if (d.state() == state) { + val = time; + } + } + } + + public void addToPlot(AltosGraphTime g, XYPlot plot) { + if (Double.isNaN(val)) + return; + + ValueMarker m = new ValueMarker(val); + m.setLabel(name); + m.setLabelAnchor(RectangleAnchor.TOP_RIGHT); + m.setLabelTextAnchor(TextAnchor.TOP_LEFT); + plot.addDomainMarker(m); + } + } + + private String callsign = null; + private Integer serial = null; + private Integer flight = null; + + private String title; + private ArrayList elements; + private HashMap axes; + private HashMap datasets; + private ArrayList datasetAxis; + + public AltosGraphTime(String title) { + this.filename = title.toLowerCase().replaceAll("[^a-z0-9]","_")+".png"; + this.title = title; + this.elements = new ArrayList(); + this.axes = new HashMap(); + this.datasets = new HashMap(); + this.datasetAxis = new ArrayList(); + } + + public AltosGraphTime addElement(Element e) { + e.attachGraph(this); + elements.add(e); + return this; + } + + public void setAxis(Element ds, String axisName, Color color) { + Integer axisNum = axes.get(axisName); + int dsNum = datasetAxis.size(); + if (axisNum == null) { + axisNum = newAxis(axisName, color); + } + datasets.put(ds, dsNum); + datasetAxis.add(axisNum); + } + + public int getAxisNum(Element ds) { + return datasetAxis.get( datasets.get(ds) ).intValue(); + } + public int getDataNum(Element ds) { + return datasets.get(ds).intValue(); + } + + private Integer newAxis(String name, Color color) { + int cnt = axes.size(); + AxisLocation locn = AxisLocation.BOTTOM_OR_LEFT; + if (cnt > 0) { + locn = AxisLocation.TOP_OR_RIGHT; + } + Integer res = new Integer(cnt); + axes.put(name, res); + this.addElement(new TimeAxis(cnt, name, color, locn)); + return res; + } + + public void addData(AltosDataPoint d) { + double time = d.time(); + for (Element e : elements) { + e.gotTimeData(time, d); + } + if (callsign == null) callsign = d.callsign(); + if (serial == null) serial = new Integer(d.serial()); + if (flight == null) flight = new Integer(d.flight()); + } + + public JFreeChart createChart() { + NumberAxis xAxis = new NumberAxis("Time (s)"); + xAxis.setAutoRangeIncludesZero(false); + XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false); + XYPlot plot = new XYPlot(); + plot.setDomainAxis(xAxis); + plot.setRenderer(renderer); + plot.setOrientation(PlotOrientation.VERTICAL); + + if (serial != null && flight != null) { + title = serial + "/" + flight + ": " + title; + } + if (callsign != null) { + title = callsign + " - " + title; + } + + renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator()); + JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, + plot, true); + ChartUtilities.applyCurrentTheme(chart); + + plot.setDomainPannable(true); + plot.setRangePannable(true); + + for (Element e : elements) { + e.addToPlot(this, plot); + } + + return chart; + } + + public void toPNG() throws java.io.IOException { + if (axes.size() > 1) { + toPNG(800, 500); + } else { + toPNG(300, 500); + } + } +} diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java new file mode 100644 index 00000000..cd158651 --- /dev/null +++ b/altosui/AltosGraphUI.java @@ -0,0 +1,274 @@ + +// Copyright (c) 2010 Anthony Towns +// GPL v2 or later + +package altosui; + +import java.io.*; +import java.util.ArrayList; + +import javax.swing.JFrame; +import java.awt.Color; + +import org.jfree.chart.ChartPanel; +import org.jfree.chart.ChartUtilities; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.AxisLocation; +import org.jfree.ui.ApplicationFrame; +import org.jfree.ui.RefineryUtilities; + +public class AltosGraphUI extends JFrame +{ + static final private Color red = new Color(194,31,31); + static final private Color green = new Color(31,194,31); + static final private Color blue = new Color(31,31,194); + static final private Color black = new Color(31,31,31); + + static private class OverallGraphs { + AltosGraphTime.Element height = + new AltosGraphTime.TimeSeries("Height (m)", "Height (AGL)", red) { + public void gotTimeData(double time, AltosDataPoint d) { + series.add(time, d.height()); + } + }; + + AltosGraphTime.Element speed = + new AltosGraphTime.TimeSeries("Speed (m/s)", "Vertical Speed", green) { + public void gotTimeData(double time, AltosDataPoint d) { + if (d.state() < Altos.ao_flight_drogue) { + series.add(time, d.accel_speed()); + } else { + series.add(time, d.baro_speed()); + } + } + }; + + AltosGraphTime.Element acceleration = + new AltosGraphTime.TimeSeries("Acceleration (m/s\u00B2)", + "Axial Acceleration", blue) + { + public void gotTimeData(double time, AltosDataPoint d) { + series.add(time, d.acceleration()); + } + }; + + AltosGraphTime.Element temperature = + new AltosGraphTime.TimeSeries("Temperature (\u00B0C)", + "Board temperature", red) + { + public void gotTimeData(double time, AltosDataPoint d) { + series.add(time, d.temperature()); + } + }; + + AltosGraphTime.Element drogue_voltage = + new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", blue) + { + public void gotTimeData(double time, AltosDataPoint d) { + series.add(time, d.drogue_voltage()); + } + }; + + AltosGraphTime.Element main_voltage = + new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", green) + { + public void gotTimeData(double time, AltosDataPoint d) { + series.add(time, d.main_voltage()); + } + }; + + AltosGraphTime.Element e_pad = new AltosGraphTime.StateMarker(Altos.ao_flight_pad, "Pad"); + AltosGraphTime.Element e_boost = new AltosGraphTime.StateMarker(Altos.ao_flight_boost, "Boost"); + AltosGraphTime.Element e_fast = new AltosGraphTime.StateMarker(Altos.ao_flight_fast, "Fast"); + AltosGraphTime.Element e_coast = new AltosGraphTime.StateMarker(Altos.ao_flight_coast, "Coast"); + AltosGraphTime.Element e_drogue = new AltosGraphTime.StateMarker(Altos.ao_flight_drogue, "Drogue"); + AltosGraphTime.Element e_main = new AltosGraphTime.StateMarker(Altos.ao_flight_main, "Main"); + AltosGraphTime.Element e_landed = new AltosGraphTime.StateMarker(Altos.ao_flight_landed, "Landed"); + + protected AltosGraphTime myAltosGraphTime(String suffix) { + return (new AltosGraphTime("Overall " + suffix)) + .addElement(e_boost) + .addElement(e_drogue) + .addElement(e_main) + .addElement(e_landed); + } + + public ArrayList graphs() { + ArrayList graphs = new ArrayList(); + + graphs.add( myAltosGraphTime("Summary") + .addElement(height) + .addElement(speed) + .addElement(acceleration) ); + + graphs.add( myAltosGraphTime("Altitude") + .addElement(height) ); + + graphs.add( myAltosGraphTime("Speed") + .addElement(speed) ); + + graphs.add( myAltosGraphTime("Acceleration") + .addElement(acceleration) ); + + graphs.add( myAltosGraphTime("Temperature") + .addElement(temperature) ); + + graphs.add( myAltosGraphTime("Continuity") + .addElement(drogue_voltage) + .addElement(main_voltage) ); + + return graphs; + } + } + + static private class AscentGraphs extends OverallGraphs { + protected AltosGraphTime myAltosGraphTime(String suffix) { + return (new AltosGraphTime("Ascent " + suffix) { + public void addData(AltosDataPoint d) { + int state = d.state(); + if (Altos.ao_flight_boost <= state && state <= Altos.ao_flight_coast) { + super.addData(d); + } + } + }).addElement(e_boost) + .addElement(e_fast) + .addElement(e_coast); + } + } + + static private class DescentGraphs extends OverallGraphs { + protected AltosGraphTime myAltosGraphTime(String suffix) { + return (new AltosGraphTime("Descent " + suffix) { + public void addData(AltosDataPoint d) { + int state = d.state(); + if (Altos.ao_flight_drogue <= state && state <= Altos.ao_flight_main) { + super.addData(d); + } + } + }).addElement(e_drogue) + .addElement(e_main); + // ((XYGraph)graph[8]).ymin = new Double(-50); + } + } + + public AltosGraphUI(AltosRecordIterable records) { + super("Altos Graph"); + + Iterable reader = new AltosDataPointReader (records); + if (reader == null) + return; + + init(reader, 0); + } + + public AltosGraphUI(Iterable data, int which) + { + super("Altos Graph"); + init(data, which); + } + + private void init(Iterable data, int which) { + AltosGraph graph = createGraph(data, which); + + JFreeChart chart = graph.createChart(); + ChartPanel chartPanel = new ChartPanel(chart); + chartPanel.setMouseWheelEnabled(true); + chartPanel.setPreferredSize(new java.awt.Dimension(800, 500)); + setContentPane(chartPanel); + + pack(); + + RefineryUtilities.centerFrameOnScreen(this); + + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + setVisible(true); + } + + private static AltosGraph createGraph(Iterable data, + int which) + { + return createGraphsWhich(data, which).get(0); + } + + private static ArrayList createGraphs( + Iterable data) + { + return createGraphsWhich(data, -1); + } + + private static ArrayList createGraphsWhich( + Iterable data, int which) + { + ArrayList graph = new ArrayList(); + graph.addAll((new OverallGraphs()).graphs()); + graph.addAll((new AscentGraphs()).graphs()); + graph.addAll((new DescentGraphs()).graphs()); + + if (which > 0) { + if (which >= graph.size()) { + which = 0; + } + AltosGraph g = graph.get(which); + graph = new ArrayList(); + graph.add(g); + } + + for (AltosDataPoint dp : data) { + for (AltosGraph g : graph) { + g.addData(dp); + } + } + + return graph; + } +} + +/* gnuplot bits... + * +300x400 + +-------------------------------------------------------- +TOO HARD! :) + +"ascent-gps-accuracy.png" "Vertical error margin to apogee - GPS v Baro (m)" + 5:($7 < 6 ? $24-$11 : 1/0) +"descent-gps-accuracy.png" "Vertical error margin during descent - GPS v Baro (m)" + 5:($7 < 6 ? 1/0 : $24-$11) + +set output "overall-gps-accuracy.png" +set ylabel "distance above sea level (m)" +plot "telemetry.csv" using 5:11 with lines ti "baro altitude" axis x1y1, \ + "telemetry.csv" using 5:24 with lines ti "gps altitude" axis x1y1 + +set term png tiny size 700,700 enhanced +set xlabel "m" +set ylabel "m" +set polar +set grid polar +set rrange[*:*] +set angles degrees + +set output "overall-gps-path.png" +#:30 with yerrorlines +plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0) with lines ti "pad", \ + "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0) with lines ti "boost", \ + "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0) with lines ti "fast", \ + "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0) with lines ti "coast", \ + "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \ + "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \ + "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed" + +set output "ascent-gps-path.png" +plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0):30 with lines ti "pad", \ + "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0):20 with lines ti "boost", \ + "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0):10 with lines ti "fast", \ + "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0):5 with lines ti "coast" + +set output "descent-gps-path.png" +plot "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \ + "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \ + "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed" + + */ + + diff --git a/altosui/AltosGreatCircle.java b/altosui/AltosGreatCircle.java new file mode 100644 index 00000000..fb1b6ab3 --- /dev/null +++ b/altosui/AltosGreatCircle.java @@ -0,0 +1,100 @@ +/* + * 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 altosui; + +import java.lang.Math; + +public class AltosGreatCircle { + double distance; + double bearing; + + double sqr(double a) { return a * a; } + + static final double rad = Math.PI / 180; + static final double earth_radius = 6371.2 * 1000; /* in meters */ + + static int BEARING_LONG = 0; + static int BEARING_SHORT = 1; + static int BEARING_VOICE = 2; + String bearing_words(int length) { + String [][] bearing_string = { + { + "North", "North North East", "North East", "East North East", + "East", "East South East", "South East", "South South East", + "South", "South South West", "South West", "West South West", + "West", "West North West", "North West", "North North West" + }, { + "N", "NNE", "NE", "ENE", + "E", "ESE", "SE", "SSE", + "S", "SSW", "SW", "WSW", + "W", "WNW", "NW", "NNW" + }, { + "north", "nor nor east", "north east", "east nor east", + "east", "east sow east", "south east", "sow sow east", + "south", "sow sow west", "south west", "west sow west", + "west", "west nor west", "north west", "nor nor west " + } + }; + return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16]; + } + + public AltosGreatCircle (double start_lat, double start_lon, + double end_lat, double end_lon) + { + double lat1 = rad * start_lat; + double lon1 = rad * -start_lon; + double lat2 = rad * end_lat; + double lon2 = rad * -end_lon; + + double d_lon = lon2 - lon1; + + /* From http://en.wikipedia.org/wiki/Great-circle_distance */ + double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) + + sqr(Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon))); + double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon); + double d = Math.atan2(vdn,vdd); + double course; + + if (Math.cos(lat1) < 1e-20) { + if (lat1 > 0) + course = Math.PI; + else + course = -Math.PI; + } else { + if (d < 1e-10) + course = 0; + else + course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) / + (Math.sin(d)*Math.cos(lat1))); + if (Math.sin(lon2-lon1) > 0) + course = 2 * Math.PI-course; + } + distance = d * earth_radius; + bearing = course * 180/Math.PI; + } + + public AltosGreatCircle(AltosGPS start, AltosGPS end) { + this(start.lat, start.lon, end.lat, end.lon); + } + + public AltosGreatCircle() { + distance = 0; + bearing = 0; + } +} diff --git a/altosui/AltosHexfile.java b/altosui/AltosHexfile.java new file mode 100644 index 00000000..19e35ae1 --- /dev/null +++ b/altosui/AltosHexfile.java @@ -0,0 +1,252 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.io.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.LinkedList; +import java.util.Iterator; +import java.util.Arrays; + +class HexFileInputStream extends PushbackInputStream { + public int line; + + public HexFileInputStream(FileInputStream o) { + super(new BufferedInputStream(o)); + line = 1; + } + + public int read() throws IOException { + int c = super.read(); + if (c == '\n') + line++; + return c; + } + + public void unread(int c) throws IOException { + if (c == '\n') + line--; + if (c != -1) + super.unread(c); + } +} + +class HexRecord implements Comparable { + public int address; + public int type; + public byte checksum; + public byte[] data; + + static final int NORMAL = 0; + static final int EOF = 1; + static final int EXTENDED_ADDRESS = 2; + + enum read_state { + marker, + length, + address, + type, + data, + checksum, + newline, + white, + done, + } + + boolean ishex(int c) { + if ('0' <= c && c <= '9') + return true; + if ('a' <= c && c <= 'f') + return true; + if ('A' <= c && c <= 'F') + return true; + return false; + } + + boolean isspace(int c) { + switch (c) { + case ' ': + case '\t': + return true; + } + return false; + } + + int fromhex(int c) { + 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; + return -1; + } + + public byte checksum() { + byte got = 0; + + got += data.length; + got += (address >> 8) & 0xff; + got += (address ) & 0xff; + got += type; + for (int i = 0; i < data.length; i++) + got += data[i]; + return (byte) (-got); + } + + public int compareTo(Object other) { + HexRecord o = (HexRecord) other; + return address - o.address; + } + + public String toString() { + return String.format("%04x: %02x (%d)", address, type, data.length); + } + + public HexRecord(HexFileInputStream input) throws IOException { + read_state state = read_state.marker; + int nhexbytes = 0; + int hex = 0; + int ndata = 0; + byte got_checksum; + + while (state != read_state.done) { + int c = input.read(); + if (c < 0 && state != read_state.white) + throw new IOException(String.format("%d: Unexpected EOF", input.line)); + if (c == ' ') + continue; + switch (state) { + case marker: + if (c != ':') + throw new IOException("Missing ':'"); + state = read_state.length; + nhexbytes = 2; + hex = 0; + break; + case length: + case address: + case type: + case data: + case checksum: + if(!ishex(c)) + throw new IOException(String.format("Non-hex char '%c'", c)); + hex = hex << 4 | fromhex(c); + --nhexbytes; + if (nhexbytes != 0) + break; + + switch (state) { + case length: + data = new byte[hex]; + state = read_state.address; + nhexbytes = 4; + break; + case address: + address = hex; + state = read_state.type; + nhexbytes = 2; + break; + case type: + type = hex; + if (data.length > 0) + state = read_state.data; + else + state = read_state.checksum; + nhexbytes = 2; + ndata = 0; + break; + case data: + data[ndata] = (byte) hex; + ndata++; + nhexbytes = 2; + if (ndata == data.length) + state = read_state.checksum; + break; + case checksum: + checksum = (byte) hex; + state = read_state.newline; + break; + default: + break; + } + hex = 0; + break; + case newline: + if (c != '\n' && c != '\r') + throw new IOException("Missing newline"); + state = read_state.white; + break; + case white: + if (!isspace(c)) { + input.unread(c); + state = read_state.done; + } + break; + case done: + break; + } + } + got_checksum = checksum(); + if (got_checksum != checksum) + throw new IOException(String.format("Invalid checksum (read 0x%02x computed 0x%02x)\n", + checksum, got_checksum)); + } +} + +public class AltosHexfile { + public int address; + public byte[] data; + + public byte get_byte(int a) { + return data[a - address]; + } + + public AltosHexfile(FileInputStream file) throws IOException { + HexFileInputStream input = new HexFileInputStream(file); + LinkedList record_list = new LinkedList(); + boolean done = false; + + while (!done) { + HexRecord record = new HexRecord(input); + + if (record.type == HexRecord.EOF) + done = true; + else + record_list.add(record); + } + HexRecord[] records = record_list.toArray(new HexRecord[0]); + Arrays.sort(records); + if (records.length > 0) { + int base = records[0].address; + int bound = records[records.length-1].address + + records[records.length-1].data.length; + + data = new byte[bound - base]; + address = base; + Arrays.fill(data, (byte) 0xff); + + /* Paint the records into the new array */ + for (int i = 0; i < records.length; i++) { + for (int j = 0; j < records[i].data.length; j++) + data[records[i].address - base + j] = records[i].data[j]; + } + } + } +} \ No newline at end of file diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java new file mode 100644 index 00000000..3cbd8a75 --- /dev/null +++ b/altosui/AltosIgnite.java @@ -0,0 +1,173 @@ +/* + * 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 altosui; + +import java.io.*; +import java.util.concurrent.*; + +public class AltosIgnite { + AltosDevice device; + AltosSerial serial; + boolean remote; + boolean serial_started; + final static int None = 0; + final static int Apogee = 1; + final static int Main = 2; + + final static int Unknown = 0; + final static int Ready = 1; + final static int Active = 2; + final static int Open = 3; + + private void start_serial() throws InterruptedException { + serial_started = true; + if (remote) { + serial.set_radio(); + serial.printf("p\nE 0\n"); + serial.flush_input(); + } + } + + private void stop_serial() throws InterruptedException { + if (!serial_started) + return; + serial_started = false; + if (serial == null) + return; + if (remote) { + serial.printf("~"); + serial.flush_output(); + } + } + + class string_ref { + String value; + + public String get() { + return value; + } + public void set(String i) { + value = i; + } + public string_ref() { + value = null; + } + } + + private boolean get_string(String line, String label, string_ref s) { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + s.set(quoted); + return true; + } else { + return false; + } + } + + private int status(String status_name) { + if (status_name.equals("unknown")) + return Unknown; + if (status_name.equals("ready")) + return Ready; + if (status_name.equals("active")) + return Active; + if (status_name.equals("open")) + return Open; + return Unknown; + } + + public int status(int igniter) throws InterruptedException, TimeoutException { + int status = Unknown; + if (serial == null) + return status; + string_ref status_name = new string_ref(); + start_serial(); + serial.printf("t\n"); + for (;;) { + String line = serial.get_reply(5000); + if (line == null) + throw new TimeoutException(); + if (get_string(line, "Igniter: drogue Status: ", status_name)) + if (igniter == Apogee) + status = status(status_name.get()); + if (get_string(line, "Igniter: main Status: ", status_name)) { + if (igniter == Main) + status = status(status_name.get()); + break; + } + } + stop_serial(); + return status; + } + + public String status_string(int status) { + switch (status) { + case Unknown: return "Unknown"; + case Ready: return "Ready"; + case Active: return "Active"; + case Open: return "Open"; + default: return "Unknown"; + } + } + + public void fire(int igniter) { + if (serial == null) + return; + try { + start_serial(); + switch (igniter) { + case Main: + serial.printf("i DoIt main\n"); + break; + case Apogee: + serial.printf("i DoIt drogue\n"); + break; + } + } catch (InterruptedException ie) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + } + + public void close() { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + serial.close(); + serial = null; + } + + public AltosIgnite(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { + + device = in_device; + serial = new AltosSerial(device); + remote = false; + + if (!device.matchProduct(AltosDevice.product_telemetrum)) + remote = true; + } +} \ No newline at end of file diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java new file mode 100644 index 00000000..d542729c --- /dev/null +++ b/altosui/AltosIgniteUI.java @@ -0,0 +1,317 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosIgniteUI + extends JDialog + implements ActionListener +{ + AltosDevice device; + AltosIgnite ignite; + JFrame owner; + JLabel label; + JRadioButton apogee; + JLabel apogee_status_label; + JRadioButton main; + JLabel main_status_label; + JToggleButton arm; + JButton fire; + javax.swing.Timer timer; + + int apogee_status; + int main_status; + + final static int timeout = 1 * 1000; + + int time_remaining; + boolean timer_running; + + void set_arm_text() { + if (arm.isSelected()) + arm.setText(String.format("%d", time_remaining)); + else + arm.setText("Arm"); + } + + void start_timer() { + time_remaining = 10; + set_arm_text(); + timer_running = true; + } + + void stop_timer() { + time_remaining = 0; + arm.setSelected(false); + arm.setEnabled(false); + fire.setEnabled(false); + timer_running = false; + set_arm_text(); + } + + void cancel () { + apogee.setSelected(false); + main.setSelected(false); + fire.setEnabled(false); + stop_timer(); + } + + void get_ignite_status() throws InterruptedException, TimeoutException { + apogee_status = ignite.status(AltosIgnite.Apogee); + main_status = ignite.status(AltosIgnite.Main); + } + + void set_ignite_status() throws InterruptedException, TimeoutException { + get_ignite_status(); + apogee_status_label.setText(String.format("\"%s\"", ignite.status_string(apogee_status))); + main_status_label.setText(String.format("\"%s\"", ignite.status_string(main_status))); + } + + void close() { + timer.stop(); + setVisible(false); + ignite.close(); + } + + void abort() { + close(); + JOptionPane.showMessageDialog(owner, + String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); + } + + void tick_timer() { + if (timer_running) { + --time_remaining; + if (time_remaining <= 0) + cancel(); + else + set_arm_text(); + } + try { + set_ignite_status(); + } catch (InterruptedException ie) { + abort(); + } catch (TimeoutException te) { + abort(); + } + } + + void fire() { + if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) { + int igniter = AltosIgnite.None; + if (apogee.isSelected() && !main.isSelected()) + igniter = AltosIgnite.Apogee; + else if (main.isSelected() && !apogee.isSelected()) + igniter = AltosIgnite.Main; + ignite.fire(igniter); + cancel(); + } + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + if (cmd.equals("apogee") || cmd.equals("main")) { + stop_timer(); + } + + if (cmd.equals("apogee") && apogee.isSelected()) { + main.setSelected(false); + arm.setEnabled(true); + } + if (cmd.equals("main") && main.isSelected()) { + apogee.setSelected(false); + arm.setEnabled(true); + } + + if (cmd.equals("arm")) { + if (arm.isSelected()) { + fire.setEnabled(true); + start_timer(); + } else + cancel(); + } + if (cmd.equals("fire")) + fire(); + if (cmd.equals("tick")) + tick_timer(); + if (cmd.equals("close")) { + close(); + } + } + + /* A window listener to catch closing events and tell the config code */ + class ConfigListener extends WindowAdapter { + AltosIgniteUI ui; + + public ConfigListener(AltosIgniteUI this_ui) { + ui = this_ui; + } + + public void windowClosing(WindowEvent e) { + ui.actionPerformed(new ActionEvent(e.getSource(), + ActionEvent.ACTION_PERFORMED, + "close")); + } + } + + private boolean open() { + device = AltosDeviceDialog.show(owner, AltosDevice.product_any); + if (device != null) { + try { + ignite = new AltosIgnite(device); + return true; + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(owner, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(owner, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException ee) { + JOptionPane.showMessageDialog(owner, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } + } + return false; + } + + public AltosIgniteUI(JFrame in_owner) { + + owner = in_owner; + apogee_status = AltosIgnite.Unknown; + main_status = AltosIgnite.Unknown; + + if (!open()) + return; + + Container pane = getContentPane(); + GridBagConstraints c = new GridBagConstraints(); + Insets i = new Insets(4,4,4,4); + + timer = new javax.swing.Timer(timeout, this); + timer.setActionCommand("tick"); + timer_running = false; + timer.restart(); + + owner = in_owner; + + pane.setLayout(new GridBagLayout()); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + label = new JLabel ("Fire Igniter"); + pane.add(label, c); + + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + apogee = new JRadioButton ("Apogee"); + pane.add(apogee, c); + apogee.addActionListener(this); + apogee.setActionCommand("apogee"); + + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + apogee_status_label = new JLabel(); + pane.add(apogee_status_label, c); + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + main = new JRadioButton ("Main"); + pane.add(main, c); + main.addActionListener(this); + main.setActionCommand("main"); + + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + main_status_label = new JLabel(); + pane.add(main_status_label, c); + + try { + set_ignite_status(); + } catch (InterruptedException ie) { + abort(); + return; + } catch (TimeoutException te) { + abort(); + return; + } + + c.gridx = 0; + c.gridy = 3; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + arm = new JToggleButton ("Arm"); + pane.add(arm, c); + arm.addActionListener(this); + arm.setActionCommand("arm"); + arm.setEnabled(false); + + c.gridx = 1; + c.gridy = 3; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + fire = new JButton ("Fire"); + fire.setEnabled(false); + pane.add(fire, c); + fire.addActionListener(this); + fire.setActionCommand("fire"); + + pack(); + setLocationRelativeTo(owner); + setVisible(true); + + addWindowListener(new ConfigListener(this)); + } +} \ No newline at end of file diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java new file mode 100644 index 00000000..723f8301 --- /dev/null +++ b/altosui/AltosInfoTable.java @@ -0,0 +1,190 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosInfoTable extends JTable { + private AltosFlightInfoTableModel model; + + private Font infoLabelFont = new Font("SansSerif", Font.PLAIN, 14); + private Font infoValueFont = new Font("Monospaced", Font.PLAIN, 14); + + static final int info_columns = 3; + static final int info_rows = 17; + + int desired_row_height() { + FontMetrics infoValueMetrics = getFontMetrics(infoValueFont); + return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10; + } + + public AltosInfoTable() { + super(new AltosFlightInfoTableModel(info_rows, info_columns)); + model = (AltosFlightInfoTableModel) getModel(); + setFont(infoValueFont); + setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS); + setShowGrid(true); + setRowHeight(desired_row_height()); + doLayout(); + } + + public Dimension getPreferredScrollableViewportSize() { + return getPreferredSize(); + } + + void info_reset() { + model.reset(); + } + + void info_add_row(int col, String name, String value) { + model.addRow(col, name, value); + } + + void info_add_row(int col, String name, String format, Object... parameters) { + info_add_row (col, name, String.format(format, parameters)); + } + + void info_add_deg(int col, String name, double v, int pos, int neg) { + int c = pos; + if (v < 0) { + c = neg; + v = -v; + } + double deg = Math.floor(v); + double min = (v - deg) * 60; + + info_add_row(col, name, String.format("%3.0f°%08.5f'", deg, min)); + } + + void info_finish() { + model.finish(); + } + + public void clear() { + model.clear(); + } + + public void show(AltosState state, int crc_errors) { + if (state == null) + return; + info_reset(); + info_add_row(0, "Rocket state", "%s", state.data.state()); + info_add_row(0, "Callsign", "%s", state.data.callsign); + info_add_row(0, "Rocket serial", "%6d", state.data.serial); + info_add_row(0, "Rocket flight", "%6d", state.data.flight); + + info_add_row(0, "RSSI", "%6d dBm", state.data.rssi); + info_add_row(0, "CRC Errors", "%6d", crc_errors); + info_add_row(0, "Height", "%6.0f m", state.height); + info_add_row(0, "Max height", "%6.0f m", state.max_height); + info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration); + info_add_row(0, "Max acceleration", "%8.1f m/s²", state.max_acceleration); + info_add_row(0, "Speed", "%8.1f m/s", state.ascent ? state.speed : state.baro_speed); + info_add_row(0, "Max Speed", "%8.1f m/s", state.max_speed); + info_add_row(0, "Temperature", "%9.2f °C", state.temperature); + info_add_row(0, "Battery", "%9.2f V", state.battery); + info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense); + info_add_row(0, "Main", "%9.2f V", state.main_sense); + info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude); + if (state.gps == null) { + info_add_row(1, "GPS", "not available"); + } else { + if (state.gps_ready) + info_add_row(1, "GPS state", "%s", "ready"); + else + info_add_row(1, "GPS state", "wait (%d)", + state.gps_waiting); + if (state.data.gps.locked) + info_add_row(1, "GPS", " locked"); + else if (state.data.gps.connected) + info_add_row(1, "GPS", " unlocked"); + else + info_add_row(1, "GPS", " missing"); + info_add_row(1, "Satellites", "%6d", state.data.gps.nsat); + info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S'); + info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W'); + info_add_row(1, "GPS altitude", "%6d", state.gps.alt); + info_add_row(1, "GPS height", "%6.0f", state.gps_height); + + /* The SkyTraq GPS doesn't report these values */ + if (false) { + info_add_row(1, "GPS ground speed", "%8.1f m/s %3d°", + state.gps.ground_speed, + state.gps.course); + info_add_row(1, "GPS climb rate", "%8.1f m/s", + state.gps.climb_rate); + info_add_row(1, "GPS error", "%6d m(h)%3d m(v)", + state.gps.h_error, state.gps.v_error); + } + info_add_row(1, "GPS hdop", "%8.1f", state.gps.hdop); + + if (state.npad > 0) { + if (state.from_pad != null) { + info_add_row(1, "Distance from pad", "%6d m", + (int) (state.from_pad.distance + 0.5)); + info_add_row(1, "Direction from pad", "%6d°", + (int) (state.from_pad.bearing + 0.5)); + info_add_row(1, "Elevation from pad", "%6d°", + (int) (state.elevation + 0.5)); + info_add_row(1, "Range from pad", "%6d m", + (int) (state.range + 0.5)); + } else { + info_add_row(1, "Distance from pad", "unknown"); + info_add_row(1, "Direction from pad", "unknown"); + info_add_row(1, "Elevation from pad", "unknown"); + info_add_row(1, "Range from pad", "unknown"); + } + info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S'); + info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W'); + info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt); + } + info_add_row(1, "GPS date", "%04d-%02d-%02d", + state.gps.year, + state.gps.month, + state.gps.day); + info_add_row(1, "GPS time", " %02d:%02d:%02d", + state.gps.hour, + state.gps.minute, + state.gps.second); + int nsat_vis = 0; + int c; + + if (state.gps.cc_gps_sat == null) + info_add_row(2, "Satellites Visible", "%4d", 0); + else { + info_add_row(2, "Satellites Visible", "%4d", state.gps.cc_gps_sat.length); + for (c = 0; c < state.gps.cc_gps_sat.length; c++) { + info_add_row(2, "Satellite id,C/N0", + "%4d, %4d", + state.gps.cc_gps_sat[c].svid, + state.gps.cc_gps_sat[c].c_n0); + } + } + } + info_finish(); + } +} diff --git a/altosui/AltosKML.java b/altosui/AltosKML.java new file mode 100644 index 00000000..d586033f --- /dev/null +++ b/altosui/AltosKML.java @@ -0,0 +1,169 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.io.*; +import java.text.*; +import java.util.*; + +public class AltosKML implements AltosWriter { + + File name; + PrintStream out; + int state = -1; + AltosRecord prev = null; + + static final String[] kml_state_colors = { + "FF000000", + "FF000000", + "FF000000", + "FF0000FF", + "FF4080FF", + "FF00FFFF", + "FFFF0000", + "FF00FF00", + "FF000000", + "FFFFFFFF" + }; + + static final String kml_header_start = + "\n" + + "\n" + + "\n" + + " AO Flight#%d S/N: %03d\n" + + " \n"; + static final String kml_header_end = + " \n" + + " 0\n"; + + static final String kml_style_start = + " \n"; + + static final String kml_placemark_start = + " \n" + + " %s\n" + + " #ao-flightstate-%s\n" + + " \n" + + " 1\n" + + " absolute\n" + + " \n"; + + static final String kml_coord_fmt = + " %12.7f, %12.7f, %12.7f \n"; + + static final String kml_placemark_end = + " \n" + + " \n" + + " \n"; + + static final String kml_footer = + "\n" + + "\n"; + + void start (AltosRecord record) { + out.printf(kml_header_start, record.flight, record.serial); + out.printf("Date: %04d-%02d-%02d\n", + record.gps.year, record.gps.month, record.gps.day); + out.printf("Time: %2d:%02d:%02d\n", + record.gps.hour, record.gps.minute, record.gps.second); + out.printf("%s", kml_header_end); + } + + boolean started = false; + + void state_start(AltosRecord record) { + String state_name = Altos.state_name(record.state); + out.printf(kml_style_start, state_name, kml_state_colors[record.state]); + out.printf("\tState: %s\n", state_name); + out.printf("%s", kml_style_end); + out.printf(kml_placemark_start, state_name, state_name); + } + + void state_end(AltosRecord record) { + out.printf("%s", kml_placemark_end); + } + + void coord(AltosRecord record) { + AltosGPS gps = record.gps; + out.printf(kml_coord_fmt, + gps.lon, gps.lat, + record.filtered_altitude(), (double) gps.alt, + record.time, gps.nsat); + } + + void end() { + out.printf("%s", kml_footer); + } + + public void close() { + if (prev != null) { + state_end(prev); + end(); + prev = null; + } + } + + public void write(AltosRecord record) { + AltosGPS gps = record.gps; + + if (gps == null) + return; + if (!started) { + start(record); + started = true; + } + if (prev != null && + prev.gps.second == record.gps.second && + prev.gps.minute == record.gps.minute && + prev.gps.hour == record.gps.hour) + return; + if (record.state != state) { + state = record.state; + if (prev != null) { + coord(record); + state_end(prev); + } + state_start(record); + } + coord(record); + prev = record; + } + + public void write(AltosRecordIterable iterable) { + for (AltosRecord record : iterable) + write(record); + } + + public AltosKML(File in_name) throws FileNotFoundException { + name = in_name; + out = new PrintStream(name); + } + + public AltosKML(String in_string) throws FileNotFoundException { + this(new File(in_string)); + } +} diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java new file mode 100644 index 00000000..d34efe6d --- /dev/null +++ b/altosui/AltosLanded.java @@ -0,0 +1,212 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosLanded extends JComponent implements AltosFlightDisplay { + GridBagLayout layout; + Font label_font; + Font value_font; + + public class LandedValue { + JLabel label; + JTextField value; + void show(AltosState state, int crc_errors) {} + + void reset() { + value.setText(""); + } + + void show(String format, double v) { + value.setText(String.format(format, v)); + } + + public LandedValue (GridBagLayout layout, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.weighty = 1; + + label = new JLabel(text); + label.setFont(label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = 0; c.gridy = y; + c.insets = new Insets(10, 10, 10, 10); + c.anchor = GridBagConstraints.WEST; + c.weightx = 0; + c.fill = GridBagConstraints.VERTICAL; + layout.setConstraints(label, c); + add(label); + + value = new JTextField(Altos.text_width); + value.setFont(value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = 1; c.gridy = y; + c.anchor = GridBagConstraints.WEST; + c.weightx = 1; + c.fill = GridBagConstraints.BOTH; + layout.setConstraints(value, c); + add(value); + } + } + + String pos(double p, String pos, String neg) { + String h = pos; + if (p < 0) { + h = neg; + p = -p; + } + int deg = (int) Math.floor(p); + double min = (p - Math.floor(p)) * 60.0; + return String.format("%s %4d° %9.6f", h, deg, min); + } + + class Lat extends LandedValue { + void show (AltosState state, int crc_errors) { + if (state.gps != null) + value.setText(pos(state.gps.lat,"N", "S")); + else + value.setText("???"); + } + public Lat (GridBagLayout layout, int y) { + super (layout, y, "Latitude"); + } + } + + Lat lat; + + class Lon extends LandedValue { + void show (AltosState state, int crc_errors) { + if (state.gps != null) + value.setText(pos(state.gps.lon,"E", "W")); + else + value.setText("???"); + } + public Lon (GridBagLayout layout, int y) { + super (layout, y, "Longitude"); + } + } + + Lon lon; + + class Bearing extends LandedValue { + void show (AltosState state, int crc_errors) { + if (state.from_pad != null) + show("%3.0f°", state.from_pad.bearing); + else + value.setText("???"); + } + public Bearing (GridBagLayout layout, int y) { + super (layout, y, "Bearing"); + } + } + + Bearing bearing; + + class Distance extends LandedValue { + void show (AltosState state, int crc_errors) { + if (state.from_pad != null) + show("%6.0f m", state.from_pad.distance); + else + value.setText("???"); + } + public Distance (GridBagLayout layout, int y) { + super (layout, y, "Distance"); + } + } + + Distance distance; + + class Height extends LandedValue { + void show (AltosState state, int crc_errors) { + show("%6.0f m", state.max_height); + } + public Height (GridBagLayout layout, int y) { + super (layout, y, "Maximum Height"); + } + } + + Height height; + + class Speed extends LandedValue { + void show (AltosState state, int crc_errors) { + show("%6.0f m/s", state.max_speed); + } + public Speed (GridBagLayout layout, int y) { + super (layout, y, "Maximum Speed"); + } + } + + Speed speed; + + class Accel extends LandedValue { + void show (AltosState state, int crc_errors) { + show("%6.0f m/s²", state.max_acceleration); + } + public Accel (GridBagLayout layout, int y) { + super (layout, y, "Maximum Acceleration"); + } + } + + Accel accel; + + public void reset() { + lat.reset(); + lon.reset(); + bearing.reset(); + distance.reset(); + height.reset(); + speed.reset(); + accel.reset(); + } + + public void show(AltosState state, int crc_errors) { + bearing.show(state, crc_errors); + distance.show(state, crc_errors); + lat.show(state, crc_errors); + lon.show(state, crc_errors); + height.show(state, crc_errors); + speed.show(state, crc_errors); + accel.show(state, crc_errors); + } + + public AltosLanded() { + layout = new GridBagLayout(); + + label_font = new Font("Dialog", Font.PLAIN, 22); + value_font = new Font("Monospaced", Font.PLAIN, 22); + setLayout(layout); + + /* Elements in descent display */ + bearing = new Bearing(layout, 0); + distance = new Distance(layout, 1); + lat = new Lat(layout, 2); + lon = new Lon(layout, 3); + height = new Height(layout, 4); + speed = new Speed(layout, 5); + accel = new Accel(layout, 6); + } +} diff --git a/altosui/AltosLed.java b/altosui/AltosLed.java new file mode 100644 index 00000000..e08e9960 --- /dev/null +++ b/altosui/AltosLed.java @@ -0,0 +1,54 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosLed extends JLabel { + ImageIcon on, off; + + ImageIcon create_icon(String path) { + java.net.URL imgURL = AltosUI.class.getResource(path); + if (imgURL != null) + return new ImageIcon(imgURL); + System.err.printf("Cannot find icon \"%s\"\n", path); + return null; + } + + public void set(boolean set) { + if (set) + setIcon(on); + else + setIcon(off); + } + + public AltosLed(String on_path, String off_path) { + on = create_icon(on_path); + off = create_icon(off_path); + setIcon(off); + } +} diff --git a/altosui/AltosLights.java b/altosui/AltosLights.java new file mode 100644 index 00000000..2fa38412 --- /dev/null +++ b/altosui/AltosLights.java @@ -0,0 +1,73 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosLights extends JComponent { + + GridBagLayout gridbag; + + AltosLed red, green; + + ImageIcon create_icon(String path, String description) { + java.net.URL imgURL = AltosUI.class.getResource(path); + if (imgURL != null) + return new ImageIcon(imgURL, description); + System.err.printf("Cannot find icon \"%s\"\n", path); + return null; + } + + public void set (boolean on) { + if (on) { + red.set(false); + green.set(true); + } else { + red.set(true); + green.set(false); + } + } + + public AltosLights() { + GridBagConstraints c; + gridbag = new GridBagLayout(); + setLayout(gridbag); + + c = new GridBagConstraints(); + red = new AltosLed("/redled.png", "/grayled.png"); + c.gridx = 0; c.gridy = 0; + c.insets = new Insets (0, 5, 0, 5); + gridbag.setConstraints(red, c); + add(red); + red.set(true); + green = new AltosLed("/greenled.png", "/grayled.png"); + c.gridx = 1; c.gridy = 0; + gridbag.setConstraints(green, c); + add(green); + green.set(false); + } +} diff --git a/altosui/AltosLine.java b/altosui/AltosLine.java new file mode 100644 index 00000000..86e9d4c6 --- /dev/null +++ b/altosui/AltosLine.java @@ -0,0 +1,30 @@ +/* + * 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 altosui; + +public class AltosLine { + public String line; + + public AltosLine() { + line = null; + } + + public AltosLine(String s) { + line = s; + } +} \ No newline at end of file diff --git a/altosui/AltosLog.java b/altosui/AltosLog.java new file mode 100644 index 00000000..dd147d21 --- /dev/null +++ b/altosui/AltosLog.java @@ -0,0 +1,115 @@ +/* + * 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 altosui; + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.text.ParseException; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * This creates a thread to capture telemetry data and write it to + * a log file + */ +class AltosLog implements Runnable { + + LinkedBlockingQueue input_queue; + LinkedBlockingQueue pending_queue; + int serial; + int flight; + FileWriter log_file; + Thread log_thread; + + private void close_log_file() { + if (log_file != null) { + try { + log_file.close(); + } catch (IOException io) { + } + log_file = null; + } + } + + void close() { + close_log_file(); + if (log_thread != null) { + log_thread.interrupt(); + log_thread = null; + } + } + + boolean open (AltosTelemetry telem) throws IOException { + AltosFile a = new AltosFile(telem); + + log_file = new FileWriter(a, true); + if (log_file != null) { + while (!pending_queue.isEmpty()) { + try { + String s = pending_queue.take(); + log_file.write(s); + log_file.write('\n'); + } catch (InterruptedException ie) { + } + } + log_file.flush(); + } + return log_file != null; + } + + public void run () { + try { + for (;;) { + AltosLine line = input_queue.take(); + if (line.line == null) + continue; + try { + AltosTelemetry telem = new AltosTelemetry(line.line); + if (telem.serial != serial || telem.flight != flight || log_file == null) { + close_log_file(); + serial = telem.serial; + flight = telem.flight; + open(telem); + } + } catch (ParseException pe) { + } catch (AltosCRCException ce) { + } + if (log_file != null) { + log_file.write(line.line); + log_file.write('\n'); + log_file.flush(); + } else + pending_queue.put(line.line); + } + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + close(); + } + + public AltosLog (AltosSerial s) { + pending_queue = new LinkedBlockingQueue (); + input_queue = new LinkedBlockingQueue (); + s.add_monitor(input_queue); + serial = -1; + flight = -1; + log_file = null; + log_thread = new Thread(this); + log_thread.start(); + } +} diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java new file mode 100644 index 00000000..66954347 --- /dev/null +++ b/altosui/AltosPad.java @@ -0,0 +1,269 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosPad extends JComponent implements AltosFlightDisplay { + GridBagLayout layout; + + public class LaunchStatus { + JLabel label; + JTextField value; + AltosLights lights; + + void show(AltosState state, int crc_errors) {} + void reset() { + value.setText(""); + lights.set(false); + } + + public LaunchStatus (GridBagLayout layout, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.weighty = 1; + + lights = new AltosLights(); + c.gridx = 0; c.gridy = y; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(lights, c); + add(lights); + + label = new JLabel(text); + label.setFont(Altos.label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = 1; c.gridy = y; + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(label, c); + add(label); + + value = new JTextField(Altos.text_width); + value.setFont(Altos.value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = 2; c.gridy = y; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + layout.setConstraints(value, c); + add(value); + + } + } + + public class LaunchValue { + JLabel label; + JTextField value; + void show(AltosState state, int crc_errors) {} + + void reset() { + value.setText(""); + } + public LaunchValue (GridBagLayout layout, int y, String text) { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.weighty = 1; + + label = new JLabel(text); + label.setFont(Altos.label_font); + label.setHorizontalAlignment(SwingConstants.LEFT); + c.gridx = 1; c.gridy = y; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.VERTICAL; + c.weightx = 0; + layout.setConstraints(label, c); + add(label); + + value = new JTextField(Altos.text_width); + value.setFont(Altos.value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = 2; c.gridy = y; + c.anchor = GridBagConstraints.EAST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + layout.setConstraints(value, c); + add(value); + } + } + + class Battery extends LaunchStatus { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4.2f V", state.battery)); + lights.set(state.battery > 3.7); + } + public Battery (GridBagLayout layout, int y) { + super(layout, y, "Battery Voltage"); + } + } + + Battery battery; + + class Apogee extends LaunchStatus { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4.2f V", state.drogue_sense)); + lights.set(state.drogue_sense > 3.2); + } + public Apogee (GridBagLayout layout, int y) { + super(layout, y, "Apogee Igniter Voltage"); + } + } + + Apogee apogee; + + class Main extends LaunchStatus { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4.2f V", state.main_sense)); + lights.set(state.main_sense > 3.2); + } + public Main (GridBagLayout layout, int y) { + super(layout, y, "Main Igniter Voltage"); + } + } + + Main main; + + class GPSLocked extends LaunchStatus { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4d sats", state.gps.nsat)); + lights.set(state.gps.locked); + } + public GPSLocked (GridBagLayout layout, int y) { + super (layout, y, "GPS Locked"); + } + } + + GPSLocked gps_locked; + + class GPSReady extends LaunchStatus { + void show (AltosState state, int crc_errors) { + if (state.gps_ready) + value.setText("Ready"); + else + value.setText(String.format("Waiting %d", state.gps_waiting)); + lights.set(state.gps_ready); + } + public GPSReady (GridBagLayout layout, int y) { + super (layout, y, "GPS Ready"); + } + } + + GPSReady gps_ready; + + String pos(double p, String pos, String neg) { + String h = pos; + if (p < 0) { + h = neg; + p = -p; + } + int deg = (int) Math.floor(p); + double min = (p - Math.floor(p)) * 60.0; + return String.format("%s %4d° %9.6f", h, deg, min); + } + + class PadLat extends LaunchValue { + void show (AltosState state, int crc_errors) { + value.setText(pos(state.pad_lat,"N", "S")); + } + public PadLat (GridBagLayout layout, int y) { + super (layout, y, "Pad Latitude"); + } + } + + PadLat pad_lat; + + class PadLon extends LaunchValue { + void show (AltosState state, int crc_errors) { + value.setText(pos(state.pad_lon,"E", "W")); + } + public PadLon (GridBagLayout layout, int y) { + super (layout, y, "Pad Longitude"); + } + } + + PadLon pad_lon; + + class PadAlt extends LaunchValue { + void show (AltosState state, int crc_errors) { + value.setText(String.format("%4.0f m", state.pad_alt)); + } + public PadAlt (GridBagLayout layout, int y) { + super (layout, y, "Pad Altitude"); + } + } + + PadAlt pad_alt; + + public void reset() { + battery.reset(); + apogee.reset(); + main.reset(); + gps_locked.reset(); + gps_ready.reset(); + pad_lat.reset(); + pad_lon.reset(); + pad_alt.reset(); + } + + public void show(AltosState state, int crc_errors) { + battery.show(state, crc_errors); + apogee.show(state, crc_errors); + main.show(state, crc_errors); + gps_locked.show(state, crc_errors); + gps_ready.show(state, crc_errors); + pad_lat.show(state, crc_errors); + pad_lon.show(state, crc_errors); + pad_alt.show(state, crc_errors); + } + + public AltosPad() { + layout = new GridBagLayout(); + + setLayout(layout); + + /* Elements in pad display: + * + * Battery voltage + * Igniter continuity + * GPS lock status + * GPS ready status + * GPS location + * Pad altitude + * RSSI + */ + battery = new Battery(layout, 0); + apogee = new Apogee(layout, 1); + main = new Main(layout, 2); + gps_locked = new GPSLocked(layout, 3); + gps_ready = new GPSReady(layout, 4); + pad_lat = new PadLat(layout, 5); + pad_lon = new PadLon(layout, 6); + pad_alt = new PadAlt(layout, 7); + } +} diff --git a/altosui/AltosParse.java b/altosui/AltosParse.java new file mode 100644 index 00000000..fbfcaaee --- /dev/null +++ b/altosui/AltosParse.java @@ -0,0 +1,79 @@ +/* + * 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 altosui; + +import java.text.*; +import java.lang.*; + +public class AltosParse { + static boolean isdigit(char c) { + return '0' <= c && c <= '9'; + } + + static int parse_int(String v) throws ParseException { + try { + return Altos.fromdec(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing int " + v, 0); + } + } + + static int parse_hex(String v) throws ParseException { + try { + return Altos.fromhex(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing hex " + v, 0); + } + } + + static double parse_double(String v) throws ParseException { + try { + return Double.parseDouble(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing double " + v, 0); + } + } + + static double parse_coord(String coord) throws ParseException { + String[] dsf = coord.split("\\D+"); + + if (dsf.length != 3) { + throw new ParseException("error parsing coord " + coord, 0); + } + int deg = parse_int(dsf[0]); + int min = parse_int(dsf[1]); + int frac = parse_int(dsf[2]); + + double r = deg + (min + frac / 10000.0) / 60.0; + if (coord.endsWith("S") || coord.endsWith("W")) + r = -r; + return r; + } + + static String strip_suffix(String v, String suffix) { + if (v.endsWith(suffix)) + return v.substring(0, v.length() - suffix.length()); + return v; + } + + static void word(String v, String m) throws ParseException { + if (!v.equals(m)) { + throw new ParseException("error matching '" + v + "' '" + m + "'", 0); + } + } +} diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java new file mode 100644 index 00000000..e2a3df3b --- /dev/null +++ b/altosui/AltosPreferences.java @@ -0,0 +1,205 @@ +/* + * 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 altosui; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.awt.Component; +import javax.swing.*; +import javax.swing.filechooser.FileSystemView; + +class AltosPreferences { + static Preferences preferences; + + /* logdir preference name */ + final static String logdirPreference = "LOGDIR"; + + /* channel preference name */ + final static String channelPreferenceFormat = "CHANNEL-%d"; + + /* voice preference name */ + final static String voicePreference = "VOICE"; + + /* callsign preference name */ + final static String callsignPreference = "CALLSIGN"; + + /* firmware directory preference name */ + final static String firmwaredirPreference = "FIRMWARE"; + + /* Default logdir is ~/TeleMetrum */ + final static String logdirName = "TeleMetrum"; + + /* UI Component to pop dialogs up */ + static Component component; + + /* Log directory */ + static File logdir; + + /* Channel (map serial to channel) */ + static Hashtable channels; + + /* Voice preference */ + static boolean voice; + + /* Callsign preference */ + static String callsign; + + /* Firmware directory */ + static File firmwaredir; + + public static void init(Component ui) { + preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); + + component = ui; + + /* Initialize logdir from preferences */ + String logdir_string = preferences.get(logdirPreference, null); + if (logdir_string != null) + logdir = new File(logdir_string); + else { + /* Use the file system view default directory */ + logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName); + if (!logdir.exists()) + logdir.mkdirs(); + } + + channels = new Hashtable(); + + voice = preferences.getBoolean(voicePreference, true); + + callsign = preferences.get(callsignPreference,"N0CALL"); + + String firmwaredir_string = preferences.get(firmwaredirPreference, null); + if (firmwaredir_string != null) + firmwaredir = new File(firmwaredir_string); + else + firmwaredir = null; + } + + static void flush_preferences() { + try { + preferences.flush(); + } catch (BackingStoreException ee) { + JOptionPane.showMessageDialog(component, + preferences.absolutePath(), + "Cannot save prefernces", + JOptionPane.ERROR_MESSAGE); + } + } + + public static void set_logdir(File new_logdir) { + logdir = new_logdir; + synchronized (preferences) { + preferences.put(logdirPreference, logdir.getPath()); + flush_preferences(); + } + } + + 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 File logdir() { + return logdir; + } + + public static void set_channel(int serial, int new_channel) { + channels.put(serial, new_channel); + synchronized (preferences) { + preferences.putInt(String.format(channelPreferenceFormat, serial), new_channel); + flush_preferences(); + } + } + + public static int channel(int serial) { + if (channels.containsKey(serial)) + return channels.get(serial); + int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); + channels.put(serial, channel); + return channel; + } + + public static void set_voice(boolean new_voice) { + voice = new_voice; + synchronized (preferences) { + preferences.putBoolean(voicePreference, voice); + flush_preferences(); + } + } + + public static boolean voice() { + return voice; + } + + public static void set_callsign(String new_callsign) { + callsign = new_callsign; + synchronized(preferences) { + preferences.put(callsignPreference, callsign); + flush_preferences(); + } + } + + public static String callsign() { + return callsign; + } + + public static void set_firmwaredir(File new_firmwaredir) { + firmwaredir = new_firmwaredir; + synchronized (preferences) { + preferences.put(firmwaredirPreference, firmwaredir.getPath()); + flush_preferences(); + } + } + + public static File firmwaredir() { + return firmwaredir; + } +} diff --git a/altosui/AltosReader.java b/altosui/AltosReader.java new file mode 100644 index 00000000..b9280a0c --- /dev/null +++ b/altosui/AltosReader.java @@ -0,0 +1,28 @@ +/* + * 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 altosui; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosReader { + public AltosRecord read() throws IOException, ParseException { return null; } + public void close() { } + public void write_comments(PrintStream out) { } +} diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java new file mode 100644 index 00000000..1160a273 --- /dev/null +++ b/altosui/AltosRecord.java @@ -0,0 +1,219 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; +import java.io.*; + +public class AltosRecord { + int version; + String callsign; + int serial; + int flight; + int rssi; + int status; + int state; + int tick; + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + int flight_accel; + int ground_accel; + int flight_vel; + int flight_pres; + int ground_pres; + int accel_plus_g; + int accel_minus_g; + AltosGPS gps; + + double time; /* seconds since boost */ + + /* + * Values for our MP3H6115A pressure sensor + * + * From the data sheet: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * + * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa + * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa + */ + + static final double counts_per_kPa = 27 * 2047 / 3300; + static final double counts_at_101_3kPa = 1674.0; + + static double + barometer_to_pressure(double count) + { + return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; + } + + public double raw_pressure() { + return barometer_to_pressure(pres); + } + + public double filtered_pressure() { + return barometer_to_pressure(flight_pres); + } + + public double ground_pressure() { + return barometer_to_pressure(ground_pres); + } + + public double filtered_altitude() { + return AltosConvert.pressure_to_altitude(filtered_pressure()); + } + + public double raw_altitude() { + return AltosConvert.pressure_to_altitude(raw_pressure()); + } + + public double ground_altitude() { + return AltosConvert.pressure_to_altitude(ground_pressure()); + } + + public double filtered_height() { + return filtered_altitude() - ground_altitude(); + } + + public double raw_height() { + return raw_altitude() - ground_altitude(); + } + + public double battery_voltage() { + return AltosConvert.cc_battery_to_voltage(batt); + } + + public double main_voltage() { + return AltosConvert.cc_ignitor_to_voltage(main); + } + + public double drogue_voltage() { + return AltosConvert.cc_ignitor_to_voltage(drogue); + } + + /* Value for the CC1111 built-in temperature sensor + * Output voltage at 0°C = 0.755V + * Coefficient = 0.00247V/°C + * Reference voltage = 1.25V + * + * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 + * = (value - 19791.268) / 32768 * 1.25 / 0.00247 + */ + + static double + thermometer_to_temperature(double thermo) + { + return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; + } + + public double temperature() { + return thermometer_to_temperature(temp); + } + + double accel_counts_per_mss() { + double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; + + return counts_per_g / 9.80665; + } + public double acceleration() { + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public double accel_speed() { + double speed = flight_vel / (accel_counts_per_mss() * 100.0); + return speed; + } + + public String state() { + return Altos.state_name(state); + } + + public static String gets(FileInputStream s) throws IOException { + int c; + String line = ""; + + while ((c = s.read()) != -1) { + if (c == '\r') + continue; + if (c == '\n') { + return line; + } + line = line + (char) c; + } + return null; + } + + public AltosRecord(AltosRecord old) { + version = old.version; + callsign = old.callsign; + serial = old.serial; + flight = old.flight; + rssi = old.rssi; + status = old.status; + state = old.state; + tick = old.tick; + accel = old.accel; + pres = old.pres; + temp = old.temp; + batt = old.batt; + drogue = old.drogue; + main = old.main; + flight_accel = old.flight_accel; + ground_accel = old.ground_accel; + flight_vel = old.flight_vel; + flight_pres = old.flight_pres; + ground_pres = old.ground_pres; + accel_plus_g = old.accel_plus_g; + accel_minus_g = old.accel_minus_g; + gps = new AltosGPS(old.gps); + } + + public AltosRecord() { + version = 0; + callsign = "N0CALL"; + serial = 0; + flight = 0; + rssi = 0; + status = 0; + state = Altos.ao_flight_startup; + tick = 0; + accel = 0; + pres = 0; + temp = 0; + batt = 0; + drogue = 0; + main = 0; + flight_accel = 0; + ground_accel = 0; + flight_vel = 0; + flight_pres = 0; + ground_pres = 0; + accel_plus_g = 0; + accel_minus_g = 0; + gps = new AltosGPS(); + } +} diff --git a/altosui/AltosRecordIterable.java b/altosui/AltosRecordIterable.java new file mode 100644 index 00000000..a7df92d1 --- /dev/null +++ b/altosui/AltosRecordIterable.java @@ -0,0 +1,34 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public abstract class AltosRecordIterable implements Iterable { + public abstract Iterator iterator(); + public void write_comments(PrintStream out) { } +} diff --git a/altosui/AltosReplayReader.java b/altosui/AltosReplayReader.java new file mode 100644 index 00000000..4e5e1d93 --- /dev/null +++ b/altosui/AltosReplayReader.java @@ -0,0 +1,57 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * Open an existing telemetry file and replay it in realtime + */ + +public class AltosReplayReader extends AltosFlightReader { + Iterator iterator; + + public AltosRecord read() { + if (iterator.hasNext()) + return iterator.next(); + return null; + } + + public void close (boolean interrupted) { + } + + void update(AltosState state) throws InterruptedException { + /* Make it run in realtime after the rocket leaves the pad */ + if (state.state > Altos.ao_flight_pad) + Thread.sleep((int) (Math.min(state.time_change,10) * 1000)); + } + + public AltosReplayReader(Iterator in_iterator, String in_name) { + iterator = in_iterator; + name = in_name; + } +} diff --git a/altosui/AltosRomconfig.java b/altosui/AltosRomconfig.java new file mode 100644 index 00000000..55056b5e --- /dev/null +++ b/altosui/AltosRomconfig.java @@ -0,0 +1,147 @@ +/* + * 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 altosui; +import java.io.*; + +public class AltosRomconfig { + public boolean valid; + public int version; + public int check; + public int serial_number; + public int radio_calibration; + + static int get_int(byte[] bytes, int start, int len) { + int v = 0; + int o = 0; + while (len > 0) { + v = v | ((((int) bytes[start]) & 0xff) << o); + start++; + len--; + o += 8; + } + return v; + } + + static void put_int(int value, byte[] bytes, int start, int len) { + while (len > 0) { + bytes[start] = (byte) (value & 0xff); + start++; + len--; + value >>= 8; + } + } + + static void put_string(String value, byte[] bytes, int start) { + for (int i = 0; i < value.length(); i++) + bytes[start + i] = (byte) value.charAt(i); + } + + static final int AO_USB_DESC_STRING = 3; + + static void put_usb_serial(int value, byte[] bytes, int start) { + int offset = start + 0xa; + int string_num = 0; + + while (offset < bytes.length && bytes[offset] != 0) { + if (bytes[offset + 1] == AO_USB_DESC_STRING) { + ++string_num; + if (string_num == 4) + break; + } + offset += ((int) bytes[offset]) & 0xff; + } + if (offset >= bytes.length || bytes[offset] == 0) + return; + int len = ((((int) bytes[offset]) & 0xff) - 2) / 2; + String fmt = String.format("%%0%dd", len); + + String s = String.format(fmt, value); + if (s.length() != len) { + System.out.printf("weird usb length issue %s isn't %d\n", + s, len); + return; + } + for (int i = 0; i < len; i++) { + bytes[offset + 2 + i*2] = (byte) s.charAt(i); + bytes[offset + 2 + i*2+1] = 0; + } + } + + public AltosRomconfig(byte[] bytes, int offset) { + version = get_int(bytes, offset + 0, 2); + check = get_int(bytes, offset + 2, 2); + if (check == (~version & 0xffff)) { + switch (version) { + case 2: + case 1: + serial_number = get_int(bytes, offset + 4, 2); + radio_calibration = get_int(bytes, offset + 6, 4); + valid = true; + break; + } + } + } + + public AltosRomconfig(AltosHexfile hexfile) { + this(hexfile.data, 0xa0 - hexfile.address); + } + + public void write(byte[] bytes, int offset) throws IOException { + if (!valid) + throw new IOException("rom configuration invalid"); + + if (offset < 0 || bytes.length < offset + 10) + throw new IOException("image cannot contain rom config"); + + AltosRomconfig existing = new AltosRomconfig(bytes, offset); + if (!existing.valid) + throw new IOException("image does not contain existing rom config"); + + switch (existing.version) { + case 2: + put_usb_serial(serial_number, bytes, offset); + case 1: + put_int(serial_number, bytes, offset + 4, 2); + put_int(radio_calibration, bytes, offset + 6, 4); + break; + } + } + + public void write (AltosHexfile hexfile) throws IOException { + write(hexfile.data, 0xa0 - hexfile.address); + AltosRomconfig check = new AltosRomconfig(hexfile); + if (!check.valid()) + throw new IOException("writing new rom config failed\n"); + } + + public AltosRomconfig(int in_serial_number, int in_radio_calibration) { + valid = true; + version = 1; + check = (~version & 0xffff); + serial_number = in_serial_number; + radio_calibration = in_radio_calibration; + } + + public boolean valid() { + return valid && serial_number != 0; + } + + public AltosRomconfig() { + valid = false; + } +} diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java new file mode 100644 index 00000000..e1dc974e --- /dev/null +++ b/altosui/AltosRomconfigUI.java @@ -0,0 +1,186 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; + +public class AltosRomconfigUI + extends JDialog + implements ActionListener +{ + Container pane; + Box box; + JLabel serial_label; + JLabel radio_calibration_label; + + JFrame owner; + JTextField serial_value; + JTextField radio_calibration_value; + + JButton ok; + JButton cancel; + + /* Build the UI using a grid bag */ + public AltosRomconfigUI(JFrame in_owner) { + super (in_owner, "Configure TeleMetrum Rom Values", true); + + owner = in_owner; + GridBagConstraints c; + + Insets il = new Insets(4,4,4,4); + Insets ir = new Insets(4,4,4,4); + + pane = getContentPane(); + pane.setLayout(new GridBagLayout()); + + /* Serial */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 0; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + serial_label = new JLabel("Serial:"); + pane.add(serial_label, c); + + c = new GridBagConstraints(); + c.gridx = 3; c.gridy = 0; + c.gridwidth = 3; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + serial_value = new JTextField("0"); + pane.add(serial_value, c); + + /* Radio calibration value */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 1; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + radio_calibration_label = new JLabel("Radio Calibration:"); + pane.add(radio_calibration_label, c); + + c = new GridBagConstraints(); + c.gridx = 3; c.gridy = 1; + c.gridwidth = 3; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + radio_calibration_value = new JTextField("1186611"); + pane.add(radio_calibration_value, c); + + /* Buttons */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 2; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = il; + ok = new JButton("OK"); + pane.add(ok, c); + ok.addActionListener(this); + ok.setActionCommand("ok"); + + c = new GridBagConstraints(); + c.gridx = 3; c.gridy = 2; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = il; + cancel = new JButton("Cancel"); + pane.add(cancel, c); + cancel.addActionListener(this); + cancel.setActionCommand("cancel"); + + pack(); + setLocationRelativeTo(owner); + } + + boolean selected; + + /* Listen for events from our buttons */ + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if (cmd.equals("ok")) { + AltosRomconfig romconfig = romconfig(); + if (romconfig == null || !romconfig.valid()) { + JOptionPane.showMessageDialog(this, + "Invalid serial number or radio calibration value", + "Invalid rom configuration", + JOptionPane.ERROR_MESSAGE); + return; + } + selected = true; + } + setVisible(false); + } + + int serial() { + return Integer.parseInt(serial_value.getText()); + } + + void set_serial(int serial) { + serial_value.setText(String.format("%d", serial)); + } + + int radio_calibration() { + return Integer.parseInt(radio_calibration_value.getText()); + } + + void set_radio_calibration(int calibration) { + radio_calibration_value.setText(String.format("%d", calibration)); + } + + public void set(AltosRomconfig config) { + if (config != null && config.valid()) { + set_serial(config.serial_number); + set_radio_calibration(config.radio_calibration); + } + } + + AltosRomconfig romconfig() { + try { + return new AltosRomconfig(serial(), radio_calibration()); + } catch (NumberFormatException ne) { + return null; + } + } + + public AltosRomconfig showDialog() { + setVisible(true); + if (selected) + return romconfig(); + return null; + } +} diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java new file mode 100644 index 00000000..b19143e5 --- /dev/null +++ b/altosui/AltosSerial.java @@ -0,0 +1,253 @@ +/* + * 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. + */ + +/* + * Deal with TeleDongle on a serial port + */ + +package altosui; + +import java.lang.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; + +import libaltosJNI.*; + +/* + * This class reads from the serial port and places each received + * line in a queue. Dealing with that queue is left up to other + * threads. + */ + +public class AltosSerial implements Runnable { + + static List devices_opened = Collections.synchronizedList(new LinkedList()); + + AltosDevice device; + SWIGTYPE_p_altos_file altos; + LinkedList> monitors; + LinkedBlockingQueue reply_queue; + Thread input_thread; + String line; + byte[] line_bytes; + int line_count; + boolean monitor_mode; + + public void run () { + int c; + + try { + for (;;) { + c = libaltos.altos_getchar(altos, 0); + if (Thread.interrupted()) + break; + if (c == libaltosConstants.LIBALTOS_ERROR) { + for (int e = 0; e < monitors.size(); e++) { + LinkedBlockingQueue q = monitors.get(e); + q.put(new AltosLine()); + } + reply_queue.put (new AltosLine()); + break; + } + if (c == libaltosConstants.LIBALTOS_TIMEOUT) + continue; + if (c == '\r') + continue; + synchronized(this) { + if (c == '\n') { + if (line_count != 0) { + try { + line = new String(line_bytes, 0, line_count, "UTF-8"); + } catch (UnsupportedEncodingException ue) { + line = ""; + for (int i = 0; i < line_count; i++) + line = line + line_bytes[i]; + } + if (line.startsWith("VERSION") || line.startsWith("CRC")) { + for (int e = 0; e < monitors.size(); e++) { + LinkedBlockingQueue q = monitors.get(e); + q.put(new AltosLine (line)); + } + } else { +// System.out.printf("GOT: %s\n", line); + reply_queue.put(new AltosLine (line)); + } + line_count = 0; + line = ""; + } + } else { + if (line_bytes == null) { + line_bytes = new byte[256]; + } else if (line_count == line_bytes.length) { + byte[] new_line_bytes = new byte[line_count * 2]; + System.arraycopy(line_bytes, 0, new_line_bytes, 0, line_count); + line_bytes = new_line_bytes; + } + line_bytes[line_count] = (byte) c; + line_count++; + } + } + } + } catch (InterruptedException e) { + } + } + + public void flush_output() { + if (altos != null) + libaltos.altos_flush(altos); + } + + public void flush_input() { + flush_output(); + boolean got_some; + do { + try { + Thread.sleep(100); + } catch (InterruptedException ie) { + } + got_some = !reply_queue.isEmpty(); + synchronized(this) { + if (!"VERSION".startsWith(line) && + !line.startsWith("VERSION")) + line = ""; + reply_queue.clear(); + } + } while (got_some); + } + + public String get_reply() throws InterruptedException { + flush_output(); + AltosLine line = reply_queue.take(); + return line.line; + } + + public String get_reply(int timeout) throws InterruptedException { + flush_output(); + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line == null) + return null; + return line.line; + } + + public void add_monitor(LinkedBlockingQueue q) { + set_monitor(true); + monitors.add(q); + } + + public void remove_monitor(LinkedBlockingQueue q) { + monitors.remove(q); + if (monitors.isEmpty()) + set_monitor(false); + } + + public void close() { + if (altos != null) { + libaltos.altos_close(altos); + } + if (input_thread != null) { + try { + input_thread.interrupt(); + input_thread.join(); + } catch (InterruptedException e) { + } + input_thread = null; + } + if (altos != null) { + libaltos.altos_free(altos); + altos = null; + } + synchronized (devices_opened) { + devices_opened.remove(device.getPath()); + } + } + + public void putc(char c) { + if (altos != null) + libaltos.altos_putchar(altos, c); + } + + public void print(String data) { +// System.out.printf("\"%s\" ", data); + for (int i = 0; i < data.length(); i++) + putc(data.charAt(i)); + } + + public void printf(String format, Object ... arguments) { + print(String.format(format, arguments)); + } + + private void open() throws FileNotFoundException, AltosSerialInUseException { + synchronized (devices_opened) { + if (devices_opened.contains(device.getPath())) + throw new AltosSerialInUseException(device); + devices_opened.add(device.getPath()); + } + altos = libaltos.altos_open(device); + if (altos == null) { + close(); + throw new FileNotFoundException(device.toShortString()); + } + input_thread = new Thread(this); + input_thread.start(); + print("~\nE 0\n"); + set_monitor(false); + flush_output(); + } + + public void set_radio() { + set_channel(AltosPreferences.channel(device.getSerial())); + set_callsign(AltosPreferences.callsign()); + } + + public void set_channel(int channel) { + if (altos != null) { + if (monitor_mode) + printf("m 0\nc r %d\nm 1\n", channel); + else + printf("c r %d\n", channel); + flush_output(); + } + } + + void set_monitor(boolean monitor) { + monitor_mode = monitor; + if (altos != null) { + if (monitor) + printf("m 1\n"); + else + printf("m 0\n"); + flush_output(); + } + } + + public void set_callsign(String callsign) { + if (altos != null) { + printf ("c c %s\n", callsign); + flush_output(); + } + } + + public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { + device = in_device; + line = ""; + monitor_mode = false; + monitors = new LinkedList> (); + reply_queue = new LinkedBlockingQueue (); + open(); + } +} diff --git a/altosui/AltosSerialInUseException.java b/altosui/AltosSerialInUseException.java new file mode 100644 index 00000000..4b108c7c --- /dev/null +++ b/altosui/AltosSerialInUseException.java @@ -0,0 +1,28 @@ +/* + * 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 altosui; + +import libaltosJNI.*; + +public class AltosSerialInUseException extends Exception { + public altos_device device; + + public AltosSerialInUseException (altos_device in_device) { + device = in_device; + } +} diff --git a/altosui/AltosSerialMonitor.java b/altosui/AltosSerialMonitor.java new file mode 100644 index 00000000..ad0e9295 --- /dev/null +++ b/altosui/AltosSerialMonitor.java @@ -0,0 +1,22 @@ +/* + * 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 altosui; + +public interface AltosSerialMonitor { + void data(String data); +} diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java new file mode 100644 index 00000000..80970605 --- /dev/null +++ b/altosui/AltosSiteMap.java @@ -0,0 +1,388 @@ +/* + * Copyright © 2010 Anthony Towns + * + * 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.image.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.MouseInputAdapter; +import javax.imageio.ImageIO; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.lang.Math; +import java.awt.geom.Point2D; +import java.awt.geom.Line2D; + +public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { + // preferred vertical step in a tile in naut. miles + // will actually choose a step size between x and 2x, where this + // is 1.5x + static final double tile_size_nmi = 0.75; + + static final int px_size = 512; + + static final int MAX_TILE_DELTA = 100; + + private static Point2D.Double translatePoint(Point2D.Double p, + Point2D.Double d) + { + return new Point2D.Double(p.x + d.x, p.y + d.y); + } + + static class LatLng { + public double lat, lng; + public LatLng(double lat, double lng) { + this.lat = lat; + this.lng = lng; + } + } + + // based on google js + // http://maps.gstatic.com/intl/en_us/mapfiles/api-3/2/10/main.js + // search for fromLatLngToPoint and fromPointToLatLng + private static Point2D.Double pt(LatLng latlng, int zoom) { + double scale_x = 256/360.0 * Math.pow(2, zoom); + double scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom); + return pt(latlng, scale_x, scale_y); + } + + private static Point2D.Double pt(LatLng latlng, + double scale_x, double scale_y) + { + Point2D.Double res = new Point2D.Double(); + double e; + + res.x = latlng.lng * scale_x; + + e = Math.sin(Math.toRadians(latlng.lat)); + e = Math.max(e,-(1-1.0E-15)); + e = Math.min(e, 1-1.0E-15 ); + + res.y = 0.5*Math.log((1+e)/(1-e))*-scale_y; + return res; + } + + static private LatLng latlng(Point2D.Double pt, + double scale_x, double scale_y) + { + double lat, lng; + double rads; + + lng = pt.x/scale_x; + rads = 2 * Math.atan(Math.exp(-pt.y/scale_y)); + lat = Math.toDegrees(rads - Math.PI/2); + + return new LatLng(lat,lng); + } + + int zoom; + double scale_x, scale_y; + + private Point2D.Double pt(double lat, double lng) { + return pt(new LatLng(lat, lng), scale_x, scale_y); + } + + private LatLng latlng(double x, double y) { + return latlng(new Point2D.Double(x,y), scale_x, scale_y); + } + private LatLng latlng(Point2D.Double pt) { + return latlng(pt, scale_x, scale_y); + } + + HashMap mapTiles = new HashMap(); + Point2D.Double centre; + + private Point2D.Double tileCoordOffset(Point p) { + return new Point2D.Double(centre.x - p.x*px_size, + centre.y - p.y * px_size); + } + + private Point tileOffset(Point2D.Double p) { + return new Point((int)Math.floor((centre.x+p.x)/px_size), + (int)Math.floor((centre.y+p.y)/px_size)); + } + + private Point2D.Double getBaseLocation(double lat, double lng) { + Point2D.Double locn, north_step; + + zoom = 2; + // stupid loop structure to please Java's control flow analysis + do { + zoom++; + scale_x = 256/360.0 * Math.pow(2, zoom); + scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom); + locn = pt(lat, lng); + north_step = pt(lat+tile_size_nmi*4/3/60.0, lng); + if (locn.y - north_step.y > px_size) + break; + } while (zoom < 22); + locn.x = -px_size * Math.floor(locn.x/px_size); + locn.y = -px_size * Math.floor(locn.y/px_size); + return locn; + } + + public void reset() { + // nothing + } + + private void bgLoadMap(final AltosSiteMapTile tile, + final File pngfile, final String pngurl) + { + //System.out.printf("Loading/fetching map %s\n", pngfile); + Thread thread = new Thread() { + public void run() { + ImageIcon res; + res = AltosSiteMapCache.fetchAndLoadMap(pngfile, pngurl); + if (res != null) { + tile.loadMap(res); + } else { + System.out.printf("# Failed to fetch file %s\n", pngfile); + System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl); + } + } + }; + thread.start(); + } + + public static void prefetchMaps(double lat, double lng, int w, int h) { + AltosPreferences.init(null); + + AltosSiteMap asm = new AltosSiteMap(true); + asm.centre = asm.getBaseLocation(lat, lng); + + Point2D.Double p = new Point2D.Double(); + Point2D.Double p2; + int dx = -w/2, dy = -h/2; + for (int y = dy; y < h+dy; y++) { + for (int x = dx; x < w+dx; x++) { + LatLng map_latlng = asm.latlng( + -asm.centre.x + x*px_size + px_size/2, + -asm.centre.y + y*px_size + px_size/2); + File pngfile = asm.MapFile(map_latlng.lat, map_latlng.lng); + String pngurl = asm.MapURL(map_latlng.lat, map_latlng.lng); + if (pngfile.exists()) { + System.out.printf("Already have %s\n", pngfile); + } else if (AltosSiteMapCache.fetchMap(pngfile, pngurl)) { + System.out.printf("Fetched map %s\n", pngfile); + } else { + System.out.printf("# Failed to fetch file %s\n", pngfile); + System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl); + } + } + } + } + + private void initMap(AltosSiteMapTile tile, Point offset) { + Point2D.Double coord = tileCoordOffset(offset); + + LatLng map_latlng = latlng(px_size/2-coord.x, px_size/2-coord.y); + + File pngfile = MapFile(map_latlng.lat, map_latlng.lng); + String pngurl = MapURL(map_latlng.lat, map_latlng.lng); + bgLoadMap(tile, pngfile, pngurl); + } + + private void initMaps(double lat, double lng) { + centre = getBaseLocation(lat, lng); + + for (Point k : mapTiles.keySet()) { + initMap(mapTiles.get(k), k); + } + } + + private File MapFile(double lat, double lng) { + char chlat = lat < 0 ? 'S' : 'N'; + char chlng = lng < 0 ? 'E' : 'W'; + if (lat < 0) lat = -lat; + if (lng < 0) lng = -lng; + return new File(AltosPreferences.logdir(), + String.format("map-%c%.6f,%c%.6f-%d.png", + chlat, lat, chlng, lng, zoom)); + } + + private String MapURL(double lat, double lng) { + return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=hybrid&format=png32", lat, lng, zoom, px_size, px_size); + } + + boolean initialised = false; + Point2D.Double last_pt = null; + int last_state = -1; + public void show(final AltosState state, final int crc_errors) { + // if insufficient gps data, nothing to update + if (state.gps == null) + return; + if (state.pad_lat == 0 && state.pad_lon == 0) + return; + if (!state.gps.locked) { + if (state.gps.nsat < 4) + return; + } + + if (!initialised) { + initMaps(state.pad_lat, state.pad_lon); + initialised = true; + } + + final Point2D.Double pt = pt(state.gps.lat, state.gps.lon); + if (last_pt == pt && last_state == state.state) + return; + + if (last_pt == null) { + last_pt = pt; + } + boolean in_any = false; + for (Point offset : mapTiles.keySet()) { + AltosSiteMapTile tile = mapTiles.get(offset); + Point2D.Double ref, lref; + ref = translatePoint(pt, tileCoordOffset(offset)); + lref = translatePoint(last_pt, tileCoordOffset(offset)); + tile.show(state, crc_errors, lref, ref); + if (0 <= ref.x && ref.x < px_size) + if (0 <= ref.y && ref.y < px_size) + in_any = true; + } + + Point offset = tileOffset(pt); + if (!in_any) { + Point2D.Double ref, lref; + ref = translatePoint(pt, tileCoordOffset(offset)); + lref = translatePoint(last_pt, tileCoordOffset(offset)); + + AltosSiteMapTile tile = createTile(offset); + tile.show(state, crc_errors, lref, ref); + initMap(tile, offset); + finishTileLater(tile, offset); + } + + scrollRocketToVisible(pt); + + if (offset != tileOffset(last_pt)) { + ensureTilesAround(offset); + } + + last_pt = pt; + last_state = state.state; + } + + private AltosSiteMapTile createTile(Point offset) { + AltosSiteMapTile tile = new AltosSiteMapTile(px_size); + mapTiles.put(offset, tile); + return tile; + } + private void finishTileLater(final AltosSiteMapTile tile, + final Point offset) + { + SwingUtilities.invokeLater( new Runnable() { + public void run() { + addTileAt(tile, offset); + } + } ); + } + + private void ensureTilesAround(Point base_offset) { + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + Point offset = new Point(base_offset.x + x, base_offset.y + y); + if (mapTiles.containsKey(offset)) + continue; + AltosSiteMapTile tile = createTile(offset); + initMap(tile, offset); + finishTileLater(tile, offset); + } + } + } + + private Point topleft = new Point(0,0); + private void scrollRocketToVisible(Point2D.Double pt) { + Rectangle r = comp.getVisibleRect(); + Point2D.Double copt = translatePoint(pt, tileCoordOffset(topleft)); + int dx = (int)copt.x - r.width/2 - r.x; + int dy = (int)copt.y - r.height/2 - r.y; + if (Math.abs(dx) > r.width/4 || Math.abs(dy) > r.height/4) { + r.x += dx; + r.y += dy; + comp.scrollRectToVisible(r); + } + } + + private void addTileAt(AltosSiteMapTile tile, Point offset) { + if (Math.abs(offset.x) >= MAX_TILE_DELTA || + Math.abs(offset.y) >= MAX_TILE_DELTA) + { + System.out.printf("Rocket too far away from pad (tile %d,%d)\n", + offset.x, offset.y); + return; + } + + boolean review = false; + Rectangle r = comp.getVisibleRect(); + if (offset.x < topleft.x) { + r.x += (topleft.x - offset.x) * px_size; + topleft.x = offset.x; + review = true; + } + if (offset.y < topleft.y) { + r.y += (topleft.y - offset.y) * px_size; + topleft.y = offset.y; + review = true; + } + GridBagConstraints c = new GridBagConstraints(); + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + // put some space between the map tiles, debugging only + // c.insets = new Insets(5, 5, 5, 5); + + c.gridx = offset.x + MAX_TILE_DELTA; + c.gridy = offset.y + MAX_TILE_DELTA; + layout.setConstraints(tile, c); + + comp.add(tile); + if (review) { + comp.scrollRectToVisible(r); + } + } + + private AltosSiteMap(boolean knowWhatYouAreDoing) { + if (!knowWhatYouAreDoing) { + throw new RuntimeException("Arggh."); + } + } + + JComponent comp = new JComponent() { }; + private GridBagLayout layout = new GridBagLayout(); + + public AltosSiteMap() { + GrabNDrag scroller = new GrabNDrag(comp); + + comp.setLayout(layout); + + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + Point offset = new Point(x, y); + AltosSiteMapTile t = createTile(offset); + addTileAt(t, offset); + } + } + setViewportView(comp); + setPreferredSize(new Dimension(500,200)); + } +} diff --git a/altosui/AltosSiteMapCache.java b/altosui/AltosSiteMapCache.java new file mode 100644 index 00000000..2e62cc45 --- /dev/null +++ b/altosui/AltosSiteMapCache.java @@ -0,0 +1,103 @@ +/* + * Copyright © 2010 Anthony Towns + * + * 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.image.*; +import java.awt.event.*; +import javax.swing.*; +import javax.imageio.ImageIO; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.net.URL; +import java.net.URLConnection; + +public class AltosSiteMapCache extends JLabel { + public static boolean fetchMap(File file, String url) { + URL u; + + try { + u = new URL(url); + } catch (java.net.MalformedURLException e) { + return false; + } + + byte[] data; + try { + URLConnection uc = u.openConnection(); + int contentLength = uc.getContentLength(); + InputStream in = new BufferedInputStream(uc.getInputStream()); + int bytesRead = 0; + int offset = 0; + data = new byte[contentLength]; + while (offset < contentLength) { + bytesRead = in.read(data, offset, data.length - offset); + if (bytesRead == -1) + break; + offset += bytesRead; + } + in.close(); + + if (offset != contentLength) { + return false; + } + } catch (IOException e) { + return false; + } + + try { + FileOutputStream out = new FileOutputStream(file); + out.write(data); + out.flush(); + out.close(); + } catch (FileNotFoundException e) { + return false; + } catch (IOException e) { + if (file.exists()) { + file.delete(); + } + return false; + } + return true; + } + + public static ImageIcon fetchAndLoadMap(File pngfile, String url) { + if (!pngfile.exists()) { + if (!fetchMap(pngfile, url)) { + return null; + } + } + return loadMap(pngfile, url); + } + + public static ImageIcon loadMap(File pngfile, String url) { + if (!pngfile.exists()) { + return null; + } + + try { + return new ImageIcon(ImageIO.read(pngfile)); + } catch (IOException e) { + System.out.printf("# IO error trying to load %s\n", pngfile); + return null; + } + } +} diff --git a/altosui/AltosSiteMapTile.java b/altosui/AltosSiteMapTile.java new file mode 100644 index 00000000..8301f42b --- /dev/null +++ b/altosui/AltosSiteMapTile.java @@ -0,0 +1,112 @@ +/* + * Copyright © 2010 Anthony Towns + * + * 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.image.*; +import java.awt.event.*; +import javax.swing.*; +import javax.imageio.ImageIO; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.lang.Math; +import java.awt.geom.Point2D; +import java.awt.geom.Line2D; + +public class AltosSiteMapTile extends JLayeredPane { + JLabel mapLabel; + JLabel draw; + Graphics2D g2d; + + public void loadMap(ImageIcon icn) { + mapLabel.setIcon(icn); + } + + static Color stateColors[] = { + Color.WHITE, // startup + Color.WHITE, // idle + Color.WHITE, // pad + Color.RED, // boost + Color.PINK, // fast + Color.YELLOW, // coast + Color.CYAN, // drogue + Color.BLUE, // main + Color.BLACK // landed + }; + + private boolean drawn_landed_circle = false; + private boolean drawn_boost_circle = false; + public synchronized void show(AltosState state, int crc_errors, + Point2D.Double last_pt, Point2D.Double pt) + { + if (0 <= state.state && state.state < stateColors.length) { + g2d.setColor(stateColors[state.state]); + } + g2d.draw(new Line2D.Double(last_pt, pt)); + + if (state.state == 3 && !drawn_boost_circle) { + drawn_boost_circle = true; + g2d.setColor(Color.RED); + g2d.drawOval((int)last_pt.x-5, (int)last_pt.y-5, 10, 10); + g2d.drawOval((int)last_pt.x-20, (int)last_pt.y-20, 40, 40); + g2d.drawOval((int)last_pt.x-35, (int)last_pt.y-35, 70, 70); + } + if (state.state == 8 && !drawn_landed_circle) { + drawn_landed_circle = true; + g2d.setColor(Color.BLACK); + g2d.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10); + g2d.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40); + g2d.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70); + } + + repaint(); + } + + public static Graphics2D fillLabel(JLabel l, Color c, int px_size) { + BufferedImage img = new BufferedImage(px_size, px_size, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = img.createGraphics(); + g.setColor(c); + g.fillRect(0, 0, px_size, px_size); + l.setIcon(new ImageIcon(img)); + return g; + } + + public AltosSiteMapTile(int px_size) { + setPreferredSize(new Dimension(px_size, px_size)); + + mapLabel = new JLabel(); + fillLabel(mapLabel, Color.GRAY, px_size); + mapLabel.setOpaque(true); + mapLabel.setBounds(0, 0, px_size, px_size); + add(mapLabel, new Integer(0)); + + draw = new JLabel(); + g2d = fillLabel(draw, new Color(127, 127, 127, 0), px_size); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + draw.setBounds(0, 0, px_size, px_size); + draw.setOpaque(false); + + add(draw, new Integer(1)); + } +} diff --git a/altosui/AltosState.java b/altosui/AltosState.java new file mode 100644 index 00000000..ec499d5a --- /dev/null +++ b/altosui/AltosState.java @@ -0,0 +1,197 @@ +/* + * 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. + */ + +/* + * Track flight state from telemetry or eeprom data stream + */ + +package altosui; + +public class AltosState { + AltosRecord data; + + /* derived data */ + + long report_time; + + double time_change; + int tick; + + int state; + boolean landed; + boolean ascent; /* going up? */ + + double ground_altitude; + double height; + double speed; + double acceleration; + double battery; + double temperature; + double main_sense; + double drogue_sense; + double baro_speed; + + double max_height; + double max_acceleration; + double max_speed; + + AltosGPS gps; + + double pad_lat; + double pad_lon; + double pad_alt; + + static final int MIN_PAD_SAMPLES = 10; + + int npad; + int ngps; + int gps_waiting; + boolean gps_ready; + + AltosGreatCircle from_pad; + double elevation; /* from pad */ + double range; /* total distance */ + + double gps_height; + + int speak_tick; + double speak_altitude; + + + void init (AltosRecord cur, AltosState prev_state) { + int i; + AltosRecord prev; + + data = cur; + + ground_altitude = data.ground_altitude(); + height = data.filtered_altitude() - ground_altitude; + + report_time = System.currentTimeMillis(); + + acceleration = data.acceleration(); + speed = data.accel_speed(); + temperature = data.temperature(); + drogue_sense = data.drogue_voltage(); + main_sense = data.main_voltage(); + battery = data.battery_voltage(); + tick = data.tick; + state = data.state; + + if (prev_state != null) { + + /* Preserve any existing gps data */ + npad = prev_state.npad; + ngps = prev_state.ngps; + gps = prev_state.gps; + pad_lat = prev_state.pad_lat; + pad_lon = prev_state.pad_lon; + pad_alt = prev_state.pad_alt; + max_height = prev_state.max_height; + max_acceleration = prev_state.max_acceleration; + max_speed = prev_state.max_speed; + + /* make sure the clock is monotonic */ + while (tick < prev_state.tick) + tick += 65536; + + time_change = (tick - prev_state.tick) / 100.0; + + /* compute barometric speed */ + + double height_change = height - prev_state.height; + if (time_change > 0) + baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; + else + baro_speed = prev_state.baro_speed; + } else { + npad = 0; + ngps = 0; + gps = null; + baro_speed = 0; + time_change = 0; + } + + if (state == Altos.ao_flight_pad) { + + /* Track consecutive 'good' gps reports, waiting for 10 of them */ + if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) + npad++; + else + npad = 0; + + /* Average GPS data while on the pad */ + if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) { + if (ngps > 1) { + /* filter pad position */ + pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0; + pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0; + pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0; + } else { + pad_lat = data.gps.lat; + pad_lon = data.gps.lon; + pad_alt = data.gps.alt; + } + ngps++; + } + } + + gps_waiting = MIN_PAD_SAMPLES - npad; + if (gps_waiting < 0) + gps_waiting = 0; + + gps_ready = gps_waiting == 0; + + ascent = (Altos.ao_flight_boost <= state && + state <= Altos.ao_flight_coast); + + /* Only look at accelerometer data on the way up */ + if (ascent && acceleration > max_acceleration) + max_acceleration = acceleration; + if (ascent && speed > max_speed) + max_speed = speed; + + if (height > max_height) + max_height = height; + if (data.gps != null) { + if (gps == null || !gps.locked || data.gps.locked) + gps = data.gps; + if (ngps > 0 && gps.locked) { + from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); + } + } + elevation = 0; + range = -1; + if (ngps > 0) { + gps_height = gps.alt - pad_alt; + if (from_pad != null) { + elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; + range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); + } + } else { + gps_height = 0; + } + } + + public AltosState(AltosRecord cur) { + init(cur, null); + } + + public AltosState (AltosRecord cur, AltosState prev) { + init(cur, prev); + } +} diff --git a/altosui/AltosTelemetry.java b/altosui/AltosTelemetry.java new file mode 100644 index 00000000..bdb6466a --- /dev/null +++ b/altosui/AltosTelemetry.java @@ -0,0 +1,143 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * The telemetry data stream is a bit of a mess at present, with no consistent + * formatting. In particular, the GPS data is formatted for viewing instead of parsing. + * However, the key feature is that every telemetry line contains all of the information + * necessary to describe the current rocket state, including the calibration values + * for accelerometer and barometer. + * + * GPS unlocked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ + * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ + * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 + * + * GPS locked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ + * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ + * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ + * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ + * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ + * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 + */ + +public class AltosTelemetry extends AltosRecord { + public AltosTelemetry(String line) throws ParseException, AltosCRCException { + String[] words = line.split("\\s+"); + int i = 0; + + if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(words[i++], "RSSI"); + rssi = AltosParse.parse_int(words[i++]); + throw new AltosCRCException(rssi); + } + if (words[i].equals("CALL")) { + version = 0; + } else { + AltosParse.word (words[i++], "VERSION"); + version = AltosParse.parse_int(words[i++]); + } + + AltosParse.word (words[i++], "CALL"); + callsign = words[i++]; + + AltosParse.word (words[i++], "SERIAL"); + serial = AltosParse.parse_int(words[i++]); + + if (version >= 2) { + AltosParse.word (words[i++], "FLIGHT"); + flight = AltosParse.parse_int(words[i++]); + } else + flight = 0; + + AltosParse.word(words[i++], "RSSI"); + rssi = AltosParse.parse_int(words[i++]); + + /* Older telemetry data had mis-computed RSSI value */ + if (version <= 2) + rssi = (rssi + 74) / 2 - 74; + + AltosParse.word(words[i++], "STATUS"); + status = AltosParse.parse_hex(words[i++]); + + AltosParse.word(words[i++], "STATE"); + state = Altos.state(words[i++]); + + tick = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a:"); + accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "p:"); + pres = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "t:"); + temp = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "v:"); + batt = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "d:"); + drogue = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "m:"); + main = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fa:"); + flight_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "ga:"); + ground_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fv:"); + flight_vel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fp:"); + flight_pres = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "gp:"); + ground_pres = AltosParse.parse_int(words[i++]); + + if (version >= 1) { + AltosParse.word(words[i++], "a+:"); + accel_plus_g = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a-:"); + accel_minus_g = AltosParse.parse_int(words[i++]); + } else { + accel_plus_g = ground_accel; + accel_minus_g = ground_accel + 530; + } + + gps = new AltosGPS(words, i, version); + } +} diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java new file mode 100644 index 00000000..a71ab872 --- /dev/null +++ b/altosui/AltosTelemetryIterable.java @@ -0,0 +1,82 @@ +/* + * 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 altosui; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosTelemetryIterable extends AltosRecordIterable { + LinkedList records; + + public Iterator iterator () { + return records.iterator(); + } + + public AltosTelemetryIterable (FileInputStream input) { + boolean saw_boost = false; + int current_tick = 0; + int boost_tick = 0; + + records = new LinkedList (); + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) { + break; + } + try { + AltosTelemetry record = new AltosTelemetry(line); + if (record == null) + break; + if (records.isEmpty()) { + current_tick = record.tick; + } else { + int tick = record.tick | (current_tick & ~ 0xffff); + if (tick < current_tick - 0x1000) + tick += 0x10000; + current_tick = tick; + record.tick = current_tick; + } + if (!saw_boost && record.state >= Altos.ao_flight_boost) + { + saw_boost = true; + boost_tick = record.tick; + } + records.add(record); + } catch (ParseException pe) { + System.out.printf("parse exception %s\n", pe.getMessage()); + } catch (AltosCRCException ce) { + System.out.printf("crc error\n"); + } + } + } catch (IOException io) { + System.out.printf("io exception\n"); + } + + /* adjust all tick counts to be relative to boost time */ + for (AltosRecord r : this) + r.time = (r.tick - boost_tick) / 100.0; + + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java new file mode 100644 index 00000000..6c5a9397 --- /dev/null +++ b/altosui/AltosTelemetryReader.java @@ -0,0 +1,61 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +class AltosTelemetryReader extends AltosFlightReader { + AltosDevice device; + AltosSerial serial; + AltosLog log; + + LinkedBlockingQueue telem; + + AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { + AltosLine l = telem.take(); + if (l.line == null) + throw new IOException("IO error"); + return new AltosTelemetry(l.line); + } + + void close(boolean interrupted) { + serial.remove_monitor(telem); + log.close(); + serial.close(); + } + + void set_channel(int channel) { + serial.set_channel(channel); + AltosPreferences.set_channel(device.getSerial(), channel); + } + + public AltosTelemetryReader (AltosDevice in_device) + throws FileNotFoundException, AltosSerialInUseException, IOException { + device = in_device; + serial = new AltosSerial(device); + log = new AltosLog(serial); + name = device.toShortString(); + + telem = new LinkedBlockingQueue(); + serial.set_radio(); + serial.add_monitor(telem); + } +} diff --git a/altosui/AltosUI.app/Contents/Info.plist b/altosui/AltosUI.app/Contents/Info.plist new file mode 100644 index 00000000..97b1b59c --- /dev/null +++ b/altosui/AltosUI.app/Contents/Info.plist @@ -0,0 +1,38 @@ + + + + + CFBundleName + altosui + CFBundleVersion + 100.0 + CFBundleAllowMixedLocalizations + true + CFBundleExecutable + JavaApplicationStub + CFBundleDevelopmentRegion + English + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleGetInfoString + AltOS UI version 0.7 + CFBundleInfoDictionaryVersion + 6.0 + CFBundleIconFile + AltosUIIcon.icns + Java + + MainClass + altosui.AltosUI + JVMVersion + 1.5+ + ClassPath + + $JAVAROOT/altosui.jar + $JAVAROOT/freetts.jar + + + + diff --git a/altosui/AltosUI.app/Contents/MacOS/JavaApplicationStub b/altosui/AltosUI.app/Contents/MacOS/JavaApplicationStub new file mode 100755 index 00000000..c661d3e1 Binary files /dev/null and b/altosui/AltosUI.app/Contents/MacOS/JavaApplicationStub differ diff --git a/altosui/AltosUI.app/Contents/PkgInfo b/altosui/AltosUI.app/Contents/PkgInfo new file mode 100644 index 00000000..8a43480f --- /dev/null +++ b/altosui/AltosUI.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPLAM.O diff --git a/altosui/AltosUI.app/Contents/Resources/AltosUIIcon.icns b/altosui/AltosUI.app/Contents/Resources/AltosUIIcon.icns new file mode 100644 index 00000000..fe49f362 Binary files /dev/null and b/altosui/AltosUI.app/Contents/Resources/AltosUIIcon.icns differ diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java new file mode 100644 index 00000000..94c4dd2a --- /dev/null +++ b/altosui/AltosUI.java @@ -0,0 +1,405 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +import libaltosJNI.*; + +public class AltosUI extends JFrame { + public AltosVoice voice = new AltosVoice(); + + public static boolean load_library(Frame frame) { + if (!AltosDevice.load_library()) { + JOptionPane.showMessageDialog(frame, + String.format("No AltOS library in \"%s\"", + System.getProperty("java.library.path","")), + "Cannot load device access library", + JOptionPane.ERROR_MESSAGE); + return false; + } + return true; + } + + void telemetry_window(AltosDevice device) { + try { + AltosFlightReader reader = new AltosTelemetryReader(device); + if (reader != null) + new AltosFlightUI(voice, reader, device.getSerial()); + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(AltosUI.this, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(AltosUI.this, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException ee) { + JOptionPane.showMessageDialog(AltosUI.this, + device.toShortString(), + "Unkonwn I/O error", + JOptionPane.ERROR_MESSAGE); + } + } + + Container pane; + GridBagLayout gridbag; + + JButton addButton(int x, int y, String label) { + GridBagConstraints c; + JButton b; + + c = new GridBagConstraints(); + c.gridx = x; c.gridy = y; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + b = new JButton(label); + + Dimension ps = b.getPreferredSize(); + + gridbag.setConstraints(b, c); + add(b, c); + return b; + } + + public AltosUI() { + + load_library(null); + + java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg"); + if (imgURL != null) + setIconImage(new ImageIcon(imgURL).getImage()); + + AltosPreferences.init(this); + + pane = getContentPane(); + gridbag = new GridBagLayout(); + pane.setLayout(gridbag); + + JButton b; + + b = addButton(0, 0, "Monitor Flight"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ConnectToDevice(); + } + }); + b = addButton(1, 0, "Save Flight Data"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + SaveFlightData(); + } + }); + b = addButton(2, 0, "Replay Flight"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Replay(); + } + }); + b = addButton(3, 0, "Graph Data"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + GraphData(); + } + }); + b = addButton(4, 0, "Export Data"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ExportData(); + } + }); + b = addButton(0, 1, "Configure TeleMetrum"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ConfigureTeleMetrum(); + } + }); + + b = addButton(1, 1, "Configure AltosUI"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ConfigureAltosUI(); + } + }); + + b = addButton(2, 1, "Flash Image"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + FlashImage(); + } + }); + + b = addButton(3, 1, "Fire Igniter"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + FireIgniter(); + } + }); + + b = addButton(4, 1, "Quit"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.exit(0); + } + }); + + setTitle("AltOS"); + + pane.doLayout(); + pane.validate(); + + doLayout(); + validate(); + + setVisible(true); + + Insets i = getInsets(); + Dimension ps = rootPane.getPreferredSize(); + ps.width += i.left + i.right; + ps.height += i.top + i.bottom; + setPreferredSize(ps); + setSize(ps); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + } + + private void ConnectToDevice() { + AltosDevice device = AltosDeviceDialog.show(AltosUI.this, + AltosDevice.product_basestation); + + if (device != null) + telemetry_window(device); + } + + void ConfigureCallsign() { + String result; + result = JOptionPane.showInputDialog(AltosUI.this, + "Configure Callsign", + AltosPreferences.callsign()); + if (result != null) + AltosPreferences.set_callsign(result); + } + + void ConfigureTeleMetrum() { + new AltosConfig(AltosUI.this); + } + + void FlashImage() { + new AltosFlashUI(AltosUI.this); + } + + void FireIgniter() { + new AltosIgniteUI(AltosUI.this); + } + + /* + * Replay a flight from telemetry data + */ + private void Replay() { + AltosDataChooser chooser = new AltosDataChooser( + AltosUI.this); + + AltosRecordIterable iterable = chooser.runDialog(); + if (iterable != null) { + AltosFlightReader reader = new AltosReplayReader(iterable.iterator(), + chooser.filename()); + new AltosFlightUI(voice, reader); + } + } + + /* Connect to TeleMetrum, either directly or through + * a TeleDongle over the packet link + */ + private void SaveFlightData() { + new AltosEepromDownload(AltosUI.this); + } + + /* Load a flight log file and write out a CSV file containing + * all of the data in standard units + */ + + private void ExportData() { + AltosDataChooser chooser; + chooser = new AltosDataChooser(this); + AltosRecordIterable record_reader = chooser.runDialog(); + if (record_reader == null) + return; + new AltosCSVUI(AltosUI.this, record_reader, chooser.file()); + } + + /* Load a flight log CSV file and display a pretty graph. + */ + + private void GraphData() { + AltosDataChooser chooser; + chooser = new AltosDataChooser(this); + AltosRecordIterable record_reader = chooser.runDialog(); + if (record_reader == null) + return; + new AltosGraphUI(record_reader); + } + + private void ConfigureAltosUI() { + new AltosConfigureUI(AltosUI.this, voice); + } + + static AltosRecordIterable open_logfile(String filename) { + File file = new File (filename); + try { + FileInputStream in; + + in = new FileInputStream(file); + if (filename.endsWith("eeprom")) + return new AltosEepromIterable(in); + else + return new AltosTelemetryIterable(in); + } catch (FileNotFoundException fe) { + System.out.printf("Cannot open '%s'\n", filename); + return null; + } + } + + static AltosWriter open_csv(String filename) { + File file = new File (filename); + try { + return new AltosCSV(file); + } catch (FileNotFoundException fe) { + System.out.printf("Cannot open '%s'\n", filename); + return null; + } + } + + static AltosWriter open_kml(String filename) { + File file = new File (filename); + try { + return new AltosKML(file); + } catch (FileNotFoundException fe) { + System.out.printf("Cannot open '%s'\n", filename); + return null; + } + } + + static final int process_csv = 1; + static final int process_kml = 2; + + static void process_file(String input, int process) { + AltosRecordIterable iterable = open_logfile(input); + if (iterable == null) + return; + if (process == 0) + process = process_csv; + if ((process & process_csv) != 0) { + String output = Altos.replace_extension(input,".csv"); + System.out.printf("Processing \"%s\" to \"%s\"\n", input, output); + if (input.equals(output)) { + System.out.printf("Not processing '%s'\n", input); + } else { + AltosWriter writer = open_csv(output); + if (writer != null) { + writer.write(iterable); + writer.close(); + } + } + } + if ((process & process_kml) != 0) { + String output = Altos.replace_extension(input,".kml"); + System.out.printf("Processing \"%s\" to \"%s\"\n", input, output); + if (input.equals(output)) { + System.out.printf("Not processing '%s'\n", input); + } else { + AltosWriter writer = open_kml(output); + if (writer == null) + return; + writer.write(iterable); + writer.close(); + } + } + } + + public static void main(final String[] args) { + int process = 0; + /* Handle batch-mode */ + if (args.length == 1 && args[0].equals("--help")) { + System.out.printf("Usage: altosui [OPTION]... [FILE]...\n"); + System.out.printf(" Options:\n"); + System.out.printf(" --fetchmaps \tpre-fetch maps for site map view\n"); + System.out.printf(" --replay \t\trelive the glory of past flights \n"); + System.out.printf(" --csv\tgenerate comma separated output for spreadsheets, etc\n"); + System.out.printf(" --kml\tgenerate KML output for use with Google Earth\n"); + } else if (args.length == 3 && args[0].equals("--fetchmaps")) { + double lat = Double.parseDouble(args[1]); + double lon = Double.parseDouble(args[2]); + AltosSiteMap.prefetchMaps(lat, lon, 5, 5); + } else if (args.length == 2 && args[0].equals("--replay")) { + String filename = args[1]; + FileInputStream in; + try { + in = new FileInputStream(filename); + } catch (Exception e) { + System.out.printf("Failed to open file '%s'\n", filename); + return; + } + AltosRecordIterable recs; + AltosReplayReader reader; + if (filename.endsWith("eeprom")) { + recs = new AltosEepromIterable(in); + } else { + recs = new AltosTelemetryIterable(in); + } + reader = new AltosReplayReader(recs.iterator(), filename); + AltosFlightUI flight_ui = new AltosFlightUI(new AltosVoice(), reader); + flight_ui.set_exit_on_close(); + return; + } else if (args.length > 0) { + for (int i = 0; i < args.length; i++) { + if (args[i].equals("--kml")) + process |= process_kml; + else if (args[i].equals("--csv")) + process |= process_csv; + else + process_file(args[i], process); + } + } else { + AltosUI altosui = new AltosUI(); + altosui.setVisible(true); + + AltosDevice[] devices = AltosDevice.list(AltosDevice.product_basestation); + for (int i = 0; i < devices.length; i++) + altosui.telemetry_window(devices[i]); + } + } +} diff --git a/altosui/AltosVoice.java b/altosui/AltosVoice.java new file mode 100644 index 00000000..ac13ee14 --- /dev/null +++ b/altosui/AltosVoice.java @@ -0,0 +1,95 @@ +/* + * 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 altosui; + +import com.sun.speech.freetts.Voice; +import com.sun.speech.freetts.VoiceManager; +import com.sun.speech.freetts.audio.JavaClipAudioPlayer; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosVoice implements Runnable { + VoiceManager voice_manager; + Voice voice; + LinkedBlockingQueue phrases; + Thread thread; + boolean busy; + + final static String voice_name = "kevin16"; + + public void run() { + try { + for (;;) { + String s = phrases.take(); + voice.speak(s); + synchronized(this) { + if (phrases.isEmpty()) { + busy = false; + notifyAll(); + } + } + } + } catch (InterruptedException e) { + } + } + + public synchronized void drain() throws InterruptedException { + while (busy) + wait(); + } + + public void speak_always(String s) { + try { + if (voice != null) { + synchronized(this) { + busy = true; + phrases.put(s); + } + } + } catch (InterruptedException e) { + } + } + + public void speak(String s) { + if (AltosPreferences.voice()) + speak_always(s); + } + + public void speak(String format, Object... parameters) { + speak(String.format(format, parameters)); + } + + public AltosVoice () { + busy = false; + voice_manager = VoiceManager.getInstance(); + voice = voice_manager.getVoice(voice_name); + if (voice != null) { + voice.allocate(); + phrases = new LinkedBlockingQueue (); + thread = new Thread(this); + thread.start(); + } else { + System.out.printf("Voice manager failed to open %s\n", voice_name); + Voice[] voices = voice_manager.getVoices(); + System.out.printf("Available voices:\n"); + for (int i = 0; i < voices.length; i++) { + System.out.println(" " + voices[i].getName() + + " (" + voices[i].getDomain() + " domain)"); + } + } + } +} diff --git a/altosui/AltosWriter.java b/altosui/AltosWriter.java new file mode 100644 index 00000000..a172dff0 --- /dev/null +++ b/altosui/AltosWriter.java @@ -0,0 +1,32 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.io.*; +import java.text.*; +import java.util.*; + +public interface AltosWriter { + + public void write(AltosRecord record); + + public void write(AltosRecordIterable iterable); + + public void close(); +} diff --git a/altosui/GrabNDrag.java b/altosui/GrabNDrag.java new file mode 100644 index 00000000..e6b87b58 --- /dev/null +++ b/altosui/GrabNDrag.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2010 Anthony Towns + * + * 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.image.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.MouseInputAdapter; +import javax.imageio.ImageIO; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; + +class GrabNDrag extends MouseInputAdapter { + private JComponent scroll; + private Point startPt = new Point(); + + public GrabNDrag(JComponent scroll) { + this.scroll = scroll; + scroll.addMouseMotionListener(this); + scroll.addMouseListener(this); + scroll.setAutoscrolls(true); + } + + public void mousePressed(MouseEvent e) { + startPt.setLocation(e.getPoint()); + } + public void mouseDragged(MouseEvent e) { + int xd = e.getX() - startPt.x; + int yd = e.getY() - startPt.y; + + Rectangle r = scroll.getVisibleRect(); + r.x -= xd; + r.y -= yd; + scroll.scrollRectToVisible(r); + } +} diff --git a/altosui/Instdrv/NSIS/Contrib/InstDrv/Example.nsi b/altosui/Instdrv/NSIS/Contrib/InstDrv/Example.nsi new file mode 100644 index 00000000..3ed821eb --- /dev/null +++ b/altosui/Instdrv/NSIS/Contrib/InstDrv/Example.nsi @@ -0,0 +1,84 @@ +# +# InstDrv Example, (c) 2003 Jan Kiszka (Jan Kiszka@web.de) +# + +Name "InstDrv.dll test" + +OutFile "InstDrv-Test.exe" + +ShowInstDetails show + +ComponentText "InstDrv Plugin Usage Example" + +Page components +Page instfiles + +Section "Install a Driver" InstDriver + InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k" + Pop $0 + DetailPrint "InitDriverSetup: $0" + + InstDrv::DeleteOemInfFiles /NOUNLOAD + Pop $0 + DetailPrint "DeleteOemInfFiles: $0" + StrCmp $0 "00000000" PrintInfNames ContInst1 + + PrintInfNames: + Pop $0 + DetailPrint "Deleted $0" + Pop $0 + DetailPrint "Deleted $0" + + ContInst1: + InstDrv::CreateDevice /NOUNLOAD + Pop $0 + DetailPrint "CreateDevice: $0" + + SetOutPath $TEMP + File "ircomm2k.inf" + File "ircomm2k.sys" + + InstDrv::InstallDriver /NOUNLOAD "$TEMP\ircomm2k.inf" + Pop $0 + DetailPrint "InstallDriver: $0" + StrCmp $0 "00000000" PrintReboot ContInst2 + + PrintReboot: + Pop $0 + DetailPrint "Reboot: $0" + + ContInst2: + InstDrv::CountDevices + Pop $0 + DetailPrint "CountDevices: $0" +SectionEnd + +Section "Uninstall the driver again" UninstDriver + InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k" + Pop $0 + DetailPrint "InitDriverSetup: $0" + + InstDrv::DeleteOemInfFiles /NOUNLOAD + Pop $0 + DetailPrint "DeleteOemInfFiles: $0" + StrCmp $0 "00000000" PrintInfNames ContUninst1 + + PrintInfNames: + Pop $0 + DetailPrint "Deleted $0" + Pop $0 + DetailPrint "Deleted $0" + + ContUninst1: + InstDrv::RemoveAllDevices + Pop $0 + DetailPrint "RemoveAllDevices: $0" + StrCmp $0 "00000000" PrintReboot ContUninst2 + + PrintReboot: + Pop $0 + DetailPrint "Reboot: $0" + + ContUninst2: + Delete "$SYSDIR\system32\ircomm2k.sys" +SectionEnd \ No newline at end of file diff --git a/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe b/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe new file mode 100644 index 00000000..615bae15 Binary files /dev/null and b/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe differ diff --git a/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.c b/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.c new file mode 100644 index 00000000..efe866e9 --- /dev/null +++ b/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.c @@ -0,0 +1,704 @@ +/* + +InstDrv.dll - Installs or Removes Device Drivers + +Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment in the + product documentation would be appreciated but is not required. +2. Altered versions must be plainly marked as such, + and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any distribution. + +*/ + + +#include +#include +#include +#include "../exdll/exdll.h" + + +char paramBuf[1024]; +GUID devClass; +char hwIdBuf[1024]; +int initialized = 0; + + + +void* memset(void* dst, int val, unsigned int len) +{ + while (len-- > 0) + *((char *)dst)++ = val; + + return NULL; +} + + + +void* memcpy(void* dst, const void* src, unsigned int len) +{ + while (len-- > 0) + *((char *)dst)++ = *((char *)src)++; + + return NULL; +} + + + +int HexCharToInt(char c) +{ + if ((c >= '0') && (c <= '9')) + return c - '0'; + else if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + else if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + else + return -1; +} + + + +BOOLEAN HexStringToUInt(char* str, int width, void* valBuf) +{ + int i, val; + + + for (i = width - 4; i >= 0; i -= 4) + { + val = HexCharToInt(*str++); + if (val < 0) + return FALSE; + *(unsigned int *)valBuf += val << i; + } + + return TRUE; +} + + + +BOOLEAN StringToGUID(char* guidStr, GUID* pGuid) +{ + int i; + + + memset(pGuid, 0, sizeof(GUID)); + + if (*guidStr++ != '{') + return FALSE; + + if (!HexStringToUInt(guidStr, 32, &pGuid->Data1)) + return FALSE; + guidStr += 8; + + if (*guidStr++ != '-') + return FALSE; + + if (!HexStringToUInt(guidStr, 16, &pGuid->Data2)) + return FALSE; + guidStr += 4; + + if (*guidStr++ != '-') + return FALSE; + + if (!HexStringToUInt(guidStr, 16, &pGuid->Data3)) + return FALSE; + guidStr += 4; + + if (*guidStr++ != '-') + return FALSE; + + for (i = 0; i < 2; i++) + { + if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i])) + return FALSE; + guidStr += 2; + } + + if (*guidStr++ != '-') + return FALSE; + + for (i = 2; i < 8; i++) + { + if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i])) + return FALSE; + guidStr += 2; + } + + if (*guidStr++ != '}') + return FALSE; + + return TRUE; +} + + + +DWORD FindNextDevice(HDEVINFO devInfoSet, SP_DEVINFO_DATA* pDevInfoData, DWORD* pIndex) +{ + DWORD buffersize = 0; + LPTSTR buffer = NULL; + DWORD dataType; + DWORD result; + + + while (1) + { + if (!SetupDiEnumDeviceInfo(devInfoSet, (*pIndex)++, pDevInfoData)) + { + result = GetLastError(); + break; + } + + GetDeviceRegistryProperty: + if (!SetupDiGetDeviceRegistryProperty(devInfoSet, pDevInfoData, SPDRP_HARDWAREID, + &dataType, (PBYTE)buffer, buffersize, + &buffersize)) + { + result = GetLastError(); + + if (result == ERROR_INSUFFICIENT_BUFFER) + { + if (buffer != NULL) + LocalFree(buffer); + + buffer = (LPTSTR)LocalAlloc(LPTR, buffersize); + + if (buffer == NULL) + break; + + goto GetDeviceRegistryProperty; + } + else if (result == ERROR_INVALID_DATA) + continue; // ignore invalid entries + else + break; // break on other errors + } + + if (lstrcmpi(buffer, hwIdBuf) == 0) + { + result = 0; + break; + } + } + + if (buffer != NULL) + LocalFree(buffer); + + return result; +} + + + +DWORD FindFirstDevice(HWND hwndParent, const GUID* pDevClass, const LPTSTR hwId, + HDEVINFO* pDevInfoSet, SP_DEVINFO_DATA* pDevInfoData, + DWORD *pIndex, DWORD flags) +{ + DWORD result; + + + *pDevInfoSet = SetupDiGetClassDevs((GUID*)pDevClass, NULL, hwndParent, flags); + if (*pDevInfoSet == INVALID_HANDLE_VALUE) + return GetLastError(); + + pDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA); + *pIndex = 0; + + result = FindNextDevice(*pDevInfoSet, pDevInfoData, pIndex); + + if (result != 0) + SetupDiDestroyDeviceInfoList(*pDevInfoSet); + + return result; +} + + + +/* + * InstDrv::InitDriverSetup devClass drvHWID + * + * devClass - GUID of the driver's device setup class + * drvHWID - Hardware ID of the supported device + * + * Return: + * result - error message, empty on success + */ +void __declspec(dllexport) InitDriverSetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +{ + EXDLL_INIT(); + + /* convert class GUID */ + popstring(paramBuf); + + if (!StringToGUID(paramBuf, &devClass)) + { + popstring(paramBuf); + pushstring("Invalid GUID!"); + return; + } + + /* get hardware ID */ + memset(hwIdBuf, 0, sizeof(hwIdBuf)); + popstring(hwIdBuf); + + initialized = 1; + pushstring(""); +} + + + +/* + * InstDrv::CountDevices + * + * Return: + * result - Number of installed devices the driver supports + */ +void __declspec(dllexport) CountDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +{ + HDEVINFO devInfoSet; + SP_DEVINFO_DATA devInfoData; + int count = 0; + char countBuf[16]; + DWORD index; + DWORD result; + + + EXDLL_INIT(); + + if (!initialized) + { + pushstring("Fatal error!"); + return; + } + + result = FindFirstDevice(hwndParent, &devClass, hwIdBuf, &devInfoSet, &devInfoData, + &index, DIGCF_PRESENT); + if (result != 0) + { + pushstring("0"); + return; + } + + do + { + count++; + } while (FindNextDevice(devInfoSet, &devInfoData, &index) == 0); + + SetupDiDestroyDeviceInfoList(devInfoSet); + + wsprintf(countBuf, "%d", count); + pushstring(countBuf); +} + + + +/* + * InstDrv::CreateDevice + * + * Return: + * result - Windows error code + */ +void __declspec(dllexport) CreateDevice(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +{ + HDEVINFO devInfoSet; + SP_DEVINFO_DATA devInfoData; + DWORD result = 0; + char resultBuf[16]; + + + EXDLL_INIT(); + + if (!initialized) + { + pushstring("Fatal error!"); + return; + } + + devInfoSet = SetupDiCreateDeviceInfoList(&devClass, hwndParent); + if (devInfoSet == INVALID_HANDLE_VALUE) + { + wsprintf(resultBuf, "%08X", GetLastError()); + pushstring(resultBuf); + return; + } + + devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + if (!SetupDiCreateDeviceInfo(devInfoSet, hwIdBuf, &devClass, NULL, + hwndParent, DICD_GENERATE_ID, &devInfoData)) + { + result = GetLastError(); + goto InstallCleanup; + } + + if (!SetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID, + hwIdBuf, (lstrlen(hwIdBuf)+2)*sizeof(TCHAR))) + { + result = GetLastError(); + goto InstallCleanup; + } + + if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData)) + result = GetLastError(); + + InstallCleanup: + SetupDiDestroyDeviceInfoList(devInfoSet); + + wsprintf(resultBuf, "%08X", result); + pushstring(resultBuf); +} + + + +/* + * InstDrv::InstallDriver infPath + * + * Return: + * result - Windows error code + * reboot - non-zero if reboot is required + */ +void __declspec(dllexport) InstallDriver(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +{ + char resultBuf[16]; + BOOL reboot; + + + EXDLL_INIT(); + popstring(paramBuf); + + if (!initialized) + { + pushstring("Fatal error!"); + return; + } + + if (!UpdateDriverForPlugAndPlayDevices(hwndParent, hwIdBuf, paramBuf, + INSTALLFLAG_FORCE, &reboot)) + { + wsprintf(resultBuf, "%08X", GetLastError()); + pushstring(resultBuf); + } + else + { + wsprintf(resultBuf, "%d", reboot); + pushstring(resultBuf); + pushstring("00000000"); + } +} + + + +/* + * InstDrv::DeleteOemInfFiles + * + * Return: + * result - Windows error code + * oeminf - Path of the deleted devices setup file (oemXX.inf) + * oempnf - Path of the deleted devices setup file (oemXX.pnf) + */ +void __declspec(dllexport) DeleteOemInfFiles(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +{ + HDEVINFO devInfo; + SP_DEVINFO_DATA devInfoData; + SP_DRVINFO_DATA drvInfoData; + SP_DRVINFO_DETAIL_DATA drvInfoDetail; + DWORD index; + DWORD result; + char resultBuf[16]; + + + if (!initialized) + { + pushstring("Fatal error!"); + return; + } + + result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0); + if (result != 0) + goto Cleanup1; + + if (!SetupDiBuildDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER)) + { + result = GetLastError(); + goto Cleanup2; + } + + drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA); + drvInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); + + if (!SetupDiEnumDriverInfo(devInfo, &devInfoData, SPDIT_COMPATDRIVER, 0, &drvInfoData)) + { + result = GetLastError(); + goto Cleanup3; + } + + if (!SetupDiGetDriverInfoDetail(devInfo, &devInfoData, &drvInfoData, + &drvInfoDetail, sizeof(drvInfoDetail), NULL)) + { + result = GetLastError(); + + if (result != ERROR_INSUFFICIENT_BUFFER) + goto Cleanup3; + + result = 0; + } + + pushstring(drvInfoDetail.InfFileName); + if (!DeleteFile(drvInfoDetail.InfFileName)) + result = GetLastError(); + else + { + index = lstrlen(drvInfoDetail.InfFileName); + if (index > 3) + { + lstrcpy(drvInfoDetail.InfFileName+index-3, "pnf"); + pushstring(drvInfoDetail.InfFileName); + if (!DeleteFile(drvInfoDetail.InfFileName)) + result = GetLastError(); + } + } + + Cleanup3: + SetupDiDestroyDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER); + + Cleanup2: + SetupDiDestroyDeviceInfoList(devInfo); + + Cleanup1: + wsprintf(resultBuf, "%08X", result); + pushstring(resultBuf); +} + + + +/* + * InstDrv::RemoveAllDevices + * + * Return: + * result - Windows error code + * reboot - non-zero if reboot is required + */ +void __declspec(dllexport) RemoveAllDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +{ + HDEVINFO devInfo; + SP_DEVINFO_DATA devInfoData; + DWORD index; + DWORD result; + char resultBuf[16]; + BOOL reboot = FALSE; + SP_DEVINSTALL_PARAMS instParams; + + + EXDLL_INIT(); + + if (!initialized) + { + pushstring("Fatal error!"); + return; + } + + result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0); + if (result != 0) + goto Cleanup1; + + do + { + if (!SetupDiCallClassInstaller(DIF_REMOVE, devInfo, &devInfoData)) + { + result = GetLastError(); + break; + } + + instParams.cbSize = sizeof(instParams); + if (!reboot && + SetupDiGetDeviceInstallParams(devInfo, &devInfoData, &instParams) && + ((instParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0)) + { + reboot = TRUE; + } + + result = FindNextDevice(devInfo, &devInfoData, &index); + } while (result == 0); + + SetupDiDestroyDeviceInfoList(devInfo); + + Cleanup1: + if ((result == 0) || (result == ERROR_NO_MORE_ITEMS)) + { + wsprintf(resultBuf, "%d", reboot); + pushstring(resultBuf); + pushstring("00000000"); + } + else + { + wsprintf(resultBuf, "%08X", result); + pushstring(resultBuf); + } +} + + + +/* + * InstDrv::StartSystemService serviceName + * + * Return: + * result - Windows error code + */ +void __declspec(dllexport) StartSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +{ + SC_HANDLE managerHndl; + SC_HANDLE svcHndl; + SERVICE_STATUS svcStatus; + DWORD oldCheckPoint; + DWORD result; + char resultBuf[16]; + + + EXDLL_INIT(); + popstring(paramBuf); + + managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (managerHndl == NULL) + { + result = GetLastError(); + goto Cleanup1; + } + + svcHndl = OpenService(managerHndl, paramBuf, SERVICE_START | SERVICE_QUERY_STATUS); + if (svcHndl == NULL) + { + result = GetLastError(); + goto Cleanup2; + } + + if (!StartService(svcHndl, 0, NULL) || !QueryServiceStatus(svcHndl, &svcStatus)) + { + result = GetLastError(); + goto Cleanup3; + } + + while (svcStatus.dwCurrentState == SERVICE_START_PENDING) + { + oldCheckPoint = svcStatus.dwCheckPoint; + + Sleep(svcStatus.dwWaitHint); + + if (!QueryServiceStatus(svcHndl, &svcStatus)) + { + result = GetLastError(); + break; + } + + if (oldCheckPoint >= svcStatus.dwCheckPoint) + { + if ((svcStatus.dwCurrentState == SERVICE_STOPPED) && + (svcStatus.dwWin32ExitCode != 0)) + result = svcStatus.dwWin32ExitCode; + else + result = ERROR_SERVICE_REQUEST_TIMEOUT; + } + } + + if (svcStatus.dwCurrentState == SERVICE_RUNNING) + result = 0; + + Cleanup3: + CloseServiceHandle(svcHndl); + + Cleanup2: + CloseServiceHandle(managerHndl); + + Cleanup1: + wsprintf(resultBuf, "%08X", result); + pushstring(resultBuf); +} + + + +/* + * InstDrv::StopSystemService serviceName + * + * Return: + * result - Windows error code + */ +void __declspec(dllexport) StopSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +{ + SC_HANDLE managerHndl; + SC_HANDLE svcHndl; + SERVICE_STATUS svcStatus; + DWORD oldCheckPoint; + DWORD result; + char resultBuf[16]; + + + EXDLL_INIT(); + popstring(paramBuf); + + managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (managerHndl == NULL) + { + result = GetLastError(); + goto Cleanup1; + } + + svcHndl = OpenService(managerHndl, paramBuf, SERVICE_STOP | SERVICE_QUERY_STATUS); + if (svcHndl == NULL) + { + result = GetLastError(); + goto Cleanup2; + } + + if (!ControlService(svcHndl, SERVICE_CONTROL_STOP, &svcStatus)) + { + result = GetLastError(); + goto Cleanup3; + } + + while (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) + { + oldCheckPoint = svcStatus.dwCheckPoint; + + Sleep(svcStatus.dwWaitHint); + + if (!QueryServiceStatus(svcHndl, &svcStatus)) + { + result = GetLastError(); + break; + } + + if (oldCheckPoint >= svcStatus.dwCheckPoint) + { + result = ERROR_SERVICE_REQUEST_TIMEOUT; + break; + } + } + + if (svcStatus.dwCurrentState == SERVICE_STOPPED) + result = 0; + + Cleanup3: + CloseServiceHandle(svcHndl); + + Cleanup2: + CloseServiceHandle(managerHndl); + + Cleanup1: + wsprintf(resultBuf, "%08X", result); + pushstring(resultBuf); +} + + + +BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + return TRUE; +} diff --git a/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsp b/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsp new file mode 100644 index 00000000..874e66c7 --- /dev/null +++ b/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsp @@ -0,0 +1,110 @@ +# Microsoft Developer Studio Project File - Name="InstDrv" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=InstDrv - Win32 Debug +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "InstDrv.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "InstDrv.mak" CFG="InstDrv - Win32 Debug" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "InstDrv - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE "InstDrv - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "InstDrv - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /I "C:\Programme\WINDDK\3790\inc\ddk\w2k" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib setupapi.lib newdev.lib /nologo /entry:"_DllMainCRTStartup" /dll /machine:I386 /nodefaultlib /out:"../../Plugins/InstDrv.dll" /libpath:"C:\Programme\WINDDK\3790\lib\w2k\i386" /opt:nowin98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "InstDrv - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /entry:"_DllMainCRTStartup" /dll /debug /machine:I386 /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "InstDrv - Win32 Release" +# Name "InstDrv - Win32 Debug" +# Begin Group "Quellcodedateien" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\InstDrv.c +# End Source File +# End Group +# Begin Group "Header-Dateien" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Ressourcendateien" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsw b/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsw new file mode 100644 index 00000000..b3d02f0e --- /dev/null +++ b/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN! + +############################################################################### + +Project: "InstDrv"=.\InstDrv.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/altosui/Instdrv/NSIS/Contrib/InstDrv/Readme.txt b/altosui/Instdrv/NSIS/Contrib/InstDrv/Readme.txt new file mode 100644 index 00000000..e5877aa6 --- /dev/null +++ b/altosui/Instdrv/NSIS/Contrib/InstDrv/Readme.txt @@ -0,0 +1,141 @@ +InstDrv.dll version 0.2 - Installs or Removes Device Drivers +------------------------------------------------------------ + + +The plugin helps you to create NSIS scripts for installing device drivers or +removing them again. It can count installed device instances, create new ones +or delete all supported device. InstDrv works on Windows 2000 or later. + + + +InstDrv::InitDriverSetup devClass drvHWID +Return: result + +To start processing a driver, first call this function. devClass is the GUID +of the device class the driver supports, drvHWID is the device hardware ID. If +you don't know what these terms mean, you may want to take a look at the +Windows DDK. This function returns an empty string on success, otherwise an +error message. + +InitDriverSetup has to be called every time after the plugin dll has been +(re-)loaded, or if you want to switch to a different driver. + + + +InstDrv::CountDevices +Return: number + +This call returns the number of installed and supported devices of the driver. + + + +InstDrv::CreateDevice +Return: result + +To create a new deviced node which the driver has to support, use this +function. You may even call it multiple times for more than one instance. The +return value is the Windows error code (in hex). Use CreateDevice before +installing or updating the driver itself. + + + +InstDrv::InstallDriver infPath +Return: result + reboot + +InstallDriver installs or updates a device driver as specified in the .inf +setup script. It returns a Windows error code (in hex) and, on success, a flag +signalling if a system reboot is required. + + + +InstDrv::DeleteOemInfFiles +Return: result + oeminf + oempnf + +DeleteOemInfFiles tries to clean up the Windows inf directory by deleting the +oemXX.inf and oemXX.pnf files associated with the drivers. It returns a +Windows error code (in hex) and, on success, the names of the deleted files. +This functions requires that at least one device instance is still present. +So, call it before you remove the devices itself. You should also call it +before updating a driver. This avoids that the inf directory gets slowly +messed up with useless old setup scripts (which does NOT really accelerate +Windows). The error code which comes up when no device is installed is +"00000103". + + + +InstDrv::RemoveAllDevices +Return: result + reboot + +This functions deletes all devices instances the driver supported. It returns +a Windows error code (in hex) and, on success, a flag signalling if the system +needs to be rebooted. You additionally have to remove the driver binaries from +the system paths. + + + +InstDrv::StartSystemService serviceName +Return: result + +Call this function to start the provided system service. The function blocks +until the service is started or the system reported a timeout. The return value +is the Windows error code (in hex). + + + +InstDrv::StopSystemService serviceName +Return: result + +This function tries to stop the provided system service. It blocks until the +service has been shut down or the system reported a timeout. The return value +is the Windows error code (in hex). + + + +Example.nsi + +The example script installs or removes the virtual COM port driver of IrCOMM2k +(2.0.0-alpha8, see www.ircomm2k.de/english). The driver and its setup script +are only included for demonstration purposes, they do not work without the +rest of IrCOMM2k (but they also do not cause any harm). + + + +Building the Source Code + +To build the plugin from the source code, some include files and libraries +which come with the Windows DDK are required. + + + +History + + 0.2 - fixed bug when calling InitDriverSetup the second time + - added StartSystemService and StopSystemService + + 0.1 - first release + + + +License + +Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment in the + product documentation would be appreciated but is not required. +2. Altered versions must be plainly marked as such, + and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any distribution. diff --git a/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.inf b/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.inf new file mode 100644 index 00000000..ccda1d87 --- /dev/null +++ b/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.inf @@ -0,0 +1,137 @@ +; IrCOMM2k.inf +; +; Installation file for the Virtual Infrared-COM-Port +; +; (c) Copyright 2001, 2002 Jan Kiszka +; + +[Version] +Signature="$Windows NT$" +Provider=%JK% +Class=Ports +ClassGUID={4d36e978-e325-11ce-bfc1-08002be10318} +;DriverVer=03/26/2002,1.2.1.0 + +[DestinationDirs] +IrCOMM2k.Copy2Drivers = 12 +IrCOMM2k.Copy2Winnt = 10 +IrCOMM2k.Copy2System32 = 11 +IrCOMM2k.Copy2Help = 18 + + +; +; Driver information +; + +[Manufacturer] +%JK% = JK.Mfg + +[JK.Mfg] +%JK.DeviceDescIrCOMM% = IrCOMM2k_inst,IrCOMM2k + + +; +; General installation section +; + +[IrCOMM2k_inst] +CopyFiles = IrCOMM2k.Copy2Drivers ;,IrCOMM2k.Copy2System32,IrCOMM2k.Copy2Help,IrCOMM2k.Copy2Winnt +;AddReg = IrCOMM2k_inst_AddReg + + +; +; File sections +; + +[IrCOMM2k.Copy2Drivers] +ircomm2k.sys,,,2 + +;[IrCOMM2k.Copy2System32] +;ircomm2k.exe,,,2 +;ircomm2k.dll,,,2 + +;[IrCOMM2k.Copy2Help] +;ircomm2k.hlp,,,2 + +;[IrCOMM2k.Copy2Winnt] +;IrCOMM2k-Setup.exe,Setup.exe,,2 + + +; +; Service Installation +; + +[IrCOMM2k_inst.Services] +AddService = IrCOMM2k,0x00000002,IrCOMM2k_DriverService_Inst,IrCOMM2k_DriverEventLog_Inst +;AddService = IrCOMM2kSvc,,IrCOMM2k_Service_Inst + +[IrCOMM2k_DriverService_Inst] +DisplayName = %IrCOMM2k.DrvName% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 0 ; SERVICE_ERROR_IGNORE +ServiceBinary = %12%\ircomm2k.sys + +;[IrCOMM2k_Service_Inst] +;DisplayName = %IrCOMM2k.SvcName% +;Description = %IrCOMM2k.SvcDesc% +;ServiceType = 0x00000120 ; SERVICE_WIN32_SHARE_PROCESS, SERVICE_INTERACTIVE_PROCESS +;StartType = 2 ; SERVICE_AUTO_START +;ErrorControl = 0 ; SERVICE_ERROR_IGNORE +;ServiceBinary = %11%\ircomm2k.exe +;Dependencies = IrCOMM2k +;AddReg = IrCOMM2kSvcAddReg + + +[IrCOMM2k_inst.nt.HW] +AddReg=IrCOMM2kHwAddReg + +[IrCOMM2kHwAddReg] +HKR,,PortSubClass,REG_BINARY,0x00000001 +;HKR,,TimeoutScaling,REG_DWORD,0x00000001 +;HKR,,StatusLines,REG_DWORD,0x00000000 + +;[IrCOMM2k_inst_AddReg] +;HKR,,EnumPropPages32,,"ircomm2k.dll,IrCOMM2kPropPageProvider" +;HKLM,%UNINSTALL_KEY%,DisplayIcon,0x00020000,"%windir%\IrCOMM2k-Setup.exe" +;HKLM,%UNINSTALL_KEY%,DisplayName,,"IrCOMM2k 1.2.1 " +;HKLM,%UNINSTALL_KEY%,DisplayVersion,,"1.2.1" +;HKLM,%UNINSTALL_KEY%,HelpLink,,"http://www.ircomm2k.de" +;HKLM,%UNINSTALL_KEY%,Publisher,,%JK% +;HKLM,%UNINSTALL_KEY%,UninstallString,0x00020000,"%windir%\IrCOMM2k-Setup.exe" + +;[IrCOMM2kSvcAddReg] +;HKR,Parameters,ActiveConnectOnly,REG_DWORD,0x00000000 + + +[IrCOMM2k_DriverEventLog_Inst] +AddReg = IrCOMM2k_DriverEventLog_AddReg + +[IrCOMM2k_DriverEventLog_AddReg] +HKR,,EventMessageFile,REG_EXPAND_SZ,"%SystemRoot%\System32\IoLogMsg.dll;%SystemRoot%\System32\drivers\ircomm2k.sys" +HKR,,TypesSupported,REG_DWORD,7 + + +[Strings] + +; +; Non-Localizable Strings +; + +REG_SZ = 0x00000000 +REG_MULTI_SZ = 0x00010000 +REG_EXPAND_SZ = 0x00020000 +REG_BINARY = 0x00000001 +REG_DWORD = 0x00010001 +SERVICEROOT = "System\CurrentControlSet\Services" +UNINSTALL_KEY = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IrCOMM2k" + +; +; Localizable Strings +; + +JK = "Jan Kiszka" +JK.DeviceDescIrCOMM = "Virtueller Infrarot-Kommunikationsanschluss" +IrCOMM2k.DrvName = "Virtueller Infrarot-Kommunikationsanschluss" +;IrCOMM2k.SvcName = "Virtueller Infrarot-Kommunikationsanschluß, Dienstprogramm" +;IrCOMM2k.SvcDesc = "Bildet über Infarot einen Kommunikationsanschluß nach." diff --git a/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys b/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys new file mode 100644 index 00000000..7882583b Binary files /dev/null and b/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys differ diff --git a/altosui/Instdrv/NSIS/Plugins/InstDrv.dll b/altosui/Instdrv/NSIS/Plugins/InstDrv.dll new file mode 100644 index 00000000..482e955e Binary files /dev/null and b/altosui/Instdrv/NSIS/Plugins/InstDrv.dll differ diff --git a/altosui/Makefile-standalone b/altosui/Makefile-standalone new file mode 100644 index 00000000..a95a5aa8 --- /dev/null +++ b/altosui/Makefile-standalone @@ -0,0 +1,184 @@ +.SUFFIXES: .java .class + +CLASSPATH=classes:./*:/usr/share/java/* +CLASSFILES=\ + Altos.class \ + AltosChannelMenu.class \ + AltosConfig.class \ + AltosConfigUI.class \ + AltosConvert.class \ + AltosCRCException.class \ + AltosCSV.class \ + AltosCSVUI.class \ + AltosDebug.class \ + AltosEepromDownload.class \ + AltosEepromMonitor.class \ + AltosEepromReader.class \ + AltosEepromRecord.class \ + AltosFile.class \ + AltosFlash.class \ + AltosFlashUI.class \ + AltosFlightInfoTableModel.class \ + AltosFlightStatusTableModel.class \ + AltosGPS.class \ + AltosGreatCircle.class \ + AltosHexfile.class \ + AltosLine.class \ + AltosInfoTable.class \ + AltosLog.class \ + AltosLogfileChooser.class \ + AltosParse.class \ + AltosPreferences.class \ + AltosReader.class \ + AltosRecord.class \ + AltosSerialMonitor.class \ + AltosSerial.class \ + AltosState.class \ + AltosStatusTable.class \ + AltosTelemetry.class \ + AltosTelemetryReader.class \ + AltosUI.class \ + AltosDevice.class \ + AltosDeviceDialog.class \ + AltosRomconfig.class \ + AltosRomconfigUI.class \ + AltosVoice.class + +JAVA_ICON=../../icon/altus-metrum-16x16.jpg +WINDOWS_ICON=../../icon/altus-metrum.ico + +# where altosui.jar gets installed +ALTOSLIB=/usr/share/java + +# where freetts.jar is to be found +FREETTSLIB=/usr/share/java + +# all of the freetts files +FREETTSJAR= \ + $(FREETTSLIB)/cmudict04.jar \ + $(FREETTSLIB)/cmulex.jar \ + $(FREETTSLIB)/cmu_time_awb.jar \ + $(FREETTSLIB)/cmutimelex.jar \ + $(FREETTSLIB)/cmu_us_kal.jar \ + $(FREETTSLIB)/en_us.jar \ + $(FREETTSLIB)/freetts.jar + +# The current hex files +HEXLIB=../../src +HEXFILES = \ + $(HEXLIB)/telemetrum-v1.0.ihx \ + $(HEXLIB)/teledongle-v0.2.ihx + +JAVAFLAGS=-Xlint:unchecked -Xlint:deprecation + +ALTOSUIJAR = altosui.jar +FATJAR = fat/altosui.jar + +OS:=$(shell uname) + +LINUX_APP=altosui + +DARWIN_ZIP=Altos-Mac.zip + +WINDOWS_EXE=Altos-Windows.exe + +LINUX_TGZ=Altos-Linux.tgz + +all: altosui.jar $(LINUX_APP) +fat: altosui.jar $(LINUX_APP) $(DARWIN_ZIP) $(WINDOWS_EXE) $(LINUX_TGZ) + +$(CLASSFILES): + +.java.class: + javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java + +altosui.jar: classes/images classes/altosui classes/libaltosJNI $(CLASSFILES) Manifest.txt + cd ./classes && jar cfm ../$@ altosui/Manifest.txt images/* altosui/*.class libaltosJNI/*.class + +Manifest.txt: Makefile $(CLASSFILES) + echo 'Main-Class: altosui.AltosUI' > $@ + echo "Class-Path: $(FREETTSLIB)/freetts.jar" >> $@ + +classes/altosui: + mkdir -p classes + ln -sf .. classes/altosui + +classes/libaltosJNI: + mkdir -p classes + ln -sf ../../libaltos/libaltosJNI classes/libaltosJNI + +classes/images: + mkdir -p classes/images + ln -sf ../../$(JAVA_ICON) classes/images + +altosui: + echo "#!/bin/sh" > $@ + echo "exec java -Djava.library.path=/usr/lib/altos -jar /usr/share/java/altosui.jar" >> $@ + chmod +x ./altosui + +fat/altosui: + echo "#!/bin/sh" > $@ + echo 'ME=`which "$0"`' >> $@ + echo 'DIR=`dirname "$ME"`' >> $@ + echo 'exec java -Djava.library.path="$$DIR" -jar "$$DIR"/altosui.jar' >> $@ + chmod +x $@ + +fat/altosui.jar: $(CLASSFILES) $(JAVA_ICON) fat/classes/Manifest.txt + mkdir -p fat/classes + test -L fat/classes/altosui || ln -sf ../.. fat/classes/altosui + mkdir -p fat/classes/images + cp $(JAVA_ICON) fat/classes/images + test -L fat/classes/libaltosJNI || ln -sf ../../../libaltos/libaltosJNI fat/classes/libaltosJNI + cd ./fat/classes && jar cfm ../../$@ Manifest.txt images/* altosui/*.class libaltosJNI/*.class + +fat/classes/Manifest.txt: $(CLASSFILES) Makefile + mkdir -p fat/classes + echo 'Main-Class: altosui.AltosUI' > $@ + echo "Class-Path: freetts.jar" >> $@ + +install: altosui.jar altosui + install -m 0644 altosui.jar $(DESTDIR)/usr/share/java/altosui.jar + install -m 0644 altosui.1 $(DESTDIR)/usr/share/man/man1/altosui.1 + install altosui $(DESTDIR)/usr/bin/altosui + +clean: + rm -f *.class altosui.jar + rm -f AltosUI.app/Contents/Resources/Java/* + rm -rf classes + rm -rf windows linux + +distclean: clean + rm -f $(DARWIN_ZIP) $(WINDOWS_EXE) $(LINUX_TGZ) + rm -rf darwin fat + +FAT_FILES=$(FATJAR) $(FREETTSJAR) $(HEXFILES) + +LINUX_FILES=$(FAT_FILES) ../libaltos/libaltos.so fat/altosui +$(LINUX_TGZ): $(LINUX_FILES) + rm -f $@ + mkdir -p linux/AltOS + rm -f linux/AltOS/* + cp $(LINUX_FILES) linux/AltOS + cd linux && tar czf ../$@ AltOS + +DARWIN_RESOURCES=$(FATJAR) $(FREETTSJAR) ../libaltos/libaltos.dylib +DARWIN_EXTRA=$(HEXFILES) +DARWIN_FILES=$(DARWIN_RESOURCES) $(DARWIN_EXTRA) + +$(DARWIN_ZIP): $(DARWIN_FILES) + rm -f $@ + cp -a AltosUI.app darwin/ + mkdir -p darwin/AltosUI.app/Contents/Resources/Java + cp $(DARWIN_RESOURCES) darwin/AltosUI.app/Contents/Resources/Java + mkdir -p darwin/AltOS + cp $(DARWIN_EXTRA) darwin/AltOS + cd darwin && zip -r ../$@ AltosUI.app AltOS + +WINDOWS_FILES = $(FAT_FILES) ../libaltos/altos.dll ../../telemetrum.inf $(WINDOWS_ICON) + +$(WINDOWS_EXE): $(WINDOWS_FILES) altos-windows.nsi + rm -f $@ + mkdir -p windows/AltOS + rm -f windows/AltOS/* + cp $(WINDOWS_FILES) windows/AltOS + makensis altos-windows.nsi diff --git a/altosui/Makefile.am b/altosui/Makefile.am new file mode 100644 index 00000000..e2ff55af --- /dev/null +++ b/altosui/Makefile.am @@ -0,0 +1,272 @@ +SUBDIRS=libaltos +JAVAROOT=classes +AM_JAVACFLAGS=-encoding UTF-8 + +man_MANS=altosui.1 + +altoslibdir=$(libdir)/altos + +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:libaltos:$(FREETTS)/*:/usr/share/java/*" + +bin_SCRIPTS=altosui + +altosui_JAVA = \ + GrabNDrag.java \ + AltosAscent.java \ + AltosChannelMenu.java \ + AltosConfig.java \ + AltosConfigUI.java \ + AltosConfigureUI.java \ + AltosConvert.java \ + AltosCRCException.java \ + AltosCSV.java \ + AltosCSVUI.java \ + AltosDebug.java \ + AltosDescent.java \ + AltosDeviceDialog.java \ + AltosDevice.java \ + AltosDisplayThread.java \ + AltosEepromDownload.java \ + AltosEepromMonitor.java \ + AltosEepromIterable.java \ + AltosEepromRecord.java \ + AltosFile.java \ + AltosFlash.java \ + AltosFlashUI.java \ + AltosFlightDisplay.java \ + AltosFlightInfoTableModel.java \ + AltosFlightReader.java \ + AltosFlightStatus.java \ + AltosFlightUI.java \ + AltosGPS.java \ + AltosGreatCircle.java \ + AltosHexfile.java \ + Altos.java \ + AltosIgnite.java \ + AltosIgniteUI.java \ + AltosInfoTable.java \ + AltosKML.java \ + AltosLanded.java \ + AltosLed.java \ + AltosLights.java \ + AltosLine.java \ + AltosLog.java \ + AltosPad.java \ + AltosParse.java \ + AltosPreferences.java \ + AltosReader.java \ + AltosRecord.java \ + AltosRecordIterable.java \ + AltosTelemetryReader.java \ + AltosReplayReader.java \ + AltosRomconfig.java \ + AltosRomconfigUI.java \ + AltosSerial.java \ + AltosSerialInUseException.java \ + AltosSerialMonitor.java \ + AltosSiteMap.java \ + AltosSiteMapCache.java \ + AltosSiteMapTile.java \ + AltosState.java \ + AltosTelemetry.java \ + AltosTelemetryIterable.java \ + AltosUI.java \ + AltosWriter.java \ + AltosDataPointReader.java \ + AltosDataPoint.java \ + AltosGraph.java \ + AltosGraphTime.java \ + AltosGraphUI.java \ + AltosDataChooser.java \ + AltosVoice.java + +JFREECHART_CLASS= \ + jfreechart.jar + +JCOMMON_CLASS=\ + jcommon.jar + +FREETTS_CLASS= \ + cmudict04.jar \ + cmulex.jar \ + cmu_time_awb.jar \ + cmutimelex.jar \ + cmu_us_kal.jar \ + en_us.jar \ + freetts.jar + +LIBALTOS= \ + libaltos.so \ + libaltos.dylib \ + altos.dll + +JAR=altosui.jar + +FATJAR=altosui-fat.jar + +# Icons +ICONDIR=$(top_srcdir)/icon + +JAVA_ICON=$(ICONDIR)/altus-metrum-16x16.jpg + +ICONS= $(ICONDIR)/redled.png $(ICONDIR)/redoff.png \ + $(ICONDIR)/greenled.png $(ICONDIR)/greenoff.png \ + $(ICONDIR)/grayled.png $(ICONDIR)/grayoff.png + +# icon base names for jar +ICONJAR= -C $(ICONDIR) altus-metrum-16x16.jpg \ + -C $(ICONDIR) redled.png -C $(ICONDIR) redoff.png \ + -C $(ICONDIR) greenled.png -C $(ICONDIR) greenoff.png \ + -C $(ICONDIR) grayon.png -C $(ICONDIR) grayled.png + +WINDOWS_ICON=$(ICONDIR)/altus-metrum.ico + +# Firmware +FIRMWARE_TD=$(top_srcdir)/src/teledongle-v0.2-$(VERSION).ihx +FIRMWARE_TM=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx +FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TD) + +# Distribution targets +LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2 +MACOSX_DIST=Altos-Mac-$(VERSION).zip +WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe + +FAT_FILES=$(FATJAR) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) + +LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) +LINUX_EXTRA=altosui-fat + +MACOSX_FILES=$(FAT_FILES) libaltos.dylib +MACOSX_EXTRA=$(FIRMWARE) + +WINDOWS_FILES=$(FAT_FILES) altos.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON) + +all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb + +clean-local: + -rm -rf classes $(JAR) $(FATJAR) \ + $(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(FREETTS_CLASS) \ + $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log \ + altosui altosui-test altosui-jdb macosx linux + +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 + + +altosuidir=$(datadir)/java + +install-altosuiJAVA: altosui.jar + @$(NORMAL_INSTALL) + test -z "$(altosuidir)" || $(MKDIR_P) "$(DESTDIR)$(altosuidir)" + echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/altosui.jar'"; \ + $(INSTALL_DATA) "$<" "$(DESTDIR)$(altosuidir)" + +classes/altosui: + mkdir -p classes/altosui + +$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICON) + jar cfm $@ Manifest.txt \ + $(ICONJAR) \ + -C classes altosui \ + -C libaltos libaltosJNI + +$(FATJAR): classaltosui.stamp Manifest-fat.txt $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICON) + jar cfm $@ Manifest-fat.txt \ + $(ICONJAR) \ + -C classes altosui \ + -C libaltos libaltosJNI + +Manifest.txt: Makefile + echo 'Main-Class: altosui.AltosUI' > $@ + echo "Class-Path: $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@ + +Manifest-fat.txt: + echo 'Main-Class: altosui.AltosUI' > $@ + echo "Class-Path: freetts.jar jfreechart.jar jcommon.jar" >> $@ + +altosui: Makefile + echo "#!/bin/sh" > $@ + echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/altosui.jar" "$$@"' >> $@ + chmod +x $@ + +altosui-test: Makefile + echo "#!/bin/sh" > $@ + echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@ + chmod +x $@ + +altosui-jdb: Makefile + echo "#!/bin/sh" > $@ + echo 'exec jdb -classpath "classes:libaltos:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" altosui/AltosUI "$$@"' >> $@ + chmod +x $@ + +libaltos.so: + -rm -f "$@" + $(LN_S) libaltos/.libs/"$@" . + +libaltos.dylib: + -rm -f "$@" + $(LN_S) libaltos/"$@" . + +altos.dll: + -rm -f "$@" + $(LN_S) libaltos/"$@" . + +$(FREETTS_CLASS): + -rm -f "$@" + $(LN_S) "$(FREETTS)"/"$@" . + +$(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/AltOS + cp -p $(LINUX_FILES) linux/AltOS + cp -p altosui-fat linux/AltOS/altosui + chmod +x linux/AltOS/altosui + tar cjf $@ -C linux AltOS + +$(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) + -rm -f $@ + -rm -rf macosx + mkdir macosx + cp -a AltosUI.app macosx/ + mkdir -p macosx/AltOS macosx/AltosUI.app/Contents/Resources/Java + cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar + cp -p $(FREETTS_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java + cp -p $(JFREECHART_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java + cp -p $(MACOSX_EXTRA) macosx/AltOS + cd macosx && zip -r ../$@ AltosUI.app AltOS + +$(WINDOWS_DIST): $(WINDOWS_FILES) altos-windows.nsi + -rm -f $@ + makensis -Oaltos-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" altos-windows.nsi diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi new file mode 100644 index 00000000..37777fd6 --- /dev/null +++ b/altosui/altos-windows.nsi @@ -0,0 +1,113 @@ +!addplugindir Instdrv/NSIS/Plugins + +Name "Altus Metrum 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 Software and Driver Installer" + +; Pages to present + +Page license +Page components +Page directory +Page instfiles + +UninstPage uninstConfirm +UninstPage instfiles + +; And the stuff to install + +Section "Install Driver" InstDriver + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} "Altus Metrum" + Pop $0 + DetailPrint "InitDriverSetup: $0" + + InstDrv::DeleteOemInfFiles /NOUNLOAD + InstDrv::CreateDevice /NOUNLOAD + SetOutPath $TEMP + File "../../telemetrum.inf" + InstDrv::InstallDriver /NOUNLOAD "$TEMP\telemetrum.inf" + + SetOutPath $INSTDIR + File "../../telemetrum.inf" +SectionEnd + +Section "AltosUI Application" + SetOutPath $INSTDIR + + File "altosui-fat.jar" + File "cmudict04.jar" + File "cmulex.jar" + File "cmu_time_awb.jar" + File "cmutimelex.jar" + File "cmu_us_kal.jar" + File "en_us.jar" + File "freetts.jar" + + File "*.dll" + + File "../../icon/*.ico" + + CreateShortCut "$SMPROGRAMS\AltusMetrum.lnk" "$INSTDIR\altosui-fat.jar" "" "$INSTDIR\altus-metrum.ico" +SectionEnd + +Section "AltosUI Desktop Shortcut" + CreateShortCut "$DESKTOP\AltusMetrum.lnk" "$INSTDIR\altosui-fat.jar" "" "$INSTDIR\altus-metrum.ico" +SectionEnd + +Section "TeleMetrum and TeleDongle Firmware" + + SetOutPath $INSTDIR + + File "../../src/telemetrum-v1.0/telemetrum-v1.0-${VERSION}.ihx" + File "../../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx" + +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 devices + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} "Altus Metrum" + InstDrv::DeleteOemInfFiles /NOUNLOAD + InstDrv::RemoveAllDevices + + ; Remove shortcuts, if any + Delete "$SMPROGRAMS\AltusMetrum.lnk" + Delete "$DESKTOP\AltusMetrum.lnk" +SectionEnd diff --git a/altosui/altosui-fat b/altosui/altosui-fat new file mode 100755 index 00000000..95b1c051 --- /dev/null +++ b/altosui/altosui-fat @@ -0,0 +1,4 @@ +#!/bin/sh +me=`which "$0"` +dir=`dirname "$me"` +exec java -cp "$dir/*" -Djava.library.path="$dir" -jar "$dir"/altosui-fat.jar "$@" diff --git a/altosui/altosui.1 b/altosui/altosui.1 new file mode 100644 index 00000000..57fa4489 --- /dev/null +++ b/altosui/altosui.1 @@ -0,0 +1,46 @@ +.\" +.\" Copyright © 2010 Bdale Garbee +.\" +.\" 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; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" 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. +.\" +.\" +.TH ALTOSUI 1 "altosui" "" +.SH NAME +altosui \- Rocket flight monitor +.SH SYNOPSIS +.B "altosui" +.SH DESCRIPTION +.I altosui +connects to a TeleDongle or TeleMetrum device through a USB serial device. +It provides a menu-oriented +user interface to monitor, record and review rocket flight data. +.SH USAGE +When connected to a TeleDongle device, altosui turns on the radio +receiver and listens for telemetry packets. It displays the received +telemetry data, and reports flight status via voice synthesis. All +received telemetry information is recorded to a file. +.P +When connected to a TeleMetrum device, altosui can be used to configure the +TeleMetrum, and to downloads the eeprom data and store it in a file. +.P +A number of other menu options exist, including the ability to export flight +data in different formats. +.SH FILES +All data log files are recorded into a user-specified directory +(default ~/TeleMetrum). Files are named using the current date, the serial +number of the reporting device, the flight number recorded in the data +and either '.telem' for telemetry data or '.eeprom' for eeprom data. +.SH AUTHOR +Keith Packard diff --git a/altosui/altusmetrum.jpg b/altosui/altusmetrum.jpg new file mode 100644 index 00000000..04027921 Binary files /dev/null and b/altosui/altusmetrum.jpg differ diff --git a/altosui/libaltos/.gitignore b/altosui/libaltos/.gitignore new file mode 100644 index 00000000..c490e6f8 --- /dev/null +++ b/altosui/libaltos/.gitignore @@ -0,0 +1,12 @@ +*.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 new file mode 100644 index 00000000..4e438050 --- /dev/null +++ b/altosui/libaltos/Makefile-standalone @@ -0,0 +1,126 @@ +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 new file mode 100644 index 00000000..388d2104 --- /dev/null +++ b/altosui/libaltos/Makefile.am @@ -0,0 +1,41 @@ +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= + +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 + +clean-local: + -rm -rf libaltosJNI *.class *.java classlibaltos.stamp $(SWIG_FILE) libaltos_wrap.c diff --git a/altosui/libaltos/altos.dll b/altosui/libaltos/altos.dll new file mode 100755 index 00000000..28e9b4ad Binary files /dev/null and b/altosui/libaltos/altos.dll differ diff --git a/altosui/libaltos/cjnitest.c b/altosui/libaltos/cjnitest.c new file mode 100644 index 00000000..c6d6e069 --- /dev/null +++ b/altosui/libaltos/cjnitest.c @@ -0,0 +1,43 @@ +#include +#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; + + 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); + altos_fini(); +} diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c new file mode 100644 index 00000000..465f0ac8 --- /dev/null +++ b/altosui/libaltos/libaltos.c @@ -0,0 +1,1028 @@ +/* + * 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. + */ + +#include "libaltos.h" +#include +#include +#include + +#define USE_POLL + +PUBLIC int +altos_init(void) +{ + return LIBALTOS_SUCCESS; +} + +PUBLIC void +altos_fini(void) +{ +} + +#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 + +/* + * Scan for Altus Metrum devices by looking through /sys + */ + +#ifdef LINUX + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +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); +} + +#endif + +#ifdef DARWIN + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} + +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; +} + +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; + } + } +} + +void +altos_list_finish(struct altos_list *list) +{ + IOObjectRelease (list->iterator); + free(list); +} + +#endif + +#ifdef POSIX_TTY + +#include +#include +#include +#include +#include + +#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; +}; + +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) + return NULL; + + file->fd = open(device->path, O_RDWR | O_NOCTTY); + if (file->fd < 0) { + perror(device->path); + 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) { + perror(device->path); + close(file->fd); + free(file); + return NULL; + } +#endif + ret = tcgetattr(file->fd, &term); + if (ret < 0) { + perror("tcgetattr"); + 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) { + perror("tcsetattr"); + 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) + return -errno; + 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 0; +} + +#ifdef USE_POLL +#include +#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) { + perror("altos_getchar"); + 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) { + perror("altos_getchar"); + 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 */ + +#ifdef WINDOWS + +#include +#include +#include + +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; +}; + +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) { + printf("SetupDiGetClassDevs failed %d\n", GetLastError()); + 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; + char port[128]; + DWORD port_len; + char friendlyname[256]; + char symbolic[256]; + DWORD symbolic_len; + HKEY dev_key; + 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) { + 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) { + printf("cannot find SymbolicName value\n"); + RegCloseKey(dev_key); + continue; + } + vid = pid = serial = 0; + sscanf(symbolic + sizeof("\\??\\USB#VID_") - 1, + "%04X", &vid); + sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1, + "%04X", &pid); + sscanf(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) { + 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)) + { + printf("Failed to get friendlyname\n"); + continue; + } + device->vendor = vid; + device->product = pid; + device->serial = serial; + strcpy(device->name, friendlyname); + + strcpy(device->path, port); + return 1; + } + result = GetLastError(); + if (result != ERROR_NO_MORE_ITEMS) + printf ("SetupDiEnumDeviceInfo failed error %d\n", 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) + 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)) + 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; + char *data = file->out_data; + char used = file->out_used; + DWORD ret; + + while (used) { + if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) { + if (GetLastError() != ERROR_IO_PENDING) + 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)) + return LIBALTOS_ERROR; + break; + default: + 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]; + DCB dcbSerialParams = {0}; + 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) { + 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); + + dcbSerialParams.DCBlength = sizeof(dcbSerialParams); + if (!GetCommState(file->handle, &dcbSerialParams)) { + CloseHandle(file->handle); + free(file); + return NULL; + } + dcbSerialParams.BaudRate = CBR_9600; + dcbSerialParams.ByteSize = 8; + dcbSerialParams.StopBits = ONESTOPBIT; + dcbSerialParams.Parity = NOPARITY; + if (!SetCommState(file->handle, &dcbSerialParams)) { + CloseHandle(file->handle); + free(file); + return NULL; + } + + return file; +} + +PUBLIC void +altos_close(struct altos_file *file) +{ + if (file->handle != INVALID_HANDLE_VALUE) { + CloseHandle(file->handle); + file->handle = INVALID_HANDLE_VALUE; + } +} + +PUBLIC void +altos_free(struct altos_file *file) +{ + altos_close(file); + free(file); +} + +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; +} + +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++]; +} + +#endif diff --git a/altosui/libaltos/libaltos.dylib b/altosui/libaltos/libaltos.dylib new file mode 100755 index 00000000..89aa12e7 Binary files /dev/null and b/altosui/libaltos/libaltos.dylib differ diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h new file mode 100644 index 00000000..6e94899e --- /dev/null +++ b/altosui/libaltos/libaltos.h @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#ifndef _LIBALTOS_H_ +#define _LIBALTOS_H_ + +#include + +#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 + +#define USB_VENDOR_FSF 0xfffe +#define USB_VENDOR_ALTUSMETRUM USB_VENDOR_FSF +#define USB_PRODUCT_ALTUSMETRUM 0x000a +#define USB_PRODUCT_TELEMETRUM 0x000b +#define USB_PRODUCT_TELEDONGLE 0x000c +#define USB_PRODUCT_TELETERRA 0x000d +#define USB_PRODUCT_ALTUSMETRUM_MIN 0x000a +#define USB_PRODUCT_ALTUSMETRUM_MAX 0x0013 + +#define USB_IS_ALTUSMETRUM(v,p) ((v) == USB_VENDOR_ALTUSMETRUM && \ + (USB_PRODUCT_ALTUSMETRUM_MIN <= (p) && \ + (p) <= USB_PRODUCT_ALTUSMETRUM_MAX)) + +struct altos_device { + //%immutable; + int vendor; + int product; + int serial; + char name[256]; + char path[256]; + //%mutable; +}; + +#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 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); + +#endif /* _LIBALTOS_H_ */ diff --git a/altosui/libaltos/libaltos.i0 b/altosui/libaltos/libaltos.i0 new file mode 100644 index 00000000..d06468f5 --- /dev/null +++ b/altosui/libaltos/libaltos.i0 @@ -0,0 +1,5 @@ +%module libaltos +%{ +#include "libaltos.h" +%} + -- cgit v1.2.3 From 3d98440d53378aaa6da87ed65e9abb2f96f7ee49 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Nov 2010 11:16:28 -0800 Subject: altosui: Make windows bits build after moving altosui directory Signed-off-by: Keith Packard --- altosui/altos-windows.nsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'altosui') diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index 37777fd6..d7c4b32a 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -9,7 +9,7 @@ InstallDir "$PROGRAMFILES\AltusMetrum" InstallDirRegKey HKLM "Software\AltusMetrum" "Install_Dir" LicenseText "GNU General Public License Version 2" -LicenseData "../../COPYING" +LicenseData "../COPYING" ; Need admin privs for Vista or Win7 RequestExecutionLevel admin @@ -38,11 +38,11 @@ Section "Install Driver" InstDriver InstDrv::DeleteOemInfFiles /NOUNLOAD InstDrv::CreateDevice /NOUNLOAD SetOutPath $TEMP - File "../../telemetrum.inf" + File "../telemetrum.inf" InstDrv::InstallDriver /NOUNLOAD "$TEMP\telemetrum.inf" SetOutPath $INSTDIR - File "../../telemetrum.inf" + File "../telemetrum.inf" SectionEnd Section "AltosUI Application" @@ -59,7 +59,7 @@ Section "AltosUI Application" File "*.dll" - File "../../icon/*.ico" + File "../icon/*.ico" CreateShortCut "$SMPROGRAMS\AltusMetrum.lnk" "$INSTDIR\altosui-fat.jar" "" "$INSTDIR\altus-metrum.ico" SectionEnd @@ -72,8 +72,8 @@ Section "TeleMetrum and TeleDongle Firmware" SetOutPath $INSTDIR - File "../../src/telemetrum-v1.0/telemetrum-v1.0-${VERSION}.ihx" - File "../../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx" + File "../src/telemetrum-v1.0/telemetrum-v1.0-${VERSION}.ihx" + File "../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx" SectionEnd -- cgit v1.2.3 From f88bde21d76a4ff91099a5051153ebace1619978 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Nov 2010 11:16:55 -0800 Subject: altosui: Hack up standalone makefile to maybe build altosui again This isn't tested, but at least the paths are more likely to be correct Signed-off-by: Keith Packard --- altosui/Makefile-standalone | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'altosui') diff --git a/altosui/Makefile-standalone b/altosui/Makefile-standalone index a95a5aa8..0d9931d5 100644 --- a/altosui/Makefile-standalone +++ b/altosui/Makefile-standalone @@ -44,8 +44,8 @@ CLASSFILES=\ AltosRomconfigUI.class \ AltosVoice.class -JAVA_ICON=../../icon/altus-metrum-16x16.jpg -WINDOWS_ICON=../../icon/altus-metrum.ico +JAVA_ICON=../icon/altus-metrum-16x16.jpg +WINDOWS_ICON=../icon/altus-metrum.ico # where altosui.jar gets installed ALTOSLIB=/usr/share/java @@ -64,7 +64,7 @@ FREETTSJAR= \ $(FREETTSLIB)/freetts.jar # The current hex files -HEXLIB=../../src +HEXLIB=../src HEXFILES = \ $(HEXLIB)/telemetrum-v1.0.ihx \ $(HEXLIB)/teledongle-v0.2.ihx @@ -105,11 +105,11 @@ classes/altosui: classes/libaltosJNI: mkdir -p classes - ln -sf ../../libaltos/libaltosJNI classes/libaltosJNI + ln -sf ../libaltos/libaltosJNI classes/libaltosJNI classes/images: mkdir -p classes/images - ln -sf ../../$(JAVA_ICON) classes/images + ln -sf ../$(JAVA_ICON) classes/images altosui: echo "#!/bin/sh" > $@ @@ -128,7 +128,7 @@ fat/altosui.jar: $(CLASSFILES) $(JAVA_ICON) fat/classes/Manifest.txt test -L fat/classes/altosui || ln -sf ../.. fat/classes/altosui mkdir -p fat/classes/images cp $(JAVA_ICON) fat/classes/images - test -L fat/classes/libaltosJNI || ln -sf ../../../libaltos/libaltosJNI fat/classes/libaltosJNI + test -L fat/classes/libaltosJNI || ln -sf ../../libaltos/libaltosJNI fat/classes/libaltosJNI cd ./fat/classes && jar cfm ../../$@ Manifest.txt images/* altosui/*.class libaltosJNI/*.class fat/classes/Manifest.txt: $(CLASSFILES) Makefile @@ -153,7 +153,7 @@ distclean: clean FAT_FILES=$(FATJAR) $(FREETTSJAR) $(HEXFILES) -LINUX_FILES=$(FAT_FILES) ../libaltos/libaltos.so fat/altosui +LINUX_FILES=$(FAT_FILES) libaltos/libaltos.so fat/altosui $(LINUX_TGZ): $(LINUX_FILES) rm -f $@ mkdir -p linux/AltOS @@ -161,7 +161,7 @@ $(LINUX_TGZ): $(LINUX_FILES) cp $(LINUX_FILES) linux/AltOS cd linux && tar czf ../$@ AltOS -DARWIN_RESOURCES=$(FATJAR) $(FREETTSJAR) ../libaltos/libaltos.dylib +DARWIN_RESOURCES=$(FATJAR) $(FREETTSJAR) libaltos/libaltos.dylib DARWIN_EXTRA=$(HEXFILES) DARWIN_FILES=$(DARWIN_RESOURCES) $(DARWIN_EXTRA) @@ -174,7 +174,7 @@ $(DARWIN_ZIP): $(DARWIN_FILES) cp $(DARWIN_EXTRA) darwin/AltOS cd darwin && zip -r ../$@ AltosUI.app AltOS -WINDOWS_FILES = $(FAT_FILES) ../libaltos/altos.dll ../../telemetrum.inf $(WINDOWS_ICON) +WINDOWS_FILES = $(FAT_FILES) libaltos/altos.dll ../telemetrum.inf $(WINDOWS_ICON) $(WINDOWS_EXE): $(WINDOWS_FILES) altos-windows.nsi rm -f $@ -- cgit v1.2.3 From 12fb7f0e70cd244475d84469f93283112478d1e1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Nov 2010 15:56:42 -0800 Subject: altosui: Only call swing display functions from main thread. Swing insists that all display functions be called from a single thread, and the flight window wasn't following this for display updates. Use SwingUtilities.invokeLater to make sure the flight UI updates happen in the right context. Fixes a UI freeze on Mac OS. Signed-off-by: Keith Packard --- altosui/AltosDisplayThread.java | 49 +++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java index 3e719130..84abfae9 100644 --- a/altosui/AltosDisplayThread.java +++ b/altosui/AltosDisplayThread.java @@ -38,11 +38,45 @@ public class AltosDisplayThread extends Thread { int crc_errors; AltosFlightDisplay display; - synchronized void show(AltosState state, int crc_errors) { + void show_internal(AltosState state, int crc_errors) { if (state != null) display.show(state, crc_errors); } + void show_safely(AltosState in_state, int in_crc_errors) { + final AltosState state = in_state; + final int crc_errors = in_crc_errors; + Runnable r = new Runnable() { + public void run() { + try { + show_internal(state, crc_errors); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + void reading_error_internal(String name) { + JOptionPane.showMessageDialog(parent, + String.format("Error reading from \"%s\"", name), + "Telemetry Read Error", + JOptionPane.ERROR_MESSAGE); + } + + void reading_error_safely(String in_name) { + final String name = in_name; + Runnable r = new Runnable() { + public void run() { + try { + reading_error_internal(name); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + class IdleThread extends Thread { boolean started; @@ -102,7 +136,7 @@ public class AltosDisplayThread extends Thread { ++reported_landing; if (state.state != Altos.ao_flight_landed) { state.state = Altos.ao_flight_landed; - show(state, 0); + show_safely(state, 0); } } } @@ -202,7 +236,6 @@ public class AltosDisplayThread extends Thread { idle_thread = new IdleThread(); - display.reset(); try { for (;;) { try { @@ -212,23 +245,20 @@ public class AltosDisplayThread extends Thread { old_state = state; state = new AltosState(record, state); reader.update(state); - show(state, crc_errors); + show_safely(state, crc_errors); told = tell(state, old_state); idle_thread.notice(state, told); } catch (ParseException pp) { System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); } catch (AltosCRCException ce) { ++crc_errors; - show(state, crc_errors); + show_safely(state, crc_errors); } } } catch (InterruptedException ee) { interrupted = true; } catch (IOException ie) { - JOptionPane.showMessageDialog(parent, - String.format("Error reading from \"%s\"", name), - "Telemetry Read Error", - JOptionPane.ERROR_MESSAGE); + reading_error_safely(name); } finally { if (!interrupted) idle_thread.report(true); @@ -245,5 +275,6 @@ public class AltosDisplayThread extends Thread { voice = in_voice; display = in_display; reader = in_reader; + display.reset(); } } -- cgit v1.2.3 From 6d3612e267cd4c1e7fdd74fc33952b3f26f870f5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Nov 2010 16:09:37 -0800 Subject: altosui: Eliminate unnecessary thread from config UI There's no reason to use a thread to run a dialog box, and swing doesn't like threads anyways. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 1c42870f..38e1484e 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -30,7 +30,7 @@ import java.util.concurrent.*; import libaltosJNI.*; -public class AltosConfig implements Runnable, ActionListener { +public class AltosConfig implements ActionListener { class int_ref { int value; @@ -64,7 +64,6 @@ public class AltosConfig implements Runnable, ActionListener { AltosDevice device; AltosSerial serial_line; boolean remote; - Thread config_thread; int_ref serial; int_ref main_deploy; int_ref apogee_delay; @@ -241,17 +240,6 @@ public class AltosConfig implements Runnable, ActionListener { } } - public void run () { - try { - init_ui(); - config_ui.make_visible(); - } catch (InterruptedException ie) { - abort(); - } catch (TimeoutException te) { - abort(); - } - } - public AltosConfig(JFrame given_owner) { owner = given_owner; @@ -270,8 +258,14 @@ public class AltosConfig implements Runnable, ActionListener { serial_line = new AltosSerial(device); if (!device.matchProduct(AltosDevice.product_telemetrum)) remote = true; - config_thread = new Thread(this); - config_thread.start(); + try { + init_ui(); + config_ui.make_visible(); + } catch (InterruptedException ie) { + abort(); + } catch (TimeoutException te) { + abort(); + } } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(owner, String.format("Cannot open device \"%s\"", -- cgit v1.2.3 From 7f88520089660845009148b69bfcea6c9dff9672 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Nov 2010 16:23:18 -0800 Subject: altosui: Flight data download GUI operations called only from main thread Swing doesn't like UI functions being called from non-dispatch thread, so fix up the eeprom download code to use SwingUtilities.invokeLater to make sure this works right. Signed-off-by: Keith Packard --- altosui/AltosEepromDownload.java | 49 ++++++++++++++++++-------- altosui/AltosEepromMonitor.java | 76 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 105 insertions(+), 20 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 02fc36f2..e5ff766c 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -214,6 +214,27 @@ public class AltosEepromDownload implements Runnable { } } + private void show_error_internal(String message, String title) { + JOptionPane.showMessageDialog(frame, + message, + title, + JOptionPane.ERROR_MESSAGE); + } + + private void show_error(String in_message, String in_title) { + final String message = in_message; + final String title = in_title; + Runnable r = new Runnable() { + public void run() { + try { + show_error_internal(message, title); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + public void run () { if (remote) { serial_line.set_radio(); @@ -221,26 +242,16 @@ public class AltosEepromDownload implements Runnable { serial_line.flush_input(); } - monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed); - monitor.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - eeprom_thread.interrupt(); - } - }); try { CaptureLog(); } catch (IOException ee) { - JOptionPane.showMessageDialog(frame, - device.toShortString(), - ee.getLocalizedMessage(), - JOptionPane.ERROR_MESSAGE); + show_error (device.toShortString(), + ee.getLocalizedMessage()); } catch (InterruptedException ie) { } catch (TimeoutException te) { - JOptionPane.showMessageDialog(frame, - String.format("Connection to \"%s\" failed", - device.toShortString()), - "Connection Failed", - JOptionPane.ERROR_MESSAGE); + show_error (String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed"); } if (remote) serial_line.printf("~"); @@ -260,6 +271,14 @@ public class AltosEepromDownload implements Runnable { serial_line = new AltosSerial(device); if (!device.matchProduct(AltosDevice.product_telemetrum)) remote = true; + monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed); + monitor.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (eeprom_thread != null) + eeprom_thread.interrupt(); + } + }); + eeprom_thread = new Thread(this); eeprom_thread.start(); } catch (FileNotFoundException ee) { diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java index 7ff00ead..13a49a95 100644 --- a/altosui/AltosEepromMonitor.java +++ b/altosui/AltosEepromMonitor.java @@ -141,7 +141,7 @@ public class AltosEepromMonitor extends JDialog { cancel.addActionListener(l); } - public void set_value(String state_name, int in_state, int in_block) { + private void set_value_internal(String state_name, int in_state, int in_block) { int block = in_block; int state = in_state; @@ -157,20 +157,86 @@ public class AltosEepromMonitor extends JDialog { pbar.setValue(pos); } - public void set_serial(int serial) { + public void set_value(String in_state_name, int in_state, int in_block) { + final String state_name = in_state_name; + final int state = in_state; + final int block = in_block; + Runnable r = new Runnable() { + public void run() { + try { + set_value_internal(state_name, state, block); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + private void set_serial_internal(int serial) { serial_value.setText(String.format("%d", serial)); } - public void set_flight(int flight) { + public void set_serial(int in_serial) { + final int serial = in_serial; + Runnable r = new Runnable() { + public void run() { + try { + set_serial_internal(serial); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + private void set_flight_internal(int flight) { flight_value.setText(String.format("%d", flight)); } - public void set_file(String file) { + public void set_flight(int in_flight) { + final int flight = in_flight; + Runnable r = new Runnable() { + public void run() { + try { + set_flight_internal(flight); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + private void set_file_internal(String file) { file_value.setText(String.format("%s", file)); } - public void done() { + public void set_file(String in_file) { + final String file = in_file; + Runnable r = new Runnable() { + public void run() { + try { + set_file_internal(file); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + private void done_internal() { setVisible(false); dispose(); } + + public void done() { + Runnable r = new Runnable() { + public void run() { + try { + done_internal(); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } } -- cgit v1.2.3 From adbb14c63d85b7a54223f88ac623571456f4a462 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Nov 2010 16:28:04 -0800 Subject: altosui: Remove gratuitous threading from device flashing UI There's no need for a thread here, and swing doesn't want us to use one anyways. Signed-off-by: Keith Packard --- altosui/AltosFlashUI.java | 83 ++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 44 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index f63097ac..0b61f041 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -30,7 +30,7 @@ import java.util.concurrent.LinkedBlockingQueue; public class AltosFlashUI extends JDialog - implements Runnable, ActionListener + implements ActionListener { Container pane; Box box; @@ -64,47 +64,6 @@ public class AltosFlashUI } } - public void run() { - try { - flash = new AltosFlash(file, debug_dongle); - flash.addActionListener(this); - AltosRomconfigUI romconfig_ui = new AltosRomconfigUI (frame); - - romconfig_ui.set(flash.romconfig()); - AltosRomconfig romconfig = romconfig_ui.showDialog(); - - if (romconfig != null && romconfig.valid()) { - flash.set_romconfig(romconfig); - serial_value.setText(String.format("%d", - flash.romconfig().serial_number)); - file_value.setText(file.toString()); - setVisible(true); - flash.flash(); - flash = null; - } - } catch (FileNotFoundException ee) { - JOptionPane.showMessageDialog(frame, - "Cannot open image", - file.toString(), - JOptionPane.ERROR_MESSAGE); - } catch (AltosSerialInUseException si) { - JOptionPane.showMessageDialog(frame, - String.format("Device \"%s\" already in use", - debug_dongle.toShortString()), - "Device in use", - JOptionPane.ERROR_MESSAGE); - } catch (IOException e) { - JOptionPane.showMessageDialog(frame, - e.getMessage(), - file.toString(), - JOptionPane.ERROR_MESSAGE); - } catch (InterruptedException ie) { - } finally { - abort(); - } - dispose(); - } - public void abort() { if (flash != null) flash.abort(); @@ -212,7 +171,43 @@ public class AltosFlashUI if (file != null) AltosPreferences.set_firmwaredir(file.getParentFile()); - thread = new Thread(this); - thread.start(); + try { + flash = new AltosFlash(file, debug_dongle); + flash.addActionListener(this); + AltosRomconfigUI romconfig_ui = new AltosRomconfigUI (frame); + + romconfig_ui.set(flash.romconfig()); + AltosRomconfig romconfig = romconfig_ui.showDialog(); + + if (romconfig != null && romconfig.valid()) { + flash.set_romconfig(romconfig); + serial_value.setText(String.format("%d", + flash.romconfig().serial_number)); + file_value.setText(file.toString()); + setVisible(true); + flash.flash(); + flash = null; + } + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(frame, + "Cannot open image", + file.toString(), + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(frame, + String.format("Device \"%s\" already in use", + debug_dongle.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException e) { + JOptionPane.showMessageDialog(frame, + e.getMessage(), + file.toString(), + JOptionPane.ERROR_MESSAGE); + } catch (InterruptedException ie) { + } finally { + abort(); + } + dispose(); } } \ No newline at end of file -- cgit v1.2.3 From b8f05cdc0e9b4a96852eed9d38ff6d5950e2d2ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Nov 2010 17:29:28 -0800 Subject: altosui: Clean up flash code to ensure swing gets called from right thread This moves all of the flash code to a separate thread and passes messages back to the swing thread to keep the UI up to date. Signed-off-by: Keith Packard --- altosui/AltosFlash.java | 202 +++++++++++++++++++++++++++------------------- altosui/AltosFlashUI.java | 25 +++--- 2 files changed, 132 insertions(+), 95 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlash.java b/altosui/AltosFlash.java index 3af25c23..802adc8c 100644 --- a/altosui/AltosFlash.java +++ b/altosui/AltosFlash.java @@ -28,7 +28,7 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; -public class AltosFlash { +public class AltosFlash implements Runnable { File file; FileInputStream input; AltosHexfile image; @@ -197,23 +197,36 @@ public class AltosFlash { }; public void clock_init() throws IOException, InterruptedException { - debug.debug_instr(set_clkcon_fast); - - byte status; - for (int times = 0; times < 20; times++) { - Thread.sleep(1); - status = debug.debug_instr(get_sleep); - if ((status & SLEEP_XOSC_STB) != 0) - return; + if (debug != null) { + debug.debug_instr(set_clkcon_fast); + + byte status; + for (int times = 0; times < 20; times++) { + Thread.sleep(1); + status = debug.debug_instr(get_sleep); + if ((status & SLEEP_XOSC_STB) != 0) + return; + } + throw new IOException("Failed to initialize target clock"); } - throw new IOException("Failed to initialize target clock"); } - void action(String s, int percent) { - if (listener != null && !aborted) - listener.actionPerformed(new ActionEvent(this, - percent, - s)); + void action(String in_s, int in_percent) { + final String s = in_s; + final int percent = in_percent; + if (listener != null && !aborted) { + Runnable r = new Runnable() { + public void run() { + try { + listener.actionPerformed(new ActionEvent(this, + percent, + s)); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } } void action(int part, int total) { @@ -223,7 +236,7 @@ public class AltosFlash { percent); } - void run(int pc) throws IOException, InterruptedException { + void altos_run(int pc) throws IOException, InterruptedException { debug.set_pc(pc); int set_pc = debug.get_pc(); if (pc != set_pc) @@ -239,74 +252,96 @@ public class AltosFlash { throw new IOException("Failed to execute program on target"); } - public void flash() throws IOException, FileNotFoundException, InterruptedException { - if (!check_rom_config()) - throw new IOException("Invalid rom config settings"); - if (image.address + image.data.length > 0x8000) - throw new IOException(String.format("Flash image too long %d", - image.address + - image.data.length)); - if ((image.address & 0x3ff) != 0) - throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)", - image.address)); - int ram_address = 0xf000; - int flash_prog = 0xf400; - - /* - * Store desired config values into image - */ - rom_config.write(image); - /* - * Bring up the clock - */ - clock_init(); - - int remain = image.data.length; - int flash_addr = image.address; - int image_start = 0; - - action("start", 0); - action(0, image.data.length); - while (remain > 0 && !aborted) { - int this_time = remain; - if (this_time > 0x400) - this_time = 0x400; - - /* write the data */ - debug.write_memory(ram_address, image.data, - image_start, this_time); - - /* write the flash program */ - byte[] flash_page = make_flash_page(flash_addr, - ram_address, - this_time); - debug.write_memory(flash_prog, flash_page); - - run(flash_prog); - - byte[] check = debug.read_memory(flash_addr, this_time); - for (int i = 0; i < this_time; i++) - if (check[i] != image.data[image_start + i]) - throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)", - image.address + image_start + i, - check[i], image.data[image_start + i])); - remain -= this_time; - flash_addr += this_time; - image_start += this_time; - - action(image.data.length - remain, image.data.length); + Thread thread; + + public void run() { + try { + if (!check_rom_config()) + throw new IOException("Invalid rom config settings"); + if (image.address + image.data.length > 0x8000) + throw new IOException(String.format("Flash image too long %d", + image.address + + image.data.length)); + if ((image.address & 0x3ff) != 0) + throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)", + image.address)); + int ram_address = 0xf000; + int flash_prog = 0xf400; + + /* + * Store desired config values into image + */ + rom_config.write(image); + /* + * Bring up the clock + */ + clock_init(); + + int remain = image.data.length; + int flash_addr = image.address; + int image_start = 0; + + action("start", 0); + action(0, image.data.length); + while (remain > 0 && !aborted) { + int this_time = remain; + if (this_time > 0x400) + this_time = 0x400; + + if (debug != null) { + /* write the data */ + debug.write_memory(ram_address, image.data, + image_start, this_time); + + /* write the flash program */ + byte[] flash_page = make_flash_page(flash_addr, + ram_address, + this_time); + debug.write_memory(flash_prog, flash_page); + + altos_run(flash_prog); + byte[] check = debug.read_memory(flash_addr, this_time); + for (int i = 0; i < this_time; i++) + if (check[i] != image.data[image_start + i]) + throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)", + image.address + image_start + i, + check[i], image.data[image_start + i])); + } else { + Thread.sleep(100); + } + + remain -= this_time; + flash_addr += this_time; + image_start += this_time; + + action(image.data.length - remain, image.data.length); + } + if (!aborted) { + action("done", 100); + if (debug != null) { + debug.set_pc(image.address); + debug.resume(); + } + } + if (debug != null) + debug.close(); + } catch (IOException ie) { + action(ie.getMessage(), -1); + abort(); + } catch (InterruptedException ie) { + abort(); } - if (!aborted) { - action("done", 100); - debug.set_pc(image.address); - debug.resume(); - } - debug.close(); } - public void abort() { + public void flash() { + thread = new Thread(this); + thread.start(); + } + + synchronized public void abort() { aborted = true; - debug.close(); + if (debug != null) + debug.close(); } public void addActionListener(ActionListener l) { @@ -314,6 +349,8 @@ public class AltosFlash { } public boolean check_rom_config() { + if (debug == null) + return true; if (rom_config == null) rom_config = debug.romconfig(); return rom_config != null && rom_config.valid(); @@ -333,10 +370,11 @@ public class AltosFlash { throws IOException, FileNotFoundException, AltosSerialInUseException, InterruptedException { file = in_file; debug_dongle = in_debug_dongle; - debug = new AltosDebug(in_debug_dongle); + if (debug_dongle != null) + debug = new AltosDebug(in_debug_dongle); input = new FileInputStream(file); image = new AltosHexfile(input); - if (!debug.check_connection()) { + if (debug != null && !debug.check_connection()) { debug.close(); throw new IOException("Debug port not connected"); } diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 0b61f041..0302ccd3 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -49,13 +49,21 @@ public class AltosFlashUI public void actionPerformed(ActionEvent e) { if (e.getSource() == cancel) { - abort(); + setVisible(false); dispose(); } else { String cmd = e.getActionCommand(); - if (cmd.equals("done")) - ; - else if (cmd.equals("start")) { + if (e.getID() == -1) { + JOptionPane.showMessageDialog(frame, + e.getActionCommand(), + file.toString(), + JOptionPane.ERROR_MESSAGE); + setVisible(false); + dispose(); + } else if (cmd.equals("done")) { + setVisible(false); + dispose(); + } else if (cmd.equals("start")) { setVisible(true); } else { pbar.setValue(e.getID()); @@ -64,11 +72,6 @@ public class AltosFlashUI } } - public void abort() { - if (flash != null) - flash.abort(); - } - public void build_dialog() { GridBagConstraints c; Insets il = new Insets(4,4,4,4); @@ -186,7 +189,6 @@ public class AltosFlashUI file_value.setText(file.toString()); setVisible(true); flash.flash(); - flash = null; } } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(frame, @@ -205,9 +207,6 @@ public class AltosFlashUI file.toString(), JOptionPane.ERROR_MESSAGE); } catch (InterruptedException ie) { - } finally { - abort(); } - dispose(); } } \ No newline at end of file -- cgit v1.2.3 From cd414e2c04ce5ecbc75f19325a6d6f82cd489fb3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 27 Nov 2010 16:30:29 -0800 Subject: altosui: Correct windows hardware IDs for nsis installer file Need real hardware IDs (encoded USB ids) to get windows to auto-install the driver? Signed-off-by: Keith Packard --- altosui/altos-windows.nsi | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index d7c4b32a..7cf51212 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -31,7 +31,10 @@ UninstPage instfiles ; And the stuff to install Section "Install Driver" InstDriver - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} "Altus Metrum" + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000A + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000B + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000C + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000D Pop $0 DetailPrint "InitDriverSetup: $0" @@ -103,7 +106,10 @@ Section "Uninstall" RMDir "$INSTDIR" ; Remove devices - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} "Altus Metrum" + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000A + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000B + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000C + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000D InstDrv::DeleteOemInfFiles /NOUNLOAD InstDrv::RemoveAllDevices -- cgit v1.2.3 From 641c5373724d34c3adfcf42420a528d6bba736b9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 27 Nov 2010 22:35:18 -0800 Subject: windows: try harder to get windows install to work Add devIDs to .nsi file. Fix install section name mapping from the hot-plug info. Signed-off-by: Keith Packard --- altosui/altos-windows.nsi | 21 ++++++++++++++++++++- telemetrum.inf | 20 ++++++++++---------- 2 files changed, 30 insertions(+), 11 deletions(-) (limited to 'altosui') diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index 7cf51212..0e985967 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -31,15 +31,34 @@ UninstPage instfiles ; And the stuff to install Section "Install Driver" InstDriver + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000A + Pop $0 + DetailPrint "InitDriverSetup: $0" + InstDrv::DeleteOemInfFiles /NOUNLOAD + InstDrv::CreateDevice /NOUNLOAD + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000B + Pop $0 + DetailPrint "InitDriverSetup: $0" + InstDrv::DeleteOemInfFiles /NOUNLOAD + InstDrv::CreateDevice /NOUNLOAD + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000C - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000D Pop $0 DetailPrint "InitDriverSetup: $0" + InstDrv::DeleteOemInfFiles /NOUNLOAD + InstDrv::CreateDevice /NOUNLOAD + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000D + Pop $0 + DetailPrint "InitDriverSetup: $0" InstDrv::DeleteOemInfFiles /NOUNLOAD InstDrv::CreateDevice /NOUNLOAD + + SetOutPath $WINDIR\Inf + File "../telemetrum.inf" + SetOutPath $TEMP File "../telemetrum.inf" InstDrv::InstallDriver /NOUNLOAD "$TEMP\telemetrum.inf" diff --git a/telemetrum.inf b/telemetrum.inf index 0d1a5534..54f8f020 100755 --- a/telemetrum.inf +++ b/telemetrum.inf @@ -11,6 +11,12 @@ DriverVer = 08/05/2010,7.1.0.0 [Manufacturer] %Mfg% = Models, NTx86, NTamd64, NTia64 +[Models] +%AltusMetrum% = TELEMETRUM, USB\VID_FFFE&PID_000A +%TeleMetrum% = TELEMETRUM, USB\VID_FFFE&PID_000B +%TeleDongle% = TELEMETRUM, USB\VID_FFFE&PID_000C +%TeleTerra% = TELEMETRUM, USB\VID_FFFE&PID_000D + [Models.NTx86] %AltusMetrum% = TELEMETRUM, USB\VID_FFFE&PID_000A %TeleMetrum% = TELEMETRUM, USB\VID_FFFE&PID_000B @@ -33,10 +39,7 @@ DriverVer = 08/05/2010,7.1.0.0 DefaultDestDir=12 [ControlFlags] -ExcludeFromSelect=USB\VID_FFFE&PID_000A -ExcludeFromSelect=USB\VID_FFFE&PID_000B -ExcludeFromSelect=USB\VID_FFFE&PID_000C -ExcludeFromSelect=USB\VID_FFFE&PID_000D +ExcludeFromSelect=* [Strings] Mfg = "altusmetrum.org" @@ -45,32 +48,29 @@ TeleMetrum = "TeleMetrum" TeleDongle = "TeleDongle" TeleTerra = "TeleTerra" - ;---------------------------------------------------------------------------- ; Installation sections ;---------------------------------------------------------------------------- -[TELEMETRUM.NT] +[TELEMETRUM] include=mdmcpq.inf CopyFiles=FakeModemCopyFileSection AddReg = All, mfglt, Modem.AddReg, VerboseResultCodes, Uninstall.AddReg -[TELEMETRUM.NT.HW] +[TELEMETRUM.HW] Include=mdmcpq.inf AddReg=LowerFilterAddReg -[TELEMETRUM.NT.Services] +[TELEMETRUM.Services] Include=mdmcpq.inf AddService=usbser, 0x00000000, LowerFilter_Service_Inst - ;---------------------------------------------------------------------------- ; AddReg sections ;---------------------------------------------------------------------------- [Modem.AddReg] HKR,, Properties, 1, C0,01,00,00, 00,00,00,00, FF,00,00,00, 07,00,00,00, 0F,00,00,00, F7,0F,00,00, 00,84,03,00, C0,DA,00,00 - ;---------------------------------------------------------------------------- ; Common Registry Sections ; -- cgit v1.2.3 From b727156ef0a7fb6e442ca28be27eb344a213ecf8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 29 Nov 2010 20:17:35 -0800 Subject: windows: Add jfreechart.jar and jcommon.jar to windows install image These are necessary for the Graph Data button to do anything useful. Signed-off-by: Keith Packard --- altosui/altos-windows.nsi | 2 ++ 1 file changed, 2 insertions(+) (limited to 'altosui') diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index 0e985967..9bbfb885 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -78,6 +78,8 @@ Section "AltosUI Application" File "cmu_us_kal.jar" File "en_us.jar" File "freetts.jar" + File "jfreechart.jar" + File "jcommon.jar" File "*.dll" -- cgit v1.2.3 From b62580855c5144f5bc7e0172289bce08814d9472 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Tue, 14 Dec 2010 03:40:18 +1000 Subject: altosui: move maps to subdir, fix E/W mismatch --- altosui/AltosPreferences.java | 13 +++++++++++++ altosui/AltosSiteMap.java | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index e2a3df3b..c6ae6cbd 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -52,6 +52,9 @@ class AltosPreferences { /* Log directory */ static File logdir; + /* Map directory -- hangs of logdir */ + static File mapdir; + /* Channel (map serial to channel) */ static Hashtable channels; @@ -79,6 +82,9 @@ class AltosPreferences { if (!logdir.exists()) logdir.mkdirs(); } + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); channels = new Hashtable(); @@ -106,6 +112,9 @@ class AltosPreferences { public static void set_logdir(File new_logdir) { logdir = new_logdir; + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); synchronized (preferences) { preferences.put(logdirPreference, logdir.getPath()); flush_preferences(); @@ -151,6 +160,10 @@ class AltosPreferences { return logdir; } + public static File mapdir() { + return mapdir; + } + public static void set_channel(int serial, int new_channel) { channels.put(serial, new_channel); synchronized (preferences) { diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index d4a4cbf4..d6bd6d1f 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -211,10 +211,10 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { private File MapFile(double lat, double lng) { char chlat = lat < 0 ? 'S' : 'N'; - char chlng = lng < 0 ? 'E' : 'W'; + char chlng = lng < 0 ? 'W' : 'E'; if (lat < 0) lat = -lat; if (lng < 0) lng = -lng; - return new File(AltosPreferences.logdir(), + return new File(AltosPreferences.mapdir(), String.format("map-%c%.6f,%c%.6f-%d.png", chlat, lat, chlng, lng, zoom)); } -- cgit v1.2.3 From 51c410c1c952e0e9bcf1b2c438813de63753be5f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 28 Nov 2010 00:24:54 -0800 Subject: windows: Update NSIS installer file to use compatibility IDs This allows the file to contain a single InitDriverSetup function, making things shorter and (I hope) clearer. --- altosui/altos-windows.nsi | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'altosui') diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index 9bbfb885..6f296f18 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -32,39 +32,22 @@ UninstPage instfiles Section "Install Driver" InstDriver - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000A + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} AltusMetrumSerial Pop $0 DetailPrint "InitDriverSetup: $0" InstDrv::DeleteOemInfFiles /NOUNLOAD InstDrv::CreateDevice /NOUNLOAD - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000B - Pop $0 - DetailPrint "InitDriverSetup: $0" - InstDrv::DeleteOemInfFiles /NOUNLOAD - InstDrv::CreateDevice /NOUNLOAD - - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000C - Pop $0 - DetailPrint "InitDriverSetup: $0" - InstDrv::DeleteOemInfFiles /NOUNLOAD - InstDrv::CreateDevice /NOUNLOAD - - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000D - Pop $0 - DetailPrint "InitDriverSetup: $0" - InstDrv::DeleteOemInfFiles /NOUNLOAD - InstDrv::CreateDevice /NOUNLOAD - - SetOutPath $WINDIR\Inf - File "../telemetrum.inf" - SetOutPath $TEMP File "../telemetrum.inf" InstDrv::InstallDriver /NOUNLOAD "$TEMP\telemetrum.inf" SetOutPath $INSTDIR File "../telemetrum.inf" + + SetOutPath $WINDIR\Inf + File "../telemetrum.inf" + SectionEnd Section "AltosUI Application" @@ -127,10 +110,7 @@ Section "Uninstall" RMDir "$INSTDIR" ; Remove devices - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000A - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000B - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000C - InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} USB\VID_FFFE&PID_000D + InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} AltusMetrumSerial InstDrv::DeleteOemInfFiles /NOUNLOAD InstDrv::RemoveAllDevices -- cgit v1.2.3 From ca66f86a899c191b6362a334417fc84a79349677 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 7 Jan 2011 20:46:29 -0800 Subject: altosui: Add configuration of flight log size This adds to the TeleMetrum configuration UI the ability to set the maximum flight log size. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 7 ++++++ altosui/AltosConfigUI.java | 53 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 6 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 38e1484e..47de6156 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -69,6 +69,7 @@ public class AltosConfig implements ActionListener { int_ref apogee_delay; int_ref radio_channel; int_ref radio_calibration; + int_ref flight_log_max; string_ref version; string_ref product; string_ref callsign; @@ -138,6 +139,7 @@ public class AltosConfig implements ActionListener { get_int(line, "Apogee delay:", apogee_delay); get_int(line, "Radio channel:", radio_channel); get_int(line, "Radio cal:", radio_calibration); + get_int(line, "Max flight log:", flight_log_max); get_string(line, "Callsign:", callsign); get_string(line,"software-version", version); get_string(line,"product", product); @@ -181,6 +183,7 @@ public class AltosConfig implements ActionListener { config_ui.set_apogee_delay(apogee_delay.get()); config_ui.set_radio_channel(radio_channel.get()); config_ui.set_radio_calibration(radio_calibration.get()); + config_ui.set_flight_log_max(flight_log_max.get()); config_ui.set_callsign(callsign.get()); config_ui.set_clean(); } @@ -193,6 +196,7 @@ public class AltosConfig implements ActionListener { apogee_delay.set(config_ui.apogee_delay()); radio_channel.set(config_ui.radio_channel()); radio_calibration.set(config_ui.radio_calibration()); + flight_log_max.set(config_ui.flight_log_max()); callsign.set(config_ui.callsign()); try { start_serial(); @@ -203,6 +207,8 @@ public class AltosConfig implements ActionListener { serial_line.printf("c f %d\n", radio_calibration.get()); } serial_line.printf("c c %s\n", callsign.get()); + if (flight_log_max.get() != 0) + serial_line.printf("c l %d\n", flight_log_max.get()); serial_line.printf("c w\n"); } catch (InterruptedException ie) { } finally { @@ -248,6 +254,7 @@ public class AltosConfig implements ActionListener { apogee_delay = new int_ref(0); radio_channel = new int_ref(0); radio_calibration = new int_ref(1186611); + flight_log_max = new int_ref(0); callsign = new string_ref("N0CALL"); version = new string_ref("unknown"); product = new string_ref("unknown"); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index cfa5d7b9..e09eab25 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -45,6 +45,7 @@ public class AltosConfigUI JLabel apogee_delay_label; JLabel radio_channel_label; JLabel radio_calibration_label; + JLabel flight_log_max_label; JLabel callsign_label; public boolean dirty; @@ -57,6 +58,7 @@ public class AltosConfigUI JComboBox apogee_delay_value; JComboBox radio_channel_value; JTextField radio_calibration_value; + JComboBox flight_log_max_value; JTextField callsign_value; JButton save; @@ -75,6 +77,12 @@ public class AltosConfigUI "0", "1", "2", "3", "4", "5" }; + static String[] flight_log_max_values = { + "64", "128", "192", "256", "320", + "384", "448", "512", "576", "640", + "704", "768", "832", "896", "960", + }; + static String[] radio_channel_values = new String[10]; { for (int i = 0; i <= 9; i++) @@ -296,9 +304,33 @@ public class AltosConfigUI callsign_value.getDocument().addDocumentListener(this); pane.add(callsign_value, c); - /* Buttons */ + /* Flight log max */ c = new GridBagConstraints(); c.gridx = 0; c.gridy = 8; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + flight_log_max_label = new JLabel("Maximum Flight Log Size:"); + pane.add(flight_log_max_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 8; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + flight_log_max_value = new JComboBox(flight_log_max_values); + flight_log_max_value.setEditable(true); + flight_log_max_value.addItemListener(this); + pane.add(flight_log_max_value, c); + + /* Buttons */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 9; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -309,7 +341,7 @@ public class AltosConfigUI save.setActionCommand("Save"); c = new GridBagConstraints(); - c.gridx = 2; c.gridy = 8; + c.gridx = 2; c.gridy = 9; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -320,7 +352,7 @@ public class AltosConfigUI reset.setActionCommand("Reset"); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 8; + c.gridx = 4; c.gridy = 9; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -331,7 +363,7 @@ public class AltosConfigUI reboot.setActionCommand("Reboot"); c = new GridBagConstraints(); - c.gridx = 6; c.gridy = 8; + c.gridx = 6; c.gridy = 9; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_END; @@ -459,8 +491,17 @@ public class AltosConfigUI return callsign_value.getText(); } + public void set_flight_log_max(int new_flight_log_max) { + if (new_flight_log_max == 0) + flight_log_max_value.setEnabled(false); + flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max)); + } + + public int flight_log_max() { + return Integer.parseInt(flight_log_max_value.getSelectedItem().toString()); + } + public void set_clean() { dirty = false; } - - } \ No newline at end of file +} -- cgit v1.2.3 From bd2480fd757b67557d9c7de42e402034002c3e37 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 11 Jan 2011 15:39:24 -0800 Subject: altosui: Split eeprom download code apart Create separate 'download config data', 'read single record' and 'read block' functions. This code will be shared with future multi-log reading code for new firmware. Signed-off-by: Keith Packard --- altosui/AltosConfigData.java | 109 +++++++++++++++++++ altosui/AltosEepromBlock.java | 82 ++++++++++++++ altosui/AltosEepromDownload.java | 230 ++++++++++++++------------------------- altosui/AltosEepromRecord.java | 47 +++++++- altosui/Makefile.am | 2 + 5 files changed, 318 insertions(+), 152 deletions(-) create mode 100644 altosui/AltosConfigData.java create mode 100644 altosui/AltosEepromBlock.java (limited to 'altosui') diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java new file mode 100644 index 00000000..8c32ed86 --- /dev/null +++ b/altosui/AltosConfigData.java @@ -0,0 +1,109 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosConfigData implements Iterable { + + /* Version information */ + String manufacturer; + String product; + String version; + int serial; + + /* Strings returned */ + LinkedList lines; + + /* Config information */ + int config_major; + int config_minor; + int main_deploy; + int apogee_delay; + int radio_channel; + String callsign; + int accel_cal_plus, accel_cal_minus; + int radio_calibration; + int flight_log_max; + + + static String get_string(String line, String label) throws ParseException { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + return quoted; + } + throw new ParseException("mismatch", 0); + } + + static int get_int(String line, String label) throws NumberFormatException, ParseException { + if (line.startsWith(label)) { + String tail = line.substring(label.length()).trim(); + String[] tokens = tail.split("\\s+"); + if (tokens.length > 0) + return Integer.parseInt(tokens[0]); + } + throw new ParseException("mismatch", 0); + } + + public Iterator iterator() { + return lines.iterator(); + } + + public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { + serial_line.printf("c s\nv\n"); + lines = new LinkedList(); + for (;;) { + String line = serial_line.get_reply(5000); + if (line == null) + throw new TimeoutException(); + if (line.contains("Syntax error")) + continue; + lines.add(line); + try { serial = get_int(line, "serial-number"); } catch (Exception e) {} + try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} + try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} + try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} + try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} + try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} + try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} + try { version = get_string(line,"software-version"); } catch (Exception e) {} + try { product = get_string(line,"product"); } catch (Exception e) {} + + /* signals the end of the version info */ + if (line.startsWith("software-version")) + break; + } + } + +} \ No newline at end of file diff --git a/altosui/AltosEepromBlock.java b/altosui/AltosEepromBlock.java new file mode 100644 index 00000000..0c1a4a92 --- /dev/null +++ b/altosui/AltosEepromBlock.java @@ -0,0 +1,82 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; +import java.lang.reflect.Array; + +import libaltosJNI.*; + +public class AltosEepromBlock extends ArrayList { + boolean has_flight; + int flight; + boolean has_state; + int state; + boolean has_date; + int year, month, day; + + public AltosEepromBlock (AltosSerial serial_line, int block) throws TimeoutException, InterruptedException { + int addr; + boolean done = false; + + has_flight = false; + has_state = false; + has_date = false; + serial_line.printf("e %x\n", block); + for (addr = 0; !done && addr < 0x100;) { + try { + AltosEepromRecord r = new AltosEepromRecord(serial_line, block * 256 + addr); + + if (r.cmd == Altos.AO_LOG_FLIGHT) { + flight = r.b; + has_flight = true; + } + + /* Monitor state transitions to update display */ + if (r.cmd == Altos.AO_LOG_STATE && r.a <= Altos.ao_flight_landed) { + if (!has_state || r.a > state) { + state = r.a; + has_state = true; + } + } + + if (r.cmd == Altos.AO_LOG_GPS_DATE) { + year = 2000 + (r.a & 0xff); + month = (r.a >> 8) & 0xff; + day = (r.b & 0xff); + has_date = true; + } + + if (r.cmd == Altos.AO_LOG_STATE && r.a == Altos.ao_flight_landed) + done = true; + add(addr / 8, r); + } catch (ParseException pe) { + } + addr += 8; + } + } +} \ No newline at end of file diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index e5ff766c..9a748710 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -32,182 +32,105 @@ import libaltosJNI.*; public class AltosEepromDownload implements Runnable { - static final String[] state_names = { - "startup", - "idle", - "pad", - "boost", - "fast", - "coast", - "drogue", - "main", - "landed", - "invalid", - }; - - int[] ParseHex(String line) { - String[] tokens = line.split("\\s+"); - int[] array = new int[tokens.length]; - - for (int i = 0; i < tokens.length; i++) - try { - array[i] = Integer.parseInt(tokens[i], 16); - } catch (NumberFormatException ne) { - return null; - } - return array; - } - - int checksum(int[] line) { - int csum = 0x5a; - for (int i = 1; i < line.length; i++) - csum += line[i]; - return csum & 0xff; - } - - void FlushPending(FileWriter file, LinkedList pending) throws IOException { - while (!pending.isEmpty()) { - file.write(pending.remove()); - } - } - JFrame frame; AltosDevice device; AltosSerial serial_line; boolean remote; Thread eeprom_thread; AltosEepromMonitor monitor; + int serial = 0; + int flight = 0; + int year = 0, month = 0, day = 0; + boolean want_file = false; + FileWriter eeprom_file = null; + LinkedList eeprom_pending = new LinkedList(); + AltosConfigData config_data; + + private void FlushPending() throws IOException { + for (String s : config_data) { + eeprom_file.write(s); + eeprom_file.write('\n'); + } - void CaptureLog() throws IOException, InterruptedException, TimeoutException { - int serial = 0; - int block, state_block = 0; - int addr; - int flight = 0; - int year = 0, month = 0, day = 0; - int state = 0; - boolean done = false; - boolean want_file = false; - boolean any_valid; - FileWriter eeprom_file = null; - AltosFile eeprom_name; - LinkedList eeprom_pending = new LinkedList(); - - serial_line.printf("\nc s\nv\n"); - - /* Pull the serial number out of the version information */ + for (String s : eeprom_pending) + eeprom_file.write(s); + } - for (;;) { - String line = serial_line.get_reply(5000); + private void CheckFile(boolean force) throws IOException { + if (eeprom_file != null) + return; + if (force || (flight != 0 && want_file)) { + AltosFile eeprom_name; + if (year != 0 && month != 0 && day != 0) + eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom"); + else + eeprom_name = new AltosFile(serial, flight, "eeprom"); - if (line == null) - throw new TimeoutException(); - if (line.startsWith("serial-number")) { - try { - serial = Integer.parseInt(line.substring(13).trim()); - } catch (NumberFormatException ne) { - serial = 0; - } + eeprom_file = new FileWriter(eeprom_name); + if (eeprom_file != null) { + monitor.set_file(eeprom_name.getName()); + FlushPending(); + eeprom_pending = null; } + } + } - eeprom_pending.add(String.format("%s\n", line)); + void CaptureLog(int start_block, int end_block) throws IOException, InterruptedException, TimeoutException { + int block, state_block = 0; + int state = 0; + boolean done = false; + int record; - /* signals the end of the version info */ - if (line.startsWith("software-version")) - break; - } + config_data = new AltosConfigData(serial_line); + serial = config_data.serial; if (serial == 0) throw new IOException("no serial number found"); monitor.set_serial(serial); /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */ - state = 0; state_block = 0; - for (block = 0; !done && block < 511; block++) { - serial_line.printf("e %x\n", block); - any_valid = false; - monitor.set_value(state_names[state], state, block - state_block); - for (addr = 0; addr < 0x100;) { - String line = serial_line.get_reply(5000); - if (line == null) - throw new TimeoutException(); - int[] values = ParseHex(line); - - if (values == null) { - System.out.printf("invalid line: %s\n", line); - continue; - } else if (values[0] != addr) { - System.out.printf("data address out of sync at 0x%x\n", - block * 256 + values[0]); - } else if (checksum(values) != 0) { - System.out.printf("invalid checksum at 0x%x\n", - block * 256 + values[0]); - } else { - any_valid = true; - int cmd = values[1]; - int tick = values[3] + (values[4] << 8); - int a = values[5] + (values[6] << 8); - int b = values[7] + (values[8] << 8); + state = 0; state_block = start_block; + for (block = start_block; !done && block < end_block; block++) { + monitor.set_value(Altos.state_to_string[state], state, block - state_block); - if (cmd == Altos.AO_LOG_FLIGHT) { - flight = b; - monitor.set_flight(flight); - } - - /* Monitor state transitions to update display */ - if (cmd == Altos.AO_LOG_STATE && a <= Altos.ao_flight_landed) { - if (a > Altos.ao_flight_pad) - want_file = true; - if (a > state) - state_block = block; - state = a; - } + AltosEepromBlock eeblock = new AltosEepromBlock(serial_line, block); + if (eeblock.has_flight) { + flight = eeblock.flight; + monitor.set_flight(flight); + } + if (eeblock.has_date) { + year = eeblock.year; + month = eeblock.month; + day = eeblock.day; + want_file = true; + } - if (cmd == Altos.AO_LOG_GPS_DATE) { - year = 2000 + (a & 0xff); - month = (a >> 8) & 0xff; - day = (b & 0xff); - want_file = true; - } + if (eeblock.size() == 0 || + eeblock.has_state && eeblock.state == Altos.ao_flight_landed) + done = true; - if (eeprom_file == null) { - if (serial != 0 && flight != 0 && want_file) { - if (year != 0 && month != 0 && day != 0) - eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom"); - else - eeprom_name = new AltosFile(serial, flight, "eeprom"); + /* Monitor state transitions to update display */ + if (eeblock.has_state) { + if (eeblock.state > Altos.ao_flight_pad) + want_file = true; + if (eeblock.state > state) + state = eeblock.state; + } - monitor.set_file(eeprom_name.getName()); - eeprom_file = new FileWriter(eeprom_name); - if (eeprom_file != null) { - FlushPending(eeprom_file, eeprom_pending); - eeprom_pending = null; - } - } - } + CheckFile(true); - String log_line = String.format("%c %4x %4x %4x\n", - cmd, tick, a, b); - if (eeprom_file != null) - eeprom_file.write(log_line); - else - eeprom_pending.add(log_line); + for (record = 0; record < eeblock.size(); record++) { + AltosEepromRecord r = eeblock.get(record); - if (cmd == Altos.AO_LOG_STATE && a == Altos.ao_flight_landed) { - done = true; - } - } - addr += 8; - } - if (!any_valid) - done = true; - } - if (eeprom_file == null) { - eeprom_name = new AltosFile(serial,flight,"eeprom"); - eeprom_file = new FileWriter(eeprom_name); - if (eeprom_file != null) { - FlushPending(eeprom_file, eeprom_pending); + String log_line = String.format("%c %4x %4x %4x\n", + r.cmd, r.tick, r.a, r.b); + if (eeprom_file != null) + eeprom_file.write(log_line); + else + eeprom_pending.add(log_line); } } + CheckFile(true); if (eeprom_file != null) { eeprom_file.flush(); eeprom_file.close(); @@ -235,6 +158,8 @@ public class AltosEepromDownload implements Runnable { SwingUtilities.invokeLater(r); } + int start_block, end_block; + public void run () { if (remote) { serial_line.set_radio(); @@ -243,7 +168,7 @@ public class AltosEepromDownload implements Runnable { } try { - CaptureLog(); + CaptureLog(start_block, end_block); } catch (IOException ee) { show_error (device.toShortString(), ee.getLocalizedMessage()); @@ -271,6 +196,7 @@ public class AltosEepromDownload implements Runnable { serial_line = new AltosSerial(device); if (!device.matchProduct(AltosDevice.product_telemetrum)) remote = true; + monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed); monitor.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -280,6 +206,8 @@ public class AltosEepromDownload implements Runnable { }); eeprom_thread = new Thread(this); + start_block = 0; + end_block = 0xfff; eeprom_thread.start(); } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(frame, diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index 5a673817..e61a7159 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -26,7 +26,9 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.*; + +import libaltosJNI.*; public class AltosEepromRecord { public int cmd; @@ -36,6 +38,49 @@ public class AltosEepromRecord { public String data; public boolean tick_valid; + int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + int checksum(int[] line) { + int csum = 0x5a; + for (int i = 1; i < line.length; i++) + csum += line[i]; + return csum & 0xff; + } + + public AltosEepromRecord (AltosSerial serial_line, int addr) + throws TimeoutException, ParseException, InterruptedException { + String line = serial_line.get_reply(5000); + if (line == null) + throw new TimeoutException(); + int[] values = ParseHex(line); + + if (values == null) + throw new ParseException(String.format("invalid line %s", line), 0); + if (values[0] != (addr & 0xff)) + throw new ParseException(String.format("data address out of sync at 0x%x", + addr), 0); + if (checksum(values) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", addr), 0); + + cmd = values[1]; + tick = values[3] + (values[4] << 8); + a = values[5] + (values[6] << 8); + b = values[7] + (values[8] << 8); + data = null; + tick_valid = true; + } + public AltosEepromRecord (String line) { tick_valid = false; tick = 0; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index e2ff55af..8cdd64cc 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -15,6 +15,7 @@ altosui_JAVA = \ AltosAscent.java \ AltosChannelMenu.java \ AltosConfig.java \ + AltosConfigData.java \ AltosConfigUI.java \ AltosConfigureUI.java \ AltosConvert.java \ @@ -26,6 +27,7 @@ altosui_JAVA = \ AltosDeviceDialog.java \ AltosDevice.java \ AltosDisplayThread.java \ + AltosEepromBlock.java \ AltosEepromDownload.java \ AltosEepromMonitor.java \ AltosEepromIterable.java \ -- cgit v1.2.3 From 440d52e34364fdeeddc76a2d744cc6d1c934364f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 11 Jan 2011 21:28:07 -0800 Subject: altosui: Add support for parsing list of flights from the 'l' command This adds parsing support to enumerate the available flights, but does not yet provide any UI to use it. Signed-off-by: Keith Packard --- altosui/AltosEepromBlock.java | 24 ++++++++- altosui/AltosEepromDownload.java | 13 ++--- altosui/AltosEepromList.java | 103 +++++++++++++++++++++++++++++++++++++++ altosui/AltosEepromLog.java | 98 +++++++++++++++++++++++++++++++++++++ altosui/AltosEepromRecord.java | 6 ++- altosui/AltosSerial.java | 10 ++++ altosui/Makefile.am | 2 + 7 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 altosui/AltosEepromList.java create mode 100644 altosui/AltosEepromLog.java (limited to 'altosui') diff --git a/altosui/AltosEepromBlock.java b/altosui/AltosEepromBlock.java index 0c1a4a92..f223f3fb 100644 --- a/altosui/AltosEepromBlock.java +++ b/altosui/AltosEepromBlock.java @@ -38,6 +38,12 @@ public class AltosEepromBlock extends ArrayList { int state; boolean has_date; int year, month, day; + boolean has_lat; + double lat; + boolean has_lon; + double lon; + boolean has_time; + int hour, minute, second; public AltosEepromBlock (AltosSerial serial_line, int block) throws TimeoutException, InterruptedException { int addr; @@ -46,6 +52,9 @@ public class AltosEepromBlock extends ArrayList { has_flight = false; has_state = false; has_date = false; + has_lat = false; + has_lon = false; + has_time = false; serial_line.printf("e %x\n", block); for (addr = 0; !done && addr < 0x100;) { try { @@ -70,7 +79,20 @@ public class AltosEepromBlock extends ArrayList { day = (r.b & 0xff); has_date = true; } - + if (r.cmd == Altos.AO_LOG_GPS_TIME) { + hour = (r.a & 0xff); + minute = (r.a >> 8); + second = (r.b & 0xff); + has_time = true; + } + if (r.cmd == Altos.AO_LOG_GPS_LAT) { + lat = (double) (r.a | (r.b << 16)) / 1e7; + has_lat = true; + } + if (r.cmd == Altos.AO_LOG_GPS_LON) { + lon = (double) (r.a | (r.b << 16)) / 1e7; + has_lon = true; + } if (r.cmd == Altos.AO_LOG_STATE && r.a == Altos.ao_flight_landed) done = true; add(addr / 8, r); diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 9a748710..ca31fdcf 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -161,11 +161,12 @@ public class AltosEepromDownload implements Runnable { int start_block, end_block; public void run () { - if (remote) { - serial_line.set_radio(); - serial_line.printf("p\nE 0\n"); - serial_line.flush_input(); - } + try { + new AltosEepromList(serial_line, remote); + } catch (Exception ee) { } + + if (remote) + serial_line.start_remote(); try { CaptureLog(start_block, end_block); @@ -179,7 +180,7 @@ public class AltosEepromDownload implements Runnable { "Connection Failed"); } if (remote) - serial_line.printf("~"); + serial_line.stop_remote(); monitor.done(); serial_line.flush_output(); serial_line.close(); diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java new file mode 100644 index 00000000..ac4a29de --- /dev/null +++ b/altosui/AltosEepromList.java @@ -0,0 +1,103 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +class AltosEepromFlight { + int flight; + int start; + int end; + + public AltosEepromFlight(int in_flight, int in_start, int in_end) { + flight = in_flight; + start = in_start; + end = in_end; + } +} + +public class AltosEepromList extends ArrayList { + AltosConfigData config_data; + + public AltosEepromList (AltosSerial serial_line, boolean remote) throws IOException, InterruptedException, TimeoutException { + try { + if (remote) + serial_line.start_remote(); + config_data = new AltosConfigData (serial_line); + if (config_data.serial == 0) + throw new IOException("no serial number found"); + + ArrayList flights = new ArrayList(); + if (config_data.flight_log_max != 0) { + serial_line.printf("l\n"); + for (;;) { + String line = serial_line.get_reply(5000); + if (line == null) + throw new TimeoutException(); + if (line.contains("done")) + break; + if (line.contains("Syntax")) + continue; + String[] tokens = line.split("\\s+"); + System.out.printf("got line %s (%d tokens)\n", line, tokens.length); + if (tokens.length < 6) + break; + + int flight = -1, start = -1, end = -1; + try { + if (tokens[0].equals("flight")) + flight = AltosParse.parse_int(tokens[1]); + if (tokens[2].equals("start")) + start = AltosParse.parse_hex(tokens[3]); + if (tokens[4].equals("end")) + end = AltosParse.parse_hex(tokens[5]); + System.out.printf("parsed flight %d %x %x\n", flight, start, end); + if (flight > 0 && start >= 0 && end > 0) + flights.add(new AltosEepromFlight(flight, start, end)); + } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); } + } + } else { + flights.add(new AltosEepromFlight(0, 0, 0xfff)); + } + for (AltosEepromFlight flight : flights) { + System.out.printf("Scanning flight %d %x %x\n", flight.flight, flight.start, flight.end); + add(new AltosEepromLog(serial_line, config_data.serial, + flight.start, flight.end)); + } + } finally { + if (remote) + serial_line.stop_remote(); + serial_line.flush_output(); + } + for (int i = 0; i < size(); i++) { + AltosEepromLog l = get(i); + System.out.printf("Found flight %d at %x - %x\n", l.flight, l.start_block, l.end_block); + } + } +} \ No newline at end of file diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java new file mode 100644 index 00000000..36289b42 --- /dev/null +++ b/altosui/AltosEepromLog.java @@ -0,0 +1,98 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosEepromLog { + int serial; + boolean has_flight; + int flight; + int start_block; + int end_block; + + boolean has_gps; + int year, month, day; + int hour, minute, second; + double lat, lon; + + public AltosEepromLog(AltosSerial serial_line, int in_serial, + int in_start_block, int in_end_block) + throws InterruptedException, TimeoutException { + + int block; + boolean has_date = false, has_time = false, has_lat = false, has_lon = false; + + start_block = in_start_block; + end_block = in_end_block; + serial = in_serial; + + if (in_end_block > in_start_block + 2) + in_end_block = in_start_block + 2; + + for (block = in_start_block; block < in_end_block; block++) { + AltosEepromBlock eeblock = new AltosEepromBlock(serial_line, block); + if (eeblock.has_flight) { + flight = eeblock.flight; + has_flight = true; + } + if (eeblock.has_date) { + year = eeblock.year; + month = eeblock.month; + day = eeblock.day; + has_date = true; + } + if (eeblock.has_time) { + hour = eeblock.hour; + minute = eeblock.minute; + second = eeblock.second; + has_time = true; + } + if (eeblock.has_lat) { + lat = eeblock.lat; + has_lat = true; + } + if (eeblock.has_lon) { + lon = eeblock.lon; + has_lon = true; + } + if (has_date && has_time && has_lat && has_lon) + has_gps = true; + if (has_gps && has_flight) + break; + } + System.out.printf("Serial %d start block %d end block %d\n", + serial, start_block, end_block); + if (has_flight) + System.out.printf("Flight %d\n", flight); + if (has_gps) + System.out.printf("%d-%d-%d %d:%02d:%02d Lat %f Lon %f\n", + year, month, day, hour, minute, second, lat, lon); + } +} diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index e61a7159..584a04b7 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -65,8 +65,10 @@ public class AltosEepromRecord { throw new TimeoutException(); int[] values = ParseHex(line); - if (values == null) - throw new ParseException(String.format("invalid line %s", line), 0); + if (values == null || values.length < 9) { + System.out.printf("invalid line %s", line); + throw new ParseException(String.format("inalid line %s", line), 0); + } if (values[0] != (addr & 0xff)) throw new ParseException(String.format("data address out of sync at 0x%x", addr), 0); diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index b19143e5..6dce6f3d 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -242,6 +242,16 @@ public class AltosSerial implements Runnable { } } + public void start_remote() { + set_radio(); + printf("p\nE 0\n"); + flush_input(); + } + + public void stop_remote() { + printf ("~"); + } + public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { device = in_device; line = ""; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 8cdd64cc..58d23787 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -29,6 +29,8 @@ altosui_JAVA = \ AltosDisplayThread.java \ AltosEepromBlock.java \ AltosEepromDownload.java \ + AltosEepromList.java \ + AltosEepromLog.java \ AltosEepromMonitor.java \ AltosEepromIterable.java \ AltosEepromRecord.java \ -- cgit v1.2.3 From 8801b8c1947bd39f7c985b91a2ba8dbc81bcc91a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 12 Jan 2011 12:40:45 -0800 Subject: altosui: Add eeprom 'manage' ui to download and delete multiple flights This shows the list of available flights and provides options to download and/or delete each one. Signed-off-by: Keith Packard --- altosui/AltosEepromDelete.java | 148 ++++++++++++++++++++++++++++++++++++ altosui/AltosEepromDownload.java | 124 +++++++++++++++---------------- altosui/AltosEepromList.java | 31 +++++++- altosui/AltosEepromLog.java | 16 ++++ altosui/AltosEepromManage.java | 157 +++++++++++++++++++++++++++++++++++++++ altosui/AltosEepromMonitor.java | 18 +++++ altosui/AltosEepromSelect.java | 132 ++++++++++++++++++++++++++++++++ altosui/AltosUI.java | 2 +- altosui/Makefile.am | 3 + 9 files changed, 565 insertions(+), 66 deletions(-) create mode 100644 altosui/AltosEepromDelete.java create mode 100644 altosui/AltosEepromManage.java create mode 100644 altosui/AltosEepromSelect.java (limited to 'altosui') diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java new file mode 100644 index 00000000..c95eda15 --- /dev/null +++ b/altosui/AltosEepromDelete.java @@ -0,0 +1,148 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosEepromDelete implements Runnable { + AltosEepromList flights; + Thread eeprom_thread; + AltosSerial serial_line; + boolean remote; + JFrame frame; + ActionListener listener; + boolean success; + + private void DeleteLog (AltosEepromLog log) + throws IOException, InterruptedException, TimeoutException { + + if (flights.config_data.flight_log_max != 0) { + + /* Devices with newer firmware can erase the + * flash blocks containing each flight + */ + serial_line.flush_input(); + serial_line.printf("d %d\n", log.flight); + System.out.printf("Attempt to delete flight %d\n", log.flight); + for (;;) { + /* It can take a while to erase the flash... */ + String line = serial_line.get_reply(20000); + System.out.printf("got back line %s\n", line); + if (line == null) + throw new TimeoutException(); + if (line.equals("Erased")) + break; + if (line.startsWith("No such")) + throw new IOException(line); + } + } + } + + private void show_error_internal(String message, String title) { + JOptionPane.showMessageDialog(frame, + message, + title, + JOptionPane.ERROR_MESSAGE); + } + + private void show_error(String in_message, String in_title) { + final String message = in_message; + final String title = in_title; + Runnable r = new Runnable() { + public void run() { + try { + show_error_internal(message, title); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + public void run () { + if (remote) + serial_line.start_remote(); + + success = false; + try { + for (AltosEepromLog log : flights) { + if (log.delete) { + DeleteLog(log); + } + } + System.out.printf("All flights successfully deleted\n"); + success = true; + } catch (IOException ee) { + show_error (ee.getLocalizedMessage(), + serial_line.device.toShortString()); + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + show_error (String.format("Connection to \"%s\" failed", + serial_line.device.toShortString()), + "Connection Failed"); + } + if (remote) + serial_line.stop_remote(); + serial_line.flush_output(); + serial_line.close(); + if (listener != null) { + Runnable r = new Runnable() { + public void run() { + try { + listener.actionPerformed(new ActionEvent(this, + success ? 1 : 0, + "delete")); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + } + + public void start() { + eeprom_thread = new Thread(this); + eeprom_thread.start(); + } + + public void addActionListener(ActionListener l) { + listener = l; + } + + public AltosEepromDelete(JFrame given_frame, + AltosSerial given_serial_line, + boolean given_remote, + AltosEepromList given_flights) { + frame = given_frame; + serial_line = given_serial_line; + remote = given_remote; + flights = given_flights; + success = false; + } +} \ No newline at end of file diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index ca31fdcf..5d19acec 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -33,21 +33,21 @@ import libaltosJNI.*; public class AltosEepromDownload implements Runnable { JFrame frame; - AltosDevice device; AltosSerial serial_line; boolean remote; Thread eeprom_thread; AltosEepromMonitor monitor; - int serial = 0; int flight = 0; int year = 0, month = 0, day = 0; boolean want_file = false; FileWriter eeprom_file = null; LinkedList eeprom_pending = new LinkedList(); - AltosConfigData config_data; + AltosEepromList flights; + ActionListener listener; + boolean success; private void FlushPending() throws IOException { - for (String s : config_data) { + for (String s : flights.config_data) { eeprom_file.write(s); eeprom_file.write('\n'); } @@ -62,9 +62,9 @@ public class AltosEepromDownload implements Runnable { if (force || (flight != 0 && want_file)) { AltosFile eeprom_name; if (year != 0 && month != 0 && day != 0) - eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom"); + eeprom_name = new AltosFile(year, month, day, flights.config_data.serial, flight, "eeprom"); else - eeprom_name = new AltosFile(serial, flight, "eeprom"); + eeprom_name = new AltosFile(flights.config_data.serial, flight, "eeprom"); eeprom_file = new FileWriter(eeprom_name); if (eeprom_file != null) { @@ -75,25 +75,24 @@ public class AltosEepromDownload implements Runnable { } } - void CaptureLog(int start_block, int end_block) throws IOException, InterruptedException, TimeoutException { + void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException { int block, state_block = 0; int state = 0; boolean done = false; int record; - config_data = new AltosConfigData(serial_line); - serial = config_data.serial; - if (serial == 0) + if (flights.config_data.serial == 0) throw new IOException("no serial number found"); - monitor.set_serial(serial); + monitor.set_serial(flights.config_data.serial); /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */ - state = 0; state_block = start_block; - for (block = start_block; !done && block < end_block; block++) { + state = 0; state_block = log.start_block; + for (block = log.start_block; !done && block < log.end_block; block++) { monitor.set_value(Altos.state_to_string[state], state, block - state_block); AltosEepromBlock eeblock = new AltosEepromBlock(serial_line, block); + if (eeblock.has_flight) { flight = eeblock.flight; monitor.set_flight(flight); @@ -117,7 +116,7 @@ public class AltosEepromDownload implements Runnable { state = eeblock.state; } - CheckFile(true); + CheckFile(false); for (record = 0; record < eeblock.size(); record++) { AltosEepromRecord r = eeblock.get(record); @@ -158,76 +157,73 @@ public class AltosEepromDownload implements Runnable { SwingUtilities.invokeLater(r); } - int start_block, end_block; - public void run () { - try { - new AltosEepromList(serial_line, remote); - } catch (Exception ee) { } - if (remote) serial_line.start_remote(); try { - CaptureLog(start_block, end_block); + for (AltosEepromLog log : flights) { + if (log.download) { + monitor.reset(); + CaptureLog(log); + } + } + System.out.printf("All flights successfully downloaded\n"); + success = true; } catch (IOException ee) { - show_error (device.toShortString(), + show_error (serial_line.device.toShortString(), ee.getLocalizedMessage()); } catch (InterruptedException ie) { } catch (TimeoutException te) { show_error (String.format("Connection to \"%s\" failed", - device.toShortString()), + serial_line.device.toShortString()), "Connection Failed"); } if (remote) serial_line.stop_remote(); monitor.done(); serial_line.flush_output(); - serial_line.close(); + if (listener != null) { + Runnable r = new Runnable() { + public void run() { + try { + listener.actionPerformed(new ActionEvent(this, + success ? 1 : 0, + "download")); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } } - public AltosEepromDownload(JFrame given_frame) { - frame = given_frame; - device = AltosDeviceDialog.show(frame, AltosDevice.product_any); + public void start() { + eeprom_thread = new Thread(this); + eeprom_thread.start(); + } - remote = false; + public void addActionListener(ActionListener l) { + listener = l; + } - if (device != null) { - try { - serial_line = new AltosSerial(device); - if (!device.matchProduct(AltosDevice.product_telemetrum)) - remote = true; + public AltosEepromDownload(JFrame given_frame, + AltosSerial given_serial_line, + boolean given_remote, + AltosEepromList given_flights) { - monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed); - monitor.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (eeprom_thread != null) - eeprom_thread.interrupt(); - } - }); - - eeprom_thread = new Thread(this); - start_block = 0; - end_block = 0xfff; - eeprom_thread.start(); - } catch (FileNotFoundException ee) { - JOptionPane.showMessageDialog(frame, - String.format("Cannot open device \"%s\"", - device.toShortString()), - "Cannot open target device", - JOptionPane.ERROR_MESSAGE); - } catch (AltosSerialInUseException si) { - JOptionPane.showMessageDialog(frame, - String.format("Device \"%s\" already in use", - device.toShortString()), - "Device in use", - JOptionPane.ERROR_MESSAGE); - } catch (IOException ee) { - JOptionPane.showMessageDialog(frame, - device.toShortString(), - ee.getLocalizedMessage(), - JOptionPane.ERROR_MESSAGE); - } - } + frame = given_frame; + serial_line = given_serial_line; + remote = given_remote; + flights = given_flights; + success = false; + + monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed); + monitor.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (eeprom_thread != null) + eeprom_thread.interrupt(); + } + }); } } diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index ac4a29de..a932dd12 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -30,6 +30,12 @@ import java.util.concurrent.*; import libaltosJNI.*; +/* + * Temporary structure to hold the list of stored flights; + * each of these will be queried in turn to generate more + * complete information + */ + class AltosEepromFlight { int flight; int start; @@ -42,10 +48,16 @@ class AltosEepromFlight { } } +/* + * Construct a list of flights available in a connected device + */ + public class AltosEepromList extends ArrayList { AltosConfigData config_data; - public AltosEepromList (AltosSerial serial_line, boolean remote) throws IOException, InterruptedException, TimeoutException { + public AltosEepromList (AltosSerial serial_line, boolean remote) + throws IOException, InterruptedException, TimeoutException + { try { if (remote) serial_line.start_remote(); @@ -54,7 +66,13 @@ public class AltosEepromList extends ArrayList { throw new IOException("no serial number found"); ArrayList flights = new ArrayList(); + if (config_data.flight_log_max != 0) { + + /* Devices with newer firmware will support the 'l' + * command which will list the region of storage + * occupied by each available flight + */ serial_line.printf("l\n"); for (;;) { String line = serial_line.get_reply(5000); @@ -83,8 +101,19 @@ public class AltosEepromList extends ArrayList { } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); } } } else { + + /* Older devices will hold only a single + * flight. This also assumes that any older + * device will have a 1MB flash device + */ flights.add(new AltosEepromFlight(0, 0, 0xfff)); } + + /* With the list of flights collected, collect more complete + * information on them by reading the first block or two of + * data. This will add GPS coordinates and a date. For older + * firmware, this will also extract the flight number. + */ for (AltosEepromFlight flight : flights) { System.out.printf("Scanning flight %d %x %x\n", flight.flight, flight.start, flight.end); add(new AltosEepromLog(serial_line, config_data.serial, diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index 36289b42..f284f103 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -30,6 +30,10 @@ import java.util.concurrent.*; import libaltosJNI.*; +/* + * Extract a bit of information from an eeprom-stored flight log. + */ + public class AltosEepromLog { int serial; boolean has_flight; @@ -42,6 +46,9 @@ public class AltosEepromLog { int hour, minute, second; double lat, lon; + boolean download; + boolean delete; + public AltosEepromLog(AltosSerial serial_line, int in_serial, int in_start_block, int in_end_block) throws InterruptedException, TimeoutException { @@ -53,6 +60,15 @@ public class AltosEepromLog { end_block = in_end_block; serial = in_serial; + /* + * By default, request that every log be downloaded but not deleted + */ + download = true; + delete = false; + /* + * Only look in the first two blocks so that this + * process doesn't take a long time + */ if (in_end_block > in_start_block + 2) in_end_block = in_start_block + 2; diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java new file mode 100644 index 00000000..b64ee525 --- /dev/null +++ b/altosui/AltosEepromManage.java @@ -0,0 +1,157 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosEepromManage implements ActionListener { + + JFrame frame; + boolean remote; + AltosDevice device; + AltosSerial serial_line; + AltosEepromList flights; + AltosEepromDownload download; + AltosEepromDelete delete; + boolean any_download; + boolean any_delete; + + public void finish() { + if (serial_line != null) { + serial_line.flush_output(); + serial_line.close(); + serial_line = null; + } + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + boolean success = e.getID() != 0; + + System.out.printf("Eeprom manager action %s %d\n", cmd, e.getID()); + if (cmd.equals("download")) { + if (success) { + System.out.printf("Download succeeded\n"); + if (any_delete) + delete.start(); + else + finish(); + } + } else if (cmd.equals("delete")) { + if (success) + System.out.printf("Delete succeeded\n"); + finish(); + } + } + + public AltosEepromManage(JFrame given_frame) { + + frame = given_frame; + device = AltosDeviceDialog.show(frame, AltosDevice.product_any); + + remote = false; + any_download = false; + any_delete = false; + + if (device != null) { + try { + serial_line = new AltosSerial(device); + if (!device.matchProduct(AltosDevice.product_telemetrum)) + remote = true; + + flights = new AltosEepromList(serial_line, remote); + + if (flights.size() == 0) { + } else { + AltosEepromSelect select = new AltosEepromSelect(frame, flights); + + if (select.run()) { + for (AltosEepromLog flight : flights) { + any_download = any_download || flight.download; + any_delete = any_delete || flight.delete; + } + if (any_download) { + download = new AltosEepromDownload(frame, + serial_line, + remote, + flights); + download.addActionListener(this); + } + + if (any_delete) { + delete = new AltosEepromDelete(frame, + serial_line, + remote, + flights); + delete.addActionListener(this); + } + + /* + * Start flight log download + */ + + if (any_download) + download.start(); + else if (any_delete) + delete.start(); + else + finish(); + } + } + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(frame, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(frame, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException ee) { + JOptionPane.showMessageDialog(frame, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + finish(); + } catch (TimeoutException te) { + JOptionPane.showMessageDialog(frame, + String.format("Communications failed with \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + finish(); + } catch (InterruptedException ie) { + finish(); + } + } + } +} diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java index 13a49a95..b9d913fa 100644 --- a/altosui/AltosEepromMonitor.java +++ b/altosui/AltosEepromMonitor.java @@ -239,4 +239,22 @@ public class AltosEepromMonitor extends JDialog { }; SwingUtilities.invokeLater(r); } + + private void reset_internal() { + set_value_internal("startup",min_state,0); + set_flight_internal(0); + set_file_internal(""); + } + + public void reset() { + Runnable r = new Runnable() { + public void run() { + try { + reset_internal(); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } } diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java new file mode 100644 index 00000000..104d3180 --- /dev/null +++ b/altosui/AltosEepromSelect.java @@ -0,0 +1,132 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; +import libaltosJNI.libaltos; +import libaltosJNI.altos_device; +import libaltosJNI.SWIGTYPE_p_altos_file; +import libaltosJNI.SWIGTYPE_p_altos_list; + +class AltosEepromItem extends JPanel implements ActionListener { + AltosEepromLog log; + JCheckBox download; + JCheckBox delete; + JLabel label; + + public void actionPerformed(ActionEvent e) { + System.out.printf("eeprom item action %s %d\n", e.getActionCommand(), e.getID()); + if (e.getSource() == download) { + log.download = download.isSelected(); + System.out.printf("download set to %b\n", log.download); + } else if (e.getSource() == delete) { + log.delete = delete.isSelected(); + System.out.printf("delete set to %b\n", log.delete); + } + } + + public AltosEepromItem(AltosEepromLog in_log) { + log = in_log; + + download = new JCheckBox("Download", log.download); + download.addActionListener(this); + add(download); + delete = new JCheckBox("Delete", log.delete); + delete.addActionListener(this); + add(delete); + label = new JLabel(String.format("Flight %d %4d-%02d-%02d", + log.flight, log.year, log.month, log.day)); + add(label); + } +} + +public class AltosEepromSelect extends JDialog implements ActionListener { + private JList list; + private JFrame frame; + JButton ok; + JButton cancel; + boolean success; + + /* Listen for events from our buttons */ + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if (cmd.equals("ok")) + success = true; + setVisible(false); + } + + public boolean run() { + success = false; + setLocationRelativeTo(frame); + setVisible(true); + return success; + } + + public AltosEepromSelect (JFrame in_frame, + AltosEepromList flights) { + + super(in_frame, String.format("Flight list for serial %d", flights.config_data.serial), true); + frame = in_frame; + + JLabel selectLabel = new JLabel("Select flights to download and/or delete", SwingConstants.CENTER); + + JPanel labelPane = new JPanel(); + labelPane.setLayout(new BoxLayout(labelPane, BoxLayout.X_AXIS)); + labelPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); + labelPane.add(Box.createHorizontalGlue()); + labelPane.add(selectLabel); + labelPane.add(Box.createHorizontalGlue()); + + JPanel flightPane = new JPanel(); + flightPane.setLayout(new BoxLayout(flightPane, BoxLayout.Y_AXIS)); + flightPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); + for (AltosEepromLog flight : flights) { + flightPane.add(new AltosEepromItem(flight)); + } + + ok = new JButton("OK"); + ok.addActionListener(this); + ok.setActionCommand("ok"); + + cancel = new JButton("Cancel"); + cancel.addActionListener(this); + cancel.setActionCommand("cancel"); + + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + buttonPane.add(Box.createHorizontalGlue()); + buttonPane.add(cancel); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(ok); + + Container contentPane = getContentPane(); + + contentPane.add(labelPane, BorderLayout.PAGE_START); + contentPane.add(flightPane, BorderLayout.CENTER); + contentPane.add(buttonPane, BorderLayout.PAGE_END); + + pack(); + } +} diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 94c4dd2a..90e3d7f0 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -245,7 +245,7 @@ public class AltosUI extends JFrame { * a TeleDongle over the packet link */ private void SaveFlightData() { - new AltosEepromDownload(AltosUI.this); + new AltosEepromManage(AltosUI.this); } /* Load a flight log file and write out a CSV file containing diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 58d23787..196d7032 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -28,12 +28,15 @@ altosui_JAVA = \ AltosDevice.java \ AltosDisplayThread.java \ AltosEepromBlock.java \ + AltosEepromDelete.java \ AltosEepromDownload.java \ AltosEepromList.java \ AltosEepromLog.java \ + AltosEepromManage.java \ AltosEepromMonitor.java \ AltosEepromIterable.java \ AltosEepromRecord.java \ + AltosEepromSelect.java \ AltosFile.java \ AltosFlash.java \ AltosFlashUI.java \ -- cgit v1.2.3 From 2d154be89246e111a36f7c2700effbb2c97da541 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Jan 2011 16:44:50 -0800 Subject: altosui: Show dialog after successful delete or when no flights Make sure the user always sees confirmation for flight log management. Signed-off-by: Keith Packard --- altosui/AltosEepromManage.java | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index b64ee525..2704f883 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -50,6 +50,20 @@ public class AltosEepromManage implements ActionListener { } } + private String showDeletedFlights() { + String result = ""; + + for (AltosEepromLog flight : flights) { + if (flight.delete) { + if (result.equals("")) + result = String.format("%d", flight.flight); + else + result = String.format("%s, %d", result, flight.flight); + } + } + return result; + } + public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); boolean success = e.getID() != 0; @@ -57,15 +71,19 @@ public class AltosEepromManage implements ActionListener { System.out.printf("Eeprom manager action %s %d\n", cmd, e.getID()); if (cmd.equals("download")) { if (success) { - System.out.printf("Download succeeded\n"); if (any_delete) delete.start(); else finish(); } } else if (cmd.equals("delete")) { - if (success) - System.out.printf("Delete succeeded\n"); + if (success) { + JOptionPane.showMessageDialog(frame, + String.format("Flights erased: %s", + showDeletedFlights()), + serial_line.device.toShortString(), + JOptionPane.INFORMATION_MESSAGE); + } finish(); } } @@ -88,6 +106,11 @@ public class AltosEepromManage implements ActionListener { flights = new AltosEepromList(serial_line, remote); if (flights.size() == 0) { + JOptionPane.showMessageDialog(frame, + String.format("No flights available on %d", + device.getSerial()), + serial_line.device.toShortString(), + JOptionPane.INFORMATION_MESSAGE); } else { AltosEepromSelect select = new AltosEepromSelect(frame, flights); -- cgit v1.2.3 From fcaee12a64d5e195b55b8f77c19dfc0c57ef5d58 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Jan 2011 16:47:19 -0800 Subject: altosui: Ensure serial line is flushed after disabling remote link Flush the '~' character. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 6dce6f3d..78da5d1f 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -250,6 +250,7 @@ public class AltosSerial implements Runnable { public void stop_remote() { printf ("~"); + flush_output(); } public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { -- cgit v1.2.3 From d908c2ebd0b11a54cfd922a192249d0f0df0ddb0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Jan 2011 16:47:36 -0800 Subject: altosui: Add preference for serial debugging. This dumps serial input/output to stdout. Signed-off-by: Keith Packard --- altosui/AltosConfigureUI.java | 28 +++++++++++++++++++++++++++- altosui/AltosPreferences.java | 22 ++++++++++++++++++++++ altosui/AltosSerial.java | 13 ++++++++++--- 3 files changed, 59 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index 153c59fd..ab3d950e 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -47,6 +47,8 @@ public class AltosConfigureUI JLabel callsign_label; JTextField callsign_value; + JRadioButton serial_debug; + /* DocumentListener interface methods */ public void changedUpdate(DocumentEvent e) { AltosPreferences.set_callsign(callsign_value.getText()); @@ -166,6 +168,30 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.WEST; pane.add(callsign_value, c); + /* Serial debug setting */ + c.gridx = 0; + c.gridy = 4; + c.gridwidth = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(new JLabel("Serial Debug"), c); + + serial_debug = new JRadioButton("Enable", AltosPreferences.serial_debug()); + serial_debug.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JRadioButton item = (JRadioButton) e.getSource(); + boolean enabled = item.isSelected(); + AltosPreferences.set_serial_debug(enabled); + } + }); + + c.gridx = 1; + c.gridy = 4; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(serial_debug, c); + /* And a close button at the bottom */ close = new JButton("Close"); close.addActionListener(new ActionListener() { @@ -174,7 +200,7 @@ public class AltosConfigureUI } }); c.gridx = 0; - c.gridy = 4; + c.gridy = 5; c.gridwidth = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index c6ae6cbd..d4df4e16 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -43,6 +43,9 @@ class AltosPreferences { /* firmware directory preference name */ final static String firmwaredirPreference = "FIRMWARE"; + /* serial debug preference name */ + final static String serialDebugPreference = "SERIAL-DEBUG"; + /* Default logdir is ~/TeleMetrum */ final static String logdirName = "TeleMetrum"; @@ -67,6 +70,9 @@ class AltosPreferences { /* Firmware directory */ static File firmwaredir; + /* Serial debug */ + static boolean serial_debug; + public static void init(Component ui) { preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); @@ -97,6 +103,9 @@ class AltosPreferences { firmwaredir = new File(firmwaredir_string); else firmwaredir = null; + + serial_debug = preferences.getBoolean(serialDebugPreference, false); + AltosSerial.set_debug(serial_debug); } static void flush_preferences() { @@ -215,4 +224,17 @@ class AltosPreferences { public static File firmwaredir() { return firmwaredir; } + + public static void set_serial_debug(boolean new_serial_debug) { + serial_debug = new_serial_debug; + AltosSerial.set_debug(serial_debug); + synchronized (preferences) { + preferences.putBoolean(serialDebugPreference, serial_debug); + flush_preferences(); + } + } + + public static boolean serial_debug() { + return serial_debug; + } } diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 78da5d1f..3ad16b2b 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -47,6 +47,11 @@ public class AltosSerial implements Runnable { byte[] line_bytes; int line_count; boolean monitor_mode; + static boolean debug; + + static void set_debug(boolean new_debug) { + debug = new_debug; + } public void run () { int c; @@ -84,7 +89,8 @@ public class AltosSerial implements Runnable { q.put(new AltosLine (line)); } } else { -// System.out.printf("GOT: %s\n", line); + if (debug) + System.out.printf("\t\t\t\t\t%s\n", line); reply_queue.put(new AltosLine (line)); } line_count = 0; @@ -176,13 +182,14 @@ public class AltosSerial implements Runnable { } } - public void putc(char c) { + private void putc(char c) { if (altos != null) libaltos.altos_putchar(altos, c); } public void print(String data) { -// System.out.printf("\"%s\" ", data); + if (debug) + System.out.printf("%s", data); for (int i = 0; i < data.length(); i++) putc(data.charAt(i)); } -- cgit v1.2.3 From fef302656f21ae0ab4772f72979cbb7f071da89a Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 16 Jan 2011 20:25:19 +1300 Subject: Re-order and re-arrange eeprom download dialog Signed-off-by: Mike Beattie --- altosui/AltosEepromSelect.java | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index 104d3180..7995d32b 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -38,25 +38,30 @@ class AltosEepromItem extends JPanel implements ActionListener { System.out.printf("eeprom item action %s %d\n", e.getActionCommand(), e.getID()); if (e.getSource() == download) { log.download = download.isSelected(); - System.out.printf("download set to %b\n", log.download); + System.out.printf("download for flight %d set to %b\n", log.flight, log.download); } else if (e.getSource() == delete) { log.delete = delete.isSelected(); - System.out.printf("delete set to %b\n", log.delete); + System.out.printf("delete for flight %d set to %b\n", log.flight, log.delete); } } public AltosEepromItem(AltosEepromLog in_log) { log = in_log; - download = new JCheckBox("Download", log.download); + label = new JLabel(String.format("Flight #%02d - %04d-%02d-%02d", + log.flight, log.year, log.month, log.day)); + label.setPreferredSize(new Dimension(170, 15)); + add(label); + download = new JCheckBox("", log.download); download.addActionListener(this); + download.setPreferredSize(new Dimension(100, 15)); + download.setHorizontalAlignment(SwingConstants.CENTER); add(download); - delete = new JCheckBox("Delete", log.delete); + delete = new JCheckBox("", log.delete); delete.addActionListener(this); + delete.setPreferredSize(new Dimension(70, 15)); + delete.setHorizontalAlignment(SwingConstants.CENTER); add(delete); - label = new JLabel(String.format("Flight %d %4d-%02d-%02d", - log.flight, log.year, log.month, log.day)); - add(label); } } @@ -98,9 +103,24 @@ public class AltosEepromSelect extends JDialog implements ActionListener { labelPane.add(selectLabel); labelPane.add(Box.createHorizontalGlue()); + JLabel flightHeaderLabel = new JLabel("Flight", SwingConstants.CENTER); + flightHeaderLabel.setPreferredSize(new Dimension(170, 15)); + + JLabel downloadHeaderLabel = new JLabel("Download", SwingConstants.CENTER); + downloadHeaderLabel.setPreferredSize(new Dimension(100, 15)); + + JLabel deleteHeaderLabel = new JLabel("Delete", SwingConstants.CENTER); + deleteHeaderLabel.setPreferredSize(new Dimension(70, 15)); + + JPanel headerPane = new JPanel(); + headerPane.add(flightHeaderLabel); + headerPane.add(downloadHeaderLabel); + headerPane.add(deleteHeaderLabel); + JPanel flightPane = new JPanel(); flightPane.setLayout(new BoxLayout(flightPane, BoxLayout.Y_AXIS)); flightPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); + flightPane.add(headerPane); for (AltosEepromLog flight : flights) { flightPane.add(new AltosEepromItem(flight)); } -- cgit v1.2.3 From df1c6ab3ac079199b5a12328c9ff5cfa6ac29b36 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Mon, 17 Jan 2011 00:40:07 +1300 Subject: Convert EepromSelect dialog to use a GridBag Signed-off-by: Mike Beattie --- altosui/AltosEepromSelect.java | 118 ++++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 30 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index 7995d32b..f0066aac 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -28,11 +28,11 @@ import libaltosJNI.altos_device; import libaltosJNI.SWIGTYPE_p_altos_file; import libaltosJNI.SWIGTYPE_p_altos_list; -class AltosEepromItem extends JPanel implements ActionListener { +class AltosEepromItem implements ActionListener { AltosEepromLog log; + JLabel label; JCheckBox download; JCheckBox delete; - JLabel label; public void actionPerformed(ActionEvent e) { System.out.printf("eeprom item action %s %d\n", e.getActionCommand(), e.getID()); @@ -50,18 +50,12 @@ class AltosEepromItem extends JPanel implements ActionListener { label = new JLabel(String.format("Flight #%02d - %04d-%02d-%02d", log.flight, log.year, log.month, log.day)); - label.setPreferredSize(new Dimension(170, 15)); - add(label); + download = new JCheckBox("", log.download); download.addActionListener(this); - download.setPreferredSize(new Dimension(100, 15)); - download.setHorizontalAlignment(SwingConstants.CENTER); - add(download); + delete = new JCheckBox("", log.delete); delete.addActionListener(this); - delete.setPreferredSize(new Dimension(70, 15)); - delete.setHorizontalAlignment(SwingConstants.CENTER); - add(delete); } } @@ -94,6 +88,10 @@ public class AltosEepromSelect extends JDialog implements ActionListener { super(in_frame, String.format("Flight list for serial %d", flights.config_data.serial), true); frame = in_frame; + /* Create the container for the dialog */ + Container contentPane = getContentPane(); + + /* First, we create a pane containing the dialog's header/title */ JLabel selectLabel = new JLabel("Select flights to download and/or delete", SwingConstants.CENTER); JPanel labelPane = new JPanel(); @@ -103,28 +101,90 @@ public class AltosEepromSelect extends JDialog implements ActionListener { labelPane.add(selectLabel); labelPane.add(Box.createHorizontalGlue()); - JLabel flightHeaderLabel = new JLabel("Flight", SwingConstants.CENTER); - flightHeaderLabel.setPreferredSize(new Dimension(170, 15)); - - JLabel downloadHeaderLabel = new JLabel("Download", SwingConstants.CENTER); - downloadHeaderLabel.setPreferredSize(new Dimension(100, 15)); - - JLabel deleteHeaderLabel = new JLabel("Delete", SwingConstants.CENTER); - deleteHeaderLabel.setPreferredSize(new Dimension(70, 15)); + /* Add the header to the container. */ + contentPane.add(labelPane, BorderLayout.PAGE_START); - JPanel headerPane = new JPanel(); - headerPane.add(flightHeaderLabel); - headerPane.add(downloadHeaderLabel); - headerPane.add(deleteHeaderLabel); - JPanel flightPane = new JPanel(); - flightPane.setLayout(new BoxLayout(flightPane, BoxLayout.Y_AXIS)); + /* Now we create the evilness that is a GridBag for the flight details */ + GridBagConstraints c; + Insets i = new Insets(4,4,4,4); + JPanel flightPane = new JPanel(); + flightPane.setLayout(new GridBagLayout()); flightPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); - flightPane.add(headerPane); + + /* Flight Header */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 0; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + JLabel flightHeaderLabel = new JLabel("Flight:"); + flightPane.add(flightHeaderLabel, c); + + /* Download Header */ + c = new GridBagConstraints(); + c.gridx = 1; c.gridy = 0; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + JLabel downloadHeaderLabel = new JLabel("Download:"); + flightPane.add(downloadHeaderLabel, c); + + /* Delete Header */ + c = new GridBagConstraints(); + c.gridx = 2; c.gridy = 0; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + JLabel deleteHeaderLabel = new JLabel("Delete:"); + flightPane.add(deleteHeaderLabel, c); + + /* Add the flights to the GridBag */ + AltosEepromItem item; + int itemNumber = 1; for (AltosEepromLog flight : flights) { - flightPane.add(new AltosEepromItem(flight)); + /* Create a flight object with handlers and + * appropriate UI items + */ + item = new AltosEepromItem(flight); + + /* Add a decriptive label for the flight */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = itemNumber; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + flightPane.add(item.label, c); + + /* Add a download checkbox for the flight */ + c = new GridBagConstraints(); + c.gridx = 1; c.gridy = itemNumber; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + flightPane.add(item.download, c); + + /* Add a delete checkbox for the flight */ + c = new GridBagConstraints(); + c.gridx = 2; c.gridy = itemNumber; + c.fill = GridBagConstraints.NONE; + c.weightx = 0.5; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + flightPane.add(item.delete, c); + + itemNumber++; } + /* Add the GridBag to the container */ + contentPane.add(flightPane, BorderLayout.CENTER); + + /* Create the dialog buttons */ ok = new JButton("OK"); ok.addActionListener(this); ok.setActionCommand("ok"); @@ -141,12 +201,10 @@ public class AltosEepromSelect extends JDialog implements ActionListener { buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); buttonPane.add(ok); - Container contentPane = getContentPane(); - - contentPane.add(labelPane, BorderLayout.PAGE_START); - contentPane.add(flightPane, BorderLayout.CENTER); + /* Add the buttons to the container */ contentPane.add(buttonPane, BorderLayout.PAGE_END); + /* Pack the window! */ pack(); } } -- cgit v1.2.3 From eec9eb2e81535e62c52fbb2e57a2d33f88f92c1a Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Mon, 17 Jan 2011 07:56:53 +1300 Subject: Close serial port if Download/Delete dialog is cancelled. Signed-off-by: Mike Beattie --- altosui/AltosEepromManage.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index 2704f883..c7efe478 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -146,6 +146,8 @@ public class AltosEepromManage implements ActionListener { else finish(); } + } else { + finish(); } } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(frame, -- cgit v1.2.3 From deb3c7b9206be0c9c46f75d35c8f766c26d9838f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 22:43:37 -0800 Subject: altosui: Reset eeprom download instance variables before reading flight To deal with downloading multiple flights in a single invocation, make sure all relevant instance variables are set back to start of flight download values each time a log is read. Signed-off-by: Keith Packard --- altosui/AltosEepromDownload.java | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 5d19acec..af70b15c 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -37,11 +37,13 @@ public class AltosEepromDownload implements Runnable { boolean remote; Thread eeprom_thread; AltosEepromMonitor monitor; - int flight = 0; - int year = 0, month = 0, day = 0; - boolean want_file = false; - FileWriter eeprom_file = null; - LinkedList eeprom_pending = new LinkedList(); + + int flight; + int year, month, day; + boolean want_file; + FileWriter eeprom_file; + LinkedList eeprom_pending; + AltosEepromList flights; ActionListener listener; boolean success; @@ -84,6 +86,16 @@ public class AltosEepromDownload implements Runnable { if (flights.config_data.serial == 0) throw new IOException("no serial number found"); + /* Reset per-capture variables */ + flight = 0; + year = 0; + month = 0; + day = 0; + want_file = false; + eeprom_file = null; + eeprom_pending = new LinkedList(); + + /* Set serial number in the monitor dialog window */ monitor.set_serial(flights.config_data.serial); /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */ -- cgit v1.2.3 From d4add23186b3586c99579d83efdc003f79e9bf7a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Jan 2011 14:26:18 -0800 Subject: altosui: Make serial debug more complete and accurate Display all serial input, including telemetry. Wait to display serial output until flush time, to debug missing flushing. Show when devices are opened and closed. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 3ad16b2b..e609c6b5 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -48,6 +48,7 @@ public class AltosSerial implements Runnable { int line_count; boolean monitor_mode; static boolean debug; + LinkedList pending_output = new LinkedList(); static void set_debug(boolean new_debug) { debug = new_debug; @@ -83,14 +84,14 @@ public class AltosSerial implements Runnable { for (int i = 0; i < line_count; i++) line = line + line_bytes[i]; } + if (debug) + System.out.printf("\t\t\t\t\t%s\n", line); if (line.startsWith("VERSION") || line.startsWith("CRC")) { for (int e = 0; e < monitors.size(); e++) { LinkedBlockingQueue q = monitors.get(e); q.put(new AltosLine (line)); } } else { - if (debug) - System.out.printf("\t\t\t\t\t%s\n", line); reply_queue.put(new AltosLine (line)); } line_count = 0; @@ -114,8 +115,12 @@ public class AltosSerial implements Runnable { } public void flush_output() { - if (altos != null) + if (altos != null) { + for (String s : pending_output) + System.out.print(s); + pending_output.clear(); libaltos.altos_flush(altos); + } } public void flush_input() { @@ -180,6 +185,8 @@ public class AltosSerial implements Runnable { synchronized (devices_opened) { devices_opened.remove(device.getPath()); } + if (debug) + System.out.printf("Closing %s\n", device.getPath()); } private void putc(char c) { @@ -189,7 +196,7 @@ public class AltosSerial implements Runnable { public void print(String data) { if (debug) - System.out.printf("%s", data); + pending_output.add(data); for (int i = 0; i < data.length(); i++) putc(data.charAt(i)); } @@ -209,6 +216,8 @@ public class AltosSerial implements Runnable { close(); throw new FileNotFoundException(device.toShortString()); } + if (debug) + System.out.printf("Open %s\n", device.getPath()); input_thread = new Thread(this); input_thread.start(); print("~\nE 0\n"); -- cgit v1.2.3 From fb534aae15f0f1e5d69790e159d0287b6b8a514a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Jan 2011 14:28:35 -0800 Subject: altosui: Use long input flush timeout when remote. 100ms isn't long enough to capture pending remote serial input, so use 300 ms in that mode. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index e609c6b5..f9f9e6e4 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -48,6 +48,7 @@ public class AltosSerial implements Runnable { int line_count; boolean monitor_mode; static boolean debug; + boolean remote; LinkedList pending_output = new LinkedList(); static void set_debug(boolean new_debug) { @@ -126,9 +127,13 @@ public class AltosSerial implements Runnable { public void flush_input() { flush_output(); boolean got_some; + + int timeout = 100; + if (remote) + timeout = 300; do { try { - Thread.sleep(100); + Thread.sleep(timeout); } catch (InterruptedException ie) { } got_some = !reply_queue.isEmpty(); @@ -259,14 +264,21 @@ public class AltosSerial implements Runnable { } public void start_remote() { + if (debug) + System.out.printf("start remote\n"); set_radio(); printf("p\nE 0\n"); flush_input(); + remote = true; } public void stop_remote() { + if (debug) + System.out.printf("stop remote\n"); + flush_input(); printf ("~"); flush_output(); + remote = false; } public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { -- cgit v1.2.3 From 987039b8f0b1d889aca9109d4c6a83f034ff64a7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Jan 2011 14:29:57 -0800 Subject: altosui: Remove debug message when eeprom downloads are complete. This message isn't useful now that this code appears to work. Signed-off-by: Keith Packard --- altosui/AltosEepromDownload.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index af70b15c..f1abd50c 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -180,7 +180,6 @@ public class AltosEepromDownload implements Runnable { CaptureLog(log); } } - System.out.printf("All flights successfully downloaded\n"); success = true; } catch (IOException ee) { show_error (serial_line.device.toShortString(), -- cgit v1.2.3 From 1bfdce6fc3367fdf03e0dc7ddd94da18723b8ba3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Jan 2011 14:30:38 -0800 Subject: altosui: Ensure serial device is closed after eeprom download finishes As this code is all event-driven, track which events will trigger further work and block closing the device in those specific cases, ensuring that all other code paths end up closing the device. Signed-off-by: Keith Packard --- altosui/AltosEepromManage.java | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index c7efe478..d10f7954 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -44,7 +44,7 @@ public class AltosEepromManage implements ActionListener { public void finish() { if (serial_line != null) { - serial_line.flush_output(); + serial_line.flush_input(); serial_line.close(); serial_line = null; } @@ -67,14 +67,15 @@ public class AltosEepromManage implements ActionListener { public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); boolean success = e.getID() != 0; + boolean running = false; System.out.printf("Eeprom manager action %s %d\n", cmd, e.getID()); if (cmd.equals("download")) { if (success) { - if (any_delete) + if (any_delete) { delete.start(); - else - finish(); + running = true; + } } } else if (cmd.equals("delete")) { if (success) { @@ -84,12 +85,15 @@ public class AltosEepromManage implements ActionListener { serial_line.device.toShortString(), JOptionPane.INFORMATION_MESSAGE); } - finish(); } + if (!running) + finish(); } public AltosEepromManage(JFrame given_frame) { + boolean running = false; + frame = given_frame; device = AltosDeviceDialog.show(frame, AltosDevice.product_any); @@ -139,15 +143,15 @@ public class AltosEepromManage implements ActionListener { * Start flight log download */ - if (any_download) + if (any_download) { download.start(); - else if (any_delete) + running = true; + } + else if (any_delete) { delete.start(); - else - finish(); + running = true; + } } - } else { - finish(); } } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(frame, @@ -166,17 +170,16 @@ public class AltosEepromManage implements ActionListener { device.toShortString(), ee.getLocalizedMessage(), JOptionPane.ERROR_MESSAGE); - finish(); } catch (TimeoutException te) { JOptionPane.showMessageDialog(frame, String.format("Communications failed with \"%s\"", device.toShortString()), "Cannot open target device", JOptionPane.ERROR_MESSAGE); - finish(); } catch (InterruptedException ie) { - finish(); } + if (!running) + finish(); } } } -- cgit v1.2.3 From d0a841b285fb398f0be72183ec3c9d1e358419a9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 12:02:43 -0800 Subject: altosui: Require 4 sats to light up the 'GPS locked' light. This tracks the same GPS signal requirement needed for 'GPS ready' and ensures that we have a 3d fix. Signed-off-by: Keith Packard --- altosui/AltosPad.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index 66954347..e345e5da 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -152,7 +152,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { class GPSLocked extends LaunchStatus { void show (AltosState state, int crc_errors) { value.setText(String.format("%4d sats", state.gps.nsat)); - lights.set(state.gps.locked); + lights.set(state.gps.locked && state.gps.nsat >= 4); } public GPSLocked (GridBagLayout layout, int y) { super (layout, y, "GPS Locked"); -- cgit v1.2.3 From 3566dee1cf83870396a0bb164f5549dd3faf58f5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Jan 2011 14:40:31 -0800 Subject: altosui: Remove spurious colons from eeprom selection headers This colons make the presentation a bit confusing. Signed-off-by: Keith Packard --- altosui/AltosEepromSelect.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index f0066aac..a3069f06 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -119,7 +119,7 @@ public class AltosEepromSelect extends JDialog implements ActionListener { c.weightx = 0.5; c.anchor = GridBagConstraints.CENTER; c.insets = i; - JLabel flightHeaderLabel = new JLabel("Flight:"); + JLabel flightHeaderLabel = new JLabel("Flight"); flightPane.add(flightHeaderLabel, c); /* Download Header */ @@ -129,7 +129,7 @@ public class AltosEepromSelect extends JDialog implements ActionListener { c.weightx = 0.5; c.anchor = GridBagConstraints.CENTER; c.insets = i; - JLabel downloadHeaderLabel = new JLabel("Download:"); + JLabel downloadHeaderLabel = new JLabel("Download"); flightPane.add(downloadHeaderLabel, c); /* Delete Header */ @@ -139,7 +139,7 @@ public class AltosEepromSelect extends JDialog implements ActionListener { c.weightx = 0.5; c.anchor = GridBagConstraints.CENTER; c.insets = i; - JLabel deleteHeaderLabel = new JLabel("Delete:"); + JLabel deleteHeaderLabel = new JLabel("Delete"); flightPane.add(deleteHeaderLabel, c); /* Add the flights to the GridBag */ -- cgit v1.2.3 From 5d91c250179f44ca17c26fff36718b7026aa8ee0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 18 Jan 2011 22:34:15 -0800 Subject: fat: Add firmware for v1.1 and docs to mac/windows/linux installers We'll need to be sure to update this each time we add a product. Signed-off-by: Keith Packard --- altosui/Makefile.am | 15 +++++++++++++-- altosui/altos-windows.nsi | 10 ++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 196d7032..52b173e2 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -129,10 +129,21 @@ ICONJAR= -C $(ICONDIR) altus-metrum-16x16.jpg \ WINDOWS_ICON=$(ICONDIR)/altus-metrum.ico # Firmware -FIRMWARE_TD=$(top_srcdir)/src/teledongle-v0.2-$(VERSION).ihx -FIRMWARE_TM=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx +FIRMWARE_TD_0_2=$(top_srcdir)/src/teledongle-v0.2-$(VERSION).ihx +FIRMWARE_TD=$(FIRMWARE_TD_0_2) + +FIRMWARE_TM_1_0=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx +FIRMWARE_TM_1_1=$(top_srcdir)/src/telemetrum-v1.1-$(VERSION).ihx +FIRMWARE_TM=$(FIRMWARE_TM_1_0) $(FIRMWARE_TM_1_1) + FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TD) +ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf +ALTOS_DOC=$(top_srcdir)/doc/altos.pdf +TEMPLATE_DOC=$(top_srcdir)/doc/telemetrum-outline.pdf + +DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TEMPLATE_DOC) + # Distribution targets LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2 MACOSX_DIST=Altos-Mac-$(VERSION).zip diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index 6f296f18..a1238095 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -80,10 +80,20 @@ Section "TeleMetrum and TeleDongle Firmware" SetOutPath $INSTDIR File "../src/telemetrum-v1.0/telemetrum-v1.0-${VERSION}.ihx" + File "../src/telemetrum-v1.1/telemetrum-v1.1-${VERSION}.ihx" File "../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx" SectionEnd +Section "Documentation" + + SetOutPath $INSTDIR + + File "../doc/altusmetrum.pdf" + File "../doc/altos.pdf" + File "../doc/telemetrum-outline.pdf" +SectionEnd + Section "Uninstaller" ; Deal with the uninstaller -- cgit v1.2.3 From 72a04d679d06aaad9c2b4297fefd585fc393ce2e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 18 Jan 2011 22:39:07 -0800 Subject: fat: Add docs to Linux package Oops. Missed this one. Signed-off-by: Keith Packard --- altosui/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 52b173e2..79394f6e 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -151,7 +151,7 @@ WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe FAT_FILES=$(FATJAR) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) -LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) +LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC) LINUX_EXTRA=altosui-fat MACOSX_FILES=$(FAT_FILES) libaltos.dylib -- cgit v1.2.3 From 7ca2cf1b7e03b8453b45b45e313a33ad65da9ad5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 19 Feb 2011 01:02:00 -0800 Subject: altosui: Mark empty eeprom records 'invalid', don't generate exception When reading empty eeprom records, mark them as 'invalid', but don't generate an exception as it's normal to read these at the end of the flight log. Signed-off-by: Keith Packard --- altosui/AltosEepromRecord.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index 584a04b7..e5196c50 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -72,15 +72,24 @@ public class AltosEepromRecord { if (values[0] != (addr & 0xff)) throw new ParseException(String.format("data address out of sync at 0x%x", addr), 0); - if (checksum(values) != 0) - throw new ParseException(String.format("invalid checksum at 0x%x", addr), 0); - + int i; + for (i = 1; i < values.length; i++) + if (values[i] != 0xff) + break; cmd = values[1]; + tick_valid = true; + if (i != values.length) { + if (checksum(values) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x in line %s", addr, line), 0); + } else { + cmd = Altos.AO_LOG_INVALID; + tick_valid = false; + } + tick = values[3] + (values[4] << 8); a = values[5] + (values[6] << 8); b = values[7] + (values[8] << 8); data = null; - tick_valid = true; } public AltosEepromRecord (String line) { -- cgit v1.2.3 From 629a7637871b24fe6d1204aaa7185d84933d4639 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 19 Feb 2011 01:04:19 -0800 Subject: altosui: Always read whole eeprom block, even at end of flight Instead of stopping early, continue reading the whole eeprom block so that the extra serial data doesn't end up confusing the next user of the serial line, which may well be reading the next flight. Signed-off-by: Keith Packard --- altosui/AltosEepromBlock.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromBlock.java b/altosui/AltosEepromBlock.java index f223f3fb..11438df8 100644 --- a/altosui/AltosEepromBlock.java +++ b/altosui/AltosEepromBlock.java @@ -56,7 +56,7 @@ public class AltosEepromBlock extends ArrayList { has_lon = false; has_time = false; serial_line.printf("e %x\n", block); - for (addr = 0; !done && addr < 0x100;) { + for (addr = 0; addr < 0x100;) { try { AltosEepromRecord r = new AltosEepromRecord(serial_line, block * 256 + addr); @@ -93,10 +93,15 @@ public class AltosEepromBlock extends ArrayList { lon = (double) (r.a | (r.b << 16)) / 1e7; has_lon = true; } + if (!done) + add(addr / 8, r); if (r.cmd == Altos.AO_LOG_STATE && r.a == Altos.ao_flight_landed) done = true; - add(addr / 8, r); } catch (ParseException pe) { + AltosEepromRecord r = new AltosEepromRecord(Altos.AO_LOG_INVALID, + 0, 0, 0); + if (!done) + add(addr/8, r); } addr += 8; } -- cgit v1.2.3 From 249cd3b63d97581b068fff988e0cd7fcd5bf493e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 19 Feb 2011 01:06:01 -0800 Subject: altosui: Display eeprom parsing errors to user When reading the eeprom, any parsing errors (most likely bad checksums) indicate some kind of problem with either the hardware or the flight software. Display these to the user and do not erase the flight. Signed-off-by: Keith Packard --- altosui/AltosEepromBlock.java | 3 +++ altosui/AltosEepromDownload.java | 51 +++++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 16 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromBlock.java b/altosui/AltosEepromBlock.java index 11438df8..d59fd39e 100644 --- a/altosui/AltosEepromBlock.java +++ b/altosui/AltosEepromBlock.java @@ -44,6 +44,7 @@ public class AltosEepromBlock extends ArrayList { double lon; boolean has_time; int hour, minute, second; + ParseException parse_exception = null; public AltosEepromBlock (AltosSerial serial_line, int block) throws TimeoutException, InterruptedException { int addr; @@ -100,6 +101,8 @@ public class AltosEepromBlock extends ArrayList { } catch (ParseException pe) { AltosEepromRecord r = new AltosEepromRecord(Altos.AO_LOG_INVALID, 0, 0, 0); + if (parse_exception == null) + parse_exception = pe; if (!done) add(addr/8, r); } diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index f1abd50c..1da94a67 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -47,6 +47,7 @@ public class AltosEepromDownload implements Runnable { AltosEepromList flights; ActionListener listener; boolean success; + ParseException parse_exception; private void FlushPending() throws IOException { for (String s : flights.config_data) { @@ -128,17 +129,22 @@ public class AltosEepromDownload implements Runnable { state = eeblock.state; } + if (parse_exception == null && eeblock.parse_exception != null) + parse_exception = eeblock.parse_exception; + CheckFile(false); for (record = 0; record < eeblock.size(); record++) { AltosEepromRecord r = eeblock.get(record); - String log_line = String.format("%c %4x %4x %4x\n", - r.cmd, r.tick, r.a, r.b); - if (eeprom_file != null) - eeprom_file.write(log_line); - else - eeprom_pending.add(log_line); + if (r.cmd != Altos.AO_LOG_INVALID) { + String log_line = String.format("%c %4x %4x %4x\n", + r.cmd, r.tick, r.a, r.b); + if (eeprom_file != null) + eeprom_file.write(log_line); + else + eeprom_pending.add(log_line); + } } } CheckFile(true); @@ -148,20 +154,21 @@ public class AltosEepromDownload implements Runnable { } } - private void show_error_internal(String message, String title) { + private void show_message_internal(String message, String title, int message_type) { JOptionPane.showMessageDialog(frame, message, title, - JOptionPane.ERROR_MESSAGE); + message_type); } - private void show_error(String in_message, String in_title) { + private void show_message(String in_message, String in_title, int in_message_type) { final String message = in_message; final String title = in_title; + final int message_type = in_message_type; Runnable r = new Runnable() { public void run() { try { - show_error_internal(message, title); + show_message_internal(message, title, message_type); } catch (Exception ex) { } } @@ -174,21 +181,33 @@ public class AltosEepromDownload implements Runnable { serial_line.start_remote(); try { + boolean failed = false; for (AltosEepromLog log : flights) { + parse_exception = null; if (log.download) { monitor.reset(); CaptureLog(log); } + if (parse_exception != null) { + failed = true; + show_message(String.format("Flight %d download error\n%s\nValid log data saved", + log.flight, + parse_exception.getMessage()), + serial_line.device.toShortString(), + JOptionPane.WARNING_MESSAGE); + } } - success = true; + success = !failed; } catch (IOException ee) { - show_error (serial_line.device.toShortString(), - ee.getLocalizedMessage()); + show_message(ee.getLocalizedMessage(), + serial_line.device.toShortString(), + JOptionPane.ERROR_MESSAGE); } catch (InterruptedException ie) { } catch (TimeoutException te) { - show_error (String.format("Connection to \"%s\" failed", - serial_line.device.toShortString()), - "Connection Failed"); + show_message(String.format("Connection to \"%s\" failed", + serial_line.device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); } if (remote) serial_line.stop_remote(); -- cgit v1.2.3 From 9f3d26cadf37880d2c9223f59271d295b11c4c2a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 16 Mar 2011 14:05:13 -0700 Subject: altosui: Missed jcommon.jar in the Mac OS install image This caused graphing to fail on Mac OS X Signed-off-by: Keith Packard --- altosui/Makefile.am | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 79394f6e..133afbe8 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -282,6 +282,7 @@ $(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar cp -p $(FREETTS_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java cp -p $(JFREECHART_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java + cp -p $(JCOMMON_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java cp -p $(MACOSX_EXTRA) macosx/AltOS cd macosx && zip -r ../$@ AltosUI.app AltOS -- cgit v1.2.3 From e980b251e5a4d25410710a9aa89ef940e06b0d93 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 19 Mar 2011 18:43:52 -0700 Subject: altosui: Add software version to Configure AltosUI dialog Show this somewhere so we can figure out what is installed. Signed-off-by: Keith Packard --- altosui/AltosConfigureUI.java | 27 +++++++++++++++++---------- altosui/AltosVersion.java.in | 22 ++++++++++++++++++++++ altosui/Makefile.am | 1 + configure.ac | 1 + 4 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 altosui/AltosVersion.java.in (limited to 'altosui') diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index ab3d950e..9a292c91 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -87,9 +87,16 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.CENTER; pane.add(new JLabel ("Configure AltOS UI"), c); - /* Voice settings */ c.gridx = 0; c.gridy = 1; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + pane.add(new JLabel (String.format("AltOS version %s", AltosVersion.version)), c); + + /* Voice settings */ + c.gridx = 0; + c.gridy = 2; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -108,7 +115,7 @@ public class AltosConfigureUI } }); c.gridx = 1; - c.gridy = 1; + c.gridy = 2; c.gridwidth = 1; c.weightx = 1; c.fill = GridBagConstraints.NONE; @@ -116,7 +123,7 @@ public class AltosConfigureUI pane.add(enable_voice, c); c.gridx = 2; - c.gridy = 1; + c.gridy = 2; c.gridwidth = 1; c.weightx = 1; c.fill = GridBagConstraints.NONE; @@ -131,7 +138,7 @@ public class AltosConfigureUI /* Log directory settings */ c.gridx = 0; - c.gridy = 2; + c.gridy = 3; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -145,7 +152,7 @@ public class AltosConfigureUI } }); c.gridx = 1; - c.gridy = 2; + c.gridy = 3; c.gridwidth = 2; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.WEST; @@ -153,7 +160,7 @@ public class AltosConfigureUI /* Callsign setting */ c.gridx = 0; - c.gridy = 3; + c.gridy = 4; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -162,7 +169,7 @@ public class AltosConfigureUI callsign_value = new JTextField(AltosPreferences.callsign()); callsign_value.getDocument().addDocumentListener(this); c.gridx = 1; - c.gridy = 3; + c.gridy = 4; c.gridwidth = 2; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.WEST; @@ -170,7 +177,7 @@ public class AltosConfigureUI /* Serial debug setting */ c.gridx = 0; - c.gridy = 4; + c.gridy = 5; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -186,7 +193,7 @@ public class AltosConfigureUI }); c.gridx = 1; - c.gridy = 4; + c.gridy = 5; c.gridwidth = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -200,7 +207,7 @@ public class AltosConfigureUI } }); c.gridx = 0; - c.gridy = 5; + c.gridy = 6; c.gridwidth = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; diff --git a/altosui/AltosVersion.java.in b/altosui/AltosVersion.java.in new file mode 100644 index 00000000..b0b3c0cf --- /dev/null +++ b/altosui/AltosVersion.java.in @@ -0,0 +1,22 @@ +/* + * 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 altosui; + +public class AltosVersion { + public final static String version = "@VERSION@"; +} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 133afbe8..288fca0e 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -85,6 +85,7 @@ altosui_JAVA = \ AltosGraphTime.java \ AltosGraphUI.java \ AltosDataChooser.java \ + AltosVersion.java \ AltosVoice.java JFREECHART_CLASS= \ diff --git a/configure.ac b/configure.ac index e27cf81f..83cf9987 100644 --- a/configure.ac +++ b/configure.ac @@ -134,6 +134,7 @@ PKG_CHECK_MODULES([SNDFILE], [sndfile]) AC_OUTPUT([ Makefile altosui/Makefile +altosui/AltosVersion.java altosui/libaltos/Makefile ao-tools/Makefile ao-tools/lib/Makefile -- cgit v1.2.3 From f3e68341f6f5daaf26dd162e4f9a06c29988986a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 24 Mar 2011 05:27:57 +0900 Subject: altosui: Add support for telemetry version 4 New telemetry format needed to support TeleNano and TeleMini Signed-off-by: Keith Packard --- altosui/AltosAscent.java | 21 ++- altosui/AltosCSV.java | 29 ++-- altosui/AltosDataPointReader.java | 2 + altosui/AltosDescent.java | 57 +++++++- altosui/AltosFlightUI.java | 23 +++- altosui/AltosGPS.java | 47 ++++++- altosui/AltosLanded.java | 31 ++++- altosui/AltosPad.java | 41 +++++- altosui/AltosRecord.java | 83 +++++++++-- altosui/AltosSiteMap.java | 2 - altosui/AltosState.java | 15 +- altosui/AltosTelemetry.java | 267 +++++++++++++++++++++++++++++++++--- altosui/AltosTelemetryIterable.java | 1 - altosui/AltosUI.java | 2 +- altosui/Makefile.am | 1 + src/ao_telem.h | 8 +- 16 files changed, 550 insertions(+), 80 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index 64bdcf30..0fbc5de2 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -87,6 +87,16 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { void reset() { value.setText(""); } + + void show() { + label.show(); + value.show(); + } + + void hide() { + label.hide(); + value.hide(); + } public AscentValue (GridBagLayout layout, int y, String text) { GridBagConstraints c = new GridBagConstraints(); c.weighty = 1; @@ -247,6 +257,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { class Lat extends AscentValue { void show (AltosState state, int crc_errors) { + show(); if (state.gps != null) value.setText(pos(state.gps.lat,"N", "S")); else @@ -261,6 +272,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { class Lon extends AscentValue { void show (AltosState state, int crc_errors) { + show(); if (state.gps != null) value.setText(pos(state.gps.lon,"E", "W")); else @@ -284,8 +296,13 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { } public void show(AltosState state, int crc_errors) { - lat.show(state, crc_errors); - lon.show(state, crc_errors); + if (state.gps != null) { + lat.show(state, crc_errors); + lon.show(state, crc_errors); + } else { + lat.hide(); + lon.hide(); + } height.show(state, crc_errors); main.show(state, crc_errors); apogee.show(state, crc_errors); diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index df98b2b4..5277c160 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -60,7 +60,7 @@ public class AltosCSV implements AltosWriter { * drogue (V) * main (V) * - * GPS data + * GPS data (if available) * connected (1/0) * locked (1/0) * nsat (used for solution) @@ -179,12 +179,14 @@ public class AltosCSV implements AltosWriter { } } - void write_header() { + void write_header(boolean gps) { out.printf("#"); write_general_header(); out.printf(","); write_flight_header(); out.printf(","); write_basic_header(); - out.printf(","); write_gps_header(); - out.printf(","); write_gps_sat_header(); + if (gps) { + out.printf(","); write_gps_header(); + out.printf(","); write_gps_sat_header(); + } out.printf ("\n"); } @@ -192,9 +194,12 @@ public class AltosCSV implements AltosWriter { state = new AltosState(record, state); write_general(record); out.printf(","); write_flight(record); out.printf(","); - write_basic(record); out.printf(","); - write_gps(record); out.printf(","); - write_gps_sat(record); + write_basic(record); + if (record.gps != null) { + out.printf(","); + write_gps(record); out.printf(","); + write_gps_sat(record); + } out.printf ("\n"); } @@ -206,7 +211,7 @@ public class AltosCSV implements AltosWriter { public void write(AltosRecord record) { if (!header_written) { - write_header(); + write_header(record.gps != null); header_written = true; } if (!seen_boost) { @@ -240,12 +245,16 @@ public class AltosCSV implements AltosWriter { write(r); } - public AltosCSV(File in_name) throws FileNotFoundException { + public AltosCSV(PrintStream in_out, File in_name) { name = in_name; - out = new PrintStream(name); + out = in_out; pad_records = new LinkedList(); } + public AltosCSV(File in_name) throws FileNotFoundException { + this(new PrintStream(in_name), in_name); + } + public AltosCSV(String in_string) throws FileNotFoundException { this(new File(in_string)); } diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index 7704310b..ee57d2ce 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -15,6 +15,8 @@ class AltosDataPointReader implements Iterable { AltosState state; AltosRecord record; + final static int MISSING = AltosRecord.MISSING; + public AltosDataPointReader(Iterable reader) { this.iter = reader.iterator(); this.state = null; diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 16ccd458..594a7a09 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -37,6 +37,19 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { AltosLights lights; abstract void show(AltosState state, int crc_errors); + + void show() { + label.show(); + value.show(); + lights.show(); + } + + void hide() { + label.hide(); + value.hide(); + lights.hide(); + } + void reset() { value.setText(""); lights.set(false); @@ -90,6 +103,16 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { abstract void show(AltosState state, int crc_errors); + void show() { + label.show(); + value.show(); + } + + void hide() { + label.hide(); + value.hide(); + } + void show(String format, double v) { value.setText(String.format(format, v)); } @@ -134,12 +157,27 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { value2.setText(""); } + void show() { + label.show(); + value1.show(); + value2.show(); + } + + void hide() { + label.hide(); + value1.hide(); + value2.hide(); + } + abstract void show(AltosState state, int crc_errors); + void show(String v1, String v2) { + show(); value1.setText(v1); value2.setText(v2); } void show(String f1, double v1, String f2, double v2) { + show(); value1.setText(String.format(f1, v1)); value2.setText(String.format(f2, v2)); } @@ -260,6 +298,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { class Main extends DescentStatus { void show (AltosState state, int crc_errors) { + show(); value.setText(String.format("%4.2f V", state.main_sense)); lights.set(state.main_sense > 3.2); } @@ -324,11 +363,19 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { public void show(AltosState state, int crc_errors) { height.show(state, crc_errors); speed.show(state, crc_errors); - bearing.show(state, crc_errors); - range.show(state, crc_errors); - elevation.show(state, crc_errors); - lat.show(state, crc_errors); - lon.show(state, crc_errors); + if (state.gps != null) { + bearing.show(state, crc_errors); + range.show(state, crc_errors); + elevation.show(state, crc_errors); + lat.show(state, crc_errors); + lon.show(state, crc_errors); + } else { + bearing.hide(); + range.hide(); + elevation.hide(); + lat.hide(); + lon.hide(); + } main.show(state, crc_errors); apogee.show(state, crc_errors); } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 7fcfb8be..68e0ef87 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -29,9 +29,6 @@ import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; public class AltosFlightUI extends JFrame implements AltosFlightDisplay { - String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" }; - Object[][] statusData = { { "0", "pad", "-50", "0" } }; - AltosVoice voice; AltosFlightReader reader; AltosDisplayThread thread; @@ -43,6 +40,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { AltosDescent descent; AltosLanded landed; AltosSiteMap sitemap; + boolean has_map; private AltosFlightStatus flightStatus; private AltosInfoTable flightInfo; @@ -85,6 +83,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { public void show(AltosState state, int crc_errors) { JComponent tab = which_tab(state); + try { pad.show(state, crc_errors); ascent.show(state, crc_errors); descent.show(state, crc_errors); @@ -97,7 +96,21 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { } flightStatus.show(state, crc_errors); flightInfo.show(state, crc_errors); - sitemap.show(state, crc_errors); + if (state.gps != null) { + if (!has_map) { + pane.add("Site Map", sitemap); + has_map = true; + } + sitemap.show(state, crc_errors); + } else { + if (has_map) { + pane.remove(sitemap); + has_map = false; + } + } + } catch (Exception e) { + System.out.print("Show exception" + e); + } } public void set_exit_on_close() { @@ -169,7 +182,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { pane.add("Table", new JScrollPane(flightInfo)); sitemap = new AltosSiteMap(); - pane.add("Site Map", sitemap); + has_map = false; /* Make the tabbed pane use the rest of the window space */ c.gridx = 0; diff --git a/altosui/AltosGPS.java b/altosui/AltosGPS.java index 83821842..0dbc8364 100644 --- a/altosui/AltosGPS.java +++ b/altosui/AltosGPS.java @@ -26,10 +26,11 @@ public class AltosGPS { int c_n0; } + final static int MISSING = AltosRecord.MISSING; + int nsat; boolean locked; boolean connected; - boolean date_valid; double lat; /* degrees (+N -S) */ double lon; /* degrees (+E -W) */ int alt; /* m */ @@ -40,11 +41,11 @@ public class AltosGPS { int minute; int second; - int gps_extended; /* has extra data */ double ground_speed; /* m/s */ int course; /* degrees */ double climb_rate; /* m/s */ - double hdop; /* unitless? */ + double hdop; /* unitless */ + double vdop; /* unitless */ int h_error; /* m */ int v_error; /* m */ @@ -73,6 +74,44 @@ public class AltosGPS { hour = minute = second = 0; } + public AltosGPS(AltosTelemetryMap map) throws ParseException { + String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, + AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); + + nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0); + if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) { + connected = true; + locked = true; + lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); + lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); + alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING); + year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING); + if (year != MISSING) + year += 2000; + month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING); + day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING); + + hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0); + minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0); + second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0); + + ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, + AltosRecord.MISSING, 1/100.0); + course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, + AltosRecord.MISSING); + hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0); + vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0); + h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING); + v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING); + } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) { + connected = true; + locked = false; + } else { + connected = false; + locked = false; + } + } + public AltosGPS(String[] words, int i, int version) throws ParseException { AltosParse.word(words[i++], "GPS"); nsat = AltosParse.parse_int(words[i++]); @@ -184,7 +223,6 @@ public class AltosGPS { nsat = old.nsat; locked = old.locked; connected = old.connected; - date_valid = old.date_valid; lat = old.lat; /* degrees (+N -S) */ lon = old.lon; /* degrees (+E -W) */ alt = old.alt; /* m */ @@ -195,7 +233,6 @@ public class AltosGPS { minute = old.minute; second = old.second; - gps_extended = old.gps_extended; /* has extra data */ ground_speed = old.ground_speed; /* m/s */ course = old.course; /* degrees */ climb_rate = old.climb_rate; /* m/s */ diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index d34efe6d..0717ffe2 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -42,10 +42,22 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { value.setText(""); } + void show() { + label.show(); + value.show(); + } + + void hide() { + label.hide(); + value.hide(); + } + void show(String format, double v) { + show(); value.setText(String.format(format, v)); } + public LandedValue (GridBagLayout layout, int y, String text) { GridBagConstraints c = new GridBagConstraints(); c.weighty = 1; @@ -86,6 +98,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { class Lat extends LandedValue { void show (AltosState state, int crc_errors) { + show(); if (state.gps != null) value.setText(pos(state.gps.lat,"N", "S")); else @@ -100,6 +113,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { class Lon extends LandedValue { void show (AltosState state, int crc_errors) { + show(); if (state.gps != null) value.setText(pos(state.gps.lon,"E", "W")); else @@ -114,6 +128,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { class Bearing extends LandedValue { void show (AltosState state, int crc_errors) { + show(); if (state.from_pad != null) show("%3.0f°", state.from_pad.bearing); else @@ -128,6 +143,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { class Distance extends LandedValue { void show (AltosState state, int crc_errors) { + show(); if (state.from_pad != null) show("%6.0f m", state.from_pad.distance); else @@ -184,10 +200,17 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { } public void show(AltosState state, int crc_errors) { - bearing.show(state, crc_errors); - distance.show(state, crc_errors); - lat.show(state, crc_errors); - lon.show(state, crc_errors); + if (state.gps != null) { + bearing.show(state, crc_errors); + distance.show(state, crc_errors); + lat.show(state, crc_errors); + lon.show(state, crc_errors); + } else { + bearing.hide(); + distance.hide(); + lat.hide(); + lon.hide(); + } height.show(state, crc_errors); speed.show(state, crc_errors); accel.show(state, crc_errors); diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index e345e5da..2f59e879 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -42,6 +42,18 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { lights.set(false); } + public void show() { + label.show(); + value.show(); + lights.show(); + } + + public void hide() { + label.hide(); + value.hide(); + lights.hide(); + } + public LaunchStatus (GridBagLayout layout, int y, String text) { GridBagConstraints c = new GridBagConstraints(); c.weighty = 1; @@ -83,6 +95,16 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { JTextField value; void show(AltosState state, int crc_errors) {} + void show() { + label.show(); + value.show(); + } + + void hide() { + label.hide(); + value.hide(); + } + void reset() { value.setText(""); } @@ -151,6 +173,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { class GPSLocked extends LaunchStatus { void show (AltosState state, int crc_errors) { + show(); value.setText(String.format("%4d sats", state.gps.nsat)); lights.set(state.gps.locked && state.gps.nsat >= 4); } @@ -163,6 +186,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { class GPSReady extends LaunchStatus { void show (AltosState state, int crc_errors) { + show(); if (state.gps_ready) value.setText("Ready"); else @@ -189,6 +213,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { class PadLat extends LaunchValue { void show (AltosState state, int crc_errors) { + show(); value.setText(pos(state.pad_lat,"N", "S")); } public PadLat (GridBagLayout layout, int y) { @@ -200,6 +225,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { class PadLon extends LaunchValue { void show (AltosState state, int crc_errors) { + show(); value.setText(pos(state.pad_lon,"E", "W")); } public PadLon (GridBagLayout layout, int y) { @@ -235,11 +261,18 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { battery.show(state, crc_errors); apogee.show(state, crc_errors); main.show(state, crc_errors); - gps_locked.show(state, crc_errors); - gps_ready.show(state, crc_errors); - pad_lat.show(state, crc_errors); - pad_lon.show(state, crc_errors); pad_alt.show(state, crc_errors); + if (state.gps != null) { + gps_locked.show(state, crc_errors); + gps_ready.show(state, crc_errors); + pad_lat.show(state, crc_errors); + pad_lon.show(state, crc_errors); + } else { + gps_locked.hide(); + gps_ready.hide(); + pad_lat.hide(); + pad_lon.hide(); + } } public AltosPad() { diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index 1160a273..46e96b95 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -23,6 +23,8 @@ import java.util.HashMap; import java.io.*; public class AltosRecord { + final static int MISSING = 0x7fffffff; + int version; String callsign; int serial; @@ -31,19 +33,27 @@ public class AltosRecord { int status; int state; int tick; + int accel; int pres; int temp; int batt; int drogue; int main; - int flight_accel; + int ground_accel; - int flight_vel; - int flight_pres; int ground_pres; int accel_plus_g; int accel_minus_g; + + double acceleration; + double speed; + double height; + + int flight_accel; + int flight_vel; + int flight_pres; + AltosGPS gps; double time; /* seconds since boost */ @@ -72,46 +82,82 @@ public class AltosRecord { } public double raw_pressure() { + if (pres == MISSING) + return MISSING; return barometer_to_pressure(pres); } public double filtered_pressure() { + if (flight_pres == MISSING) + return MISSING; return barometer_to_pressure(flight_pres); } public double ground_pressure() { + if (ground_pres == MISSING) + return MISSING; return barometer_to_pressure(ground_pres); } - public double filtered_altitude() { - return AltosConvert.pressure_to_altitude(filtered_pressure()); - } - public double raw_altitude() { - return AltosConvert.pressure_to_altitude(raw_pressure()); + double p = raw_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); } public double ground_altitude() { - return AltosConvert.pressure_to_altitude(ground_pressure()); + double p = ground_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double filtered_altitude() { + if (height != MISSING && ground_pres != MISSING) + return height + ground_altitude(); + + double p = filtered_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); } public double filtered_height() { - return filtered_altitude() - ground_altitude(); + if (height != MISSING) + return height; + + double f = filtered_altitude(); + double g = ground_altitude(); + if (f == MISSING || g == MISSING) + return MISSING; + return f - g; } public double raw_height() { - return raw_altitude() - ground_altitude(); + double r = raw_altitude(); + double g = ground_altitude(); + + if (r == MISSING || g == MISSING) + return MISSING; + return r - g; } public double battery_voltage() { + if (batt == MISSING) + return MISSING; return AltosConvert.cc_battery_to_voltage(batt); } public double main_voltage() { + if (main == MISSING) + return MISSING; return AltosConvert.cc_ignitor_to_voltage(main); } public double drogue_voltage() { + if (drogue == MISSING) + return MISSING; return AltosConvert.cc_ignitor_to_voltage(drogue); } @@ -131,6 +177,8 @@ public class AltosRecord { } public double temperature() { + if (temp == MISSING) + return MISSING; return thermometer_to_temperature(temp); } @@ -139,13 +187,22 @@ public class AltosRecord { return counts_per_g / 9.80665; } + public double acceleration() { + if (acceleration != MISSING) + return acceleration; + + if (ground_accel == MISSING || accel == MISSING) + return MISSING; return (ground_accel - accel) / accel_counts_per_mss(); } public double accel_speed() { - double speed = flight_vel / (accel_counts_per_mss() * 100.0); - return speed; + if (speed != MISSING) + return speed; + if (flight_vel == MISSING) + return MISSING; + return flight_vel / (accel_counts_per_mss() * 100.0); } public String state() { diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index d6bd6d1f..f4b6b7e0 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -228,8 +228,6 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { int last_state = -1; public void show(final AltosState state, final int crc_errors) { // if insufficient gps data, nothing to update - if (state.gps == null) - return; if (!state.gps.locked && state.gps.nsat < 4) return; diff --git a/altosui/AltosState.java b/altosui/AltosState.java index ec499d5a..4e165f80 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -79,7 +79,8 @@ public class AltosState { data = cur; ground_altitude = data.ground_altitude(); - height = data.filtered_altitude() - ground_altitude; + height = data.filtered_height(); + System.out.printf("height %g\n", height); report_time = System.currentTimeMillis(); @@ -114,10 +115,14 @@ public class AltosState { /* compute barometric speed */ double height_change = height - prev_state.height; - if (time_change > 0) - baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; - else - baro_speed = prev_state.baro_speed; + if (data.speed != AltosRecord.MISSING) + baro_speed = data.speed; + else { + if (time_change > 0) + baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; + else + baro_speed = prev_state.baro_speed; + } } else { npad = 0; ngps = 0; diff --git a/altosui/AltosTelemetry.java b/altosui/AltosTelemetry.java index bdb6466a..3eb0efa8 100644 --- a/altosui/AltosTelemetry.java +++ b/altosui/AltosTelemetry.java @@ -27,10 +27,40 @@ import java.util.HashMap; /* - * The telemetry data stream is a bit of a mess at present, with no consistent - * formatting. In particular, the GPS data is formatted for viewing instead of parsing. - * However, the key feature is that every telemetry line contains all of the information - * necessary to describe the current rocket state, including the calibration values + * Version 4 is a replacement with consistent syntax. Each telemetry line + * contains a sequence of space-separated names and values, the values are + * either integers or strings. The names are all unique. All values are + * optional + * + * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 + * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 + * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 + * + * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 + * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 + * + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + * + * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports + * in 1/2dB increments while this protocol provides only integers. So, + * the syntax didn't change just the interpretation of the RSSI + * values. + * + * Version 2 of the telemetry data stream is a bit of a mess, with no + * consistent formatting. In particular, the GPS data is formatted for + * viewing instead of parsing. However, the key feature is that every + * telemetry line contains all of the information necessary to + * describe the current rocket state, including the calibration values * for accelerometer and barometer. * * GPS unlocked: @@ -47,25 +77,201 @@ import java.util.HashMap; * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 + * */ public class AltosTelemetry extends AltosRecord { - public AltosTelemetry(String line) throws ParseException, AltosCRCException { - String[] words = line.split("\\s+"); - int i = 0; + /* + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + */ - if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(words[i++], "RSSI"); - rssi = AltosParse.parse_int(words[i++]); - throw new AltosCRCException(rssi); - } - if (words[i].equals("CALL")) { - version = 0; - } else { - AltosParse.word (words[i++], "VERSION"); - version = AltosParse.parse_int(words[i++]); - } + final static String AO_TELEM_VERSION = "VERSION"; + final static String AO_TELEM_CALL = "c"; + final static String AO_TELEM_SERIAL = "n"; + final static String AO_TELEM_FLIGHT = "f"; + final static String AO_TELEM_RSSI = "r"; + final static String AO_TELEM_STATE = "s"; + final static String AO_TELEM_TICK = "t"; + + /* + * Raw sensor values + * + * Name Value + * r_a Accelerometer reading (integer) + * r_b Barometer reading (integer) + * r_t Thermometer reading (integer) + * r_v Battery reading (integer) + * r_d Drogue continuity (integer) + * r_m Main continuity (integer) + */ + + final static String AO_TELEM_RAW_ACCEL = "r_a"; + final static String AO_TELEM_RAW_BARO = "r_b"; + final static String AO_TELEM_RAW_THERMO = "r_t"; + final static String AO_TELEM_RAW_BATT = "r_v"; + final static String AO_TELEM_RAW_DROGUE = "r_d"; + final static String AO_TELEM_RAW_MAIN = "r_m"; + + /* + * Sensor calibration values + * + * Name Value + * c_a Ground accelerometer reading (integer) + * c_b Ground barometer reading (integer) + * c_p Accelerometer reading for +1g + * c_m Accelerometer reading for -1g + */ + + final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; + final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; + final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; + final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; + + /* + * Kalman state values + * + * Name Value + * k_h Height above pad (integer, meters) + * k_s Vertical speeed (integer, m/s * 16) + * k_a Vertical acceleration (integer, m/s² * 16) + */ + + final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; + final static String AO_TELEM_KALMAN_SPEED = "k_s"; + final static String AO_TELEM_KALMAN_ACCEL = "k_a"; + + /* + * Ad-hoc flight values + * + * Name Value + * a_a Acceleration (integer, sensor units) + * a_s Speed (integer, integrated acceleration value) + * a_b Barometer reading (integer, sensor units) + */ + + final static String AO_TELEM_ADHOC_ACCEL = "a_a"; + final static String AO_TELEM_ADHOC_SPEED = "a_s"; + final static String AO_TELEM_ADHOC_BARO = "a_b"; + + /* + * GPS values + * + * Name Value + * g_s GPS state (string): + * l locked + * u unlocked + * e error (missing or broken) + * g_n Number of sats used in solution + * g_ns Latitude (degrees * 10e7) + * g_ew Longitude (degrees * 10e7) + * g_a Altitude (integer meters) + * g_Y GPS year (integer) + * g_M GPS month (integer - 1-12) + * g_D GPS day (integer - 1-31) + * g_h GPS hour (integer - 0-23) + * g_m GPS minute (integer - 0-59) + * g_s GPS second (integer - 0-59) + * g_v GPS vertical speed (integer, cm/sec) + * g_s GPS horizontal speed (integer, cm/sec) + * g_c GPS course (integer, 0-359) + * g_hd GPS hdop (integer * 10) + * g_vd GPS vdop (integer * 10) + * g_he GPS h error (integer) + * g_ve GPS v error (integer) + */ + + final static String AO_TELEM_GPS_STATE = "g"; + final static String AO_TELEM_GPS_STATE_LOCKED = "l"; + final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; + final static String AO_TELEM_GPS_STATE_ERROR = "e"; + final static String AO_TELEM_GPS_NUM_SAT = "g_n"; + final static String AO_TELEM_GPS_LATITUDE = "g_ns"; + final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; + final static String AO_TELEM_GPS_ALTITUDE = "g_a"; + final static String AO_TELEM_GPS_YEAR = "g_Y"; + final static String AO_TELEM_GPS_MONTH = "g_M"; + final static String AO_TELEM_GPS_DAY = "g_D"; + final static String AO_TELEM_GPS_HOUR = "g_h"; + final static String AO_TELEM_GPS_MINUTE = "g_m"; + final static String AO_TELEM_GPS_SECOND = "g_s"; + final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; + final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; + final static String AO_TELEM_GPS_COURSE = "g_c"; + final static String AO_TELEM_GPS_HDOP = "g_hd"; + final static String AO_TELEM_GPS_VDOP = "g_vd"; + final static String AO_TELEM_GPS_HERROR = "g_he"; + final static String AO_TELEM_GPS_VERROR = "g_ve"; + + /* + * GPS satellite values + * + * Name Value + * s_n Number of satellites reported (integer) + * s_v0 Space vehicle ID (integer) for report 0 + * s_c0 C/N0 number (integer) for report 0 + * s_v1 Space vehicle ID (integer) for report 1 + * s_c1 C/N0 number (integer) for report 1 + * ... + */ + + final static String AO_TELEM_SAT_NUM = "s_n"; + final static String AO_TELEM_SAT_SVID = "s_v"; + final static String AO_TELEM_SAT_C_N_0 = "s_c"; + + private void parse_v4(String[] words, int i) throws ParseException { + AltosTelemetryMap map = new AltosTelemetryMap(words, i); + + callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); + serial = map.get_int(AO_TELEM_SERIAL, MISSING); + flight = map.get_int(AO_TELEM_FLIGHT, MISSING); + rssi = map.get_int(AO_TELEM_RSSI, MISSING); + state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + tick = map.get_int(AO_TELEM_TICK, 0); + + /* raw sensor values */ + accel = map.get_int(AO_TELEM_RAW_ACCEL, MISSING); + pres = map.get_int(AO_TELEM_RAW_BARO, MISSING); + temp = map.get_int(AO_TELEM_RAW_THERMO, MISSING); + batt = map.get_int(AO_TELEM_RAW_BATT, MISSING); + drogue = map.get_int(AO_TELEM_RAW_DROGUE, MISSING); + main = map.get_int(AO_TELEM_RAW_MAIN, MISSING); + + /* sensor calibration information */ + ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, MISSING); + ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, MISSING); + accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, MISSING); + accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, MISSING); + + /* flight computer values */ + acceleration = map.get_int(AO_TELEM_KALMAN_ACCEL, MISSING); + if (acceleration != MISSING) + acceleration /= 16.0; + speed = map.get_int(AO_TELEM_KALMAN_SPEED, MISSING); + if (speed != MISSING) + speed /= 16.0; + height = map.get_int(AO_TELEM_KALMAN_HEIGHT, MISSING); + + flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, MISSING); + flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, MISSING); + flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, MISSING); + + if (map.has(AO_TELEM_GPS_STATE)) + gps = new AltosGPS(map); + else + gps = null; + } + + private void parse_legacy(String[] words, int i) throws ParseException { AltosParse.word (words[i++], "CALL"); callsign = words[i++]; @@ -140,4 +346,27 @@ public class AltosTelemetry extends AltosRecord { gps = new AltosGPS(words, i, version); } + + public AltosTelemetry(String line) throws ParseException, AltosCRCException { + String[] words = line.split("\\s+"); + int i = 0; + + if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(words[i++], "RSSI"); + rssi = AltosParse.parse_int(words[i++]); + throw new AltosCRCException(rssi); + } + if (words[i].equals("CALL")) { + version = 0; + } else { + AltosParse.word (words[i++], "VERSION"); + version = AltosParse.parse_int(words[i++]); + } + + if (version < 4) + parse_legacy(words, i); + else + parse_v4(words, i); + } } diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java index a71ab872..14b5f27f 100644 --- a/altosui/AltosTelemetryIterable.java +++ b/altosui/AltosTelemetryIterable.java @@ -63,7 +63,6 @@ public class AltosTelemetryIterable extends AltosRecordIterable { } catch (ParseException pe) { System.out.printf("parse exception %s\n", pe.getMessage()); } catch (AltosCRCException ce) { - System.out.printf("crc error\n"); } } } catch (IOException io) { diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 90e3d7f0..4d17b0d2 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -328,7 +328,7 @@ public class AltosUI extends JFrame { if (input.equals(output)) { System.out.printf("Not processing '%s'\n", input); } else { - AltosWriter writer = open_csv(output); + AltosWriter writer = open_csv("/dev/stdout"); if (writer != null) { writer.write(iterable); writer.close(); diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 288fca0e..49f34ce3 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -65,6 +65,7 @@ altosui_JAVA = \ AltosRecord.java \ AltosRecordIterable.java \ AltosTelemetryReader.java \ + AltosTelemetryMap.java \ AltosReplayReader.java \ AltosRomconfig.java \ AltosRomconfigUI.java \ diff --git a/src/ao_telem.h b/src/ao_telem.h index b1624fe0..1a8da291 100644 --- a/src/ao_telem.h +++ b/src/ao_telem.h @@ -108,7 +108,7 @@ * GPS values * * Name Value - * g_s GPS state (string): + * g GPS state (string): * l locked * u unlocked * e error (missing or broken) @@ -123,7 +123,7 @@ * g_m GPS minute (integer - 0-59) * g_s GPS second (integer - 0-59) * g_v GPS vertical speed (integer, cm/sec) - * g_s GPS horizontal speed (integer, cm/sec) + * g_g GPS horizontal speed (integer, cm/sec) * g_c GPS course (integer, 0-359) * g_hd GPS hdop (integer * 10) * g_vd GPS vdop (integer * 10) @@ -131,7 +131,7 @@ * g_ve GPS v error (integer) */ -#define AO_TELEM_GPS_STATE "g_s" +#define AO_TELEM_GPS_STATE "g" #define AO_TELEM_GPS_STATE_LOCKED 'l' #define AO_TELEM_GPS_STATE_UNLOCKED 'u' #define AO_TELEM_GPS_STATE_ERROR 'e' @@ -146,7 +146,7 @@ #define AO_TELEM_GPS_MINUTE "g_m" #define AO_TELEM_GPS_SECOND "g_s" #define AO_TELEM_GPS_VERTICAL_SPEED "g_v" -#define AO_TELEM_GPS_HORIZONTAL_SPEED "g_s" +#define AO_TELEM_GPS_HORIZONTAL_SPEED "g_g" #define AO_TELEM_GPS_COURSE "g_c" #define AO_TELEM_GPS_HDOP "g_hd" #define AO_TELEM_GPS_VDOP "g_vd" -- cgit v1.2.3 From 7f5b5848ad6ef5c808638a29c3dc0101b56ed11e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 24 Mar 2011 08:08:43 +0900 Subject: altosui: Add telemetry format menu and preferences Switches the TeleDongle between full and tiny telemetry packet formats, saving the last used format for each teledongle in the application preferences. Signed-off-by: Keith Packard --- altosui/Altos.java | 5 +++++ altosui/AltosFlightReader.java | 2 ++ altosui/AltosFlightUI.java | 24 ++++++++++++++++++++++++ altosui/AltosPreferences.java | 25 +++++++++++++++++++++++++ altosui/AltosSerial.java | 23 +++++++++++++++++++---- altosui/AltosState.java | 1 - altosui/AltosTelemetry.java | 8 ++------ altosui/AltosTelemetryReader.java | 5 +++++ 8 files changed, 82 insertions(+), 11 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 8ee94e04..9d5b2e02 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -63,6 +63,11 @@ public class Altos { static final int ao_flight_landed = 8; static final int ao_flight_invalid = 9; + /* Telemetry modes */ + static final int ao_telemetry_off = 0; + static final int ao_telemetry_full = 1; + static final int ao_telemetry_tiny = 2; + static HashMap string_to_state = new HashMap(); static boolean map_initialized = false; diff --git a/altosui/AltosFlightReader.java b/altosui/AltosFlightReader.java index 3d59de9a..f665bda8 100644 --- a/altosui/AltosFlightReader.java +++ b/altosui/AltosFlightReader.java @@ -34,5 +34,7 @@ public class AltosFlightReader { void set_channel(int channel) { } + void set_telemetry(int telemetry) { } + void update(AltosState state) throws InterruptedException { } } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 68e0ef87..286b2a4e 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -119,6 +119,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { Container bag; JComboBox channels; + JComboBox telemetries; public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) { AltosPreferences.init(this); @@ -149,8 +150,28 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { }); c.gridx = 0; c.gridy = 0; + c.insets = new Insets(3, 3, 3, 3); c.anchor = GridBagConstraints.WEST; bag.add (channels, c); + + // Telemetry format menu + telemetries = new JComboBox(); + telemetries.addItem("TeleMetrum"); + telemetries.addItem("TeleMini/TeleNano"); + telemetries.setSelectedIndex(AltosPreferences.telemetry(serial) - 1); + telemetries.setMaximumRowCount(2); + telemetries.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int telemetry = telemetries.getSelectedIndex(); + reader.set_telemetry(telemetry); + } + }); + c.gridx = 1; + c.gridy = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + bag.add (telemetries, c); + c.insets = new Insets(0, 0, 0, 0); } /* Flight status is always visible */ @@ -159,7 +180,9 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { c.gridy = 1; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; + c.gridwidth = 2; bag.add(flightStatus, c); + c.gridwidth = 1; /* The rest of the window uses a tabbed pane to * show one of the alternate data views @@ -190,6 +213,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { c.fill = GridBagConstraints.BOTH; c.weightx = 1; c.weighty = 1; + c.gridwidth = 2; bag.add(pane, c); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index d4df4e16..5f827655 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -34,6 +34,9 @@ class AltosPreferences { /* channel preference name */ final static String channelPreferenceFormat = "CHANNEL-%d"; + /* telemetry format preference name */ + final static String telemetryPreferenceFormat = "TELEMETRY-%d"; + /* voice preference name */ final static String voicePreference = "VOICE"; @@ -61,6 +64,9 @@ class AltosPreferences { /* Channel (map serial to channel) */ static Hashtable channels; + /* Telemetry (map serial to telemetry format) */ + static Hashtable telemetries; + /* Voice preference */ static boolean voice; @@ -94,6 +100,8 @@ class AltosPreferences { channels = new Hashtable(); + telemetries = new Hashtable(); + voice = preferences.getBoolean(voicePreference, true); callsign = preferences.get(callsignPreference,"N0CALL"); @@ -189,6 +197,23 @@ class AltosPreferences { return channel; } + public static void set_telemetry(int serial, int new_telemetry) { + telemetries.put(serial, new_telemetry); + synchronized (preferences) { + preferences.putInt(String.format(telemetryPreferenceFormat, serial), new_telemetry); + flush_preferences(); + } + } + + public static int telemetry(int serial) { + if (telemetries.containsKey(serial)) + return telemetries.get(serial); + int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), + Altos.ao_telemetry_full); + telemetries.put(serial, telemetry); + return telemetry; + } + public static void set_voice(boolean new_voice) { voice = new_voice; synchronized (preferences) { diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index f9f9e6e4..a8ba66bd 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -47,6 +47,8 @@ public class AltosSerial implements Runnable { byte[] line_bytes; int line_count; boolean monitor_mode; + int telemetry; + int channel; static boolean debug; boolean remote; LinkedList pending_output = new LinkedList(); @@ -231,25 +233,37 @@ public class AltosSerial implements Runnable { } public void set_radio() { - set_channel(AltosPreferences.channel(device.getSerial())); + telemetry = AltosPreferences.telemetry(device.getSerial()); + channel = AltosPreferences.channel(device.getSerial()); + set_channel(channel); set_callsign(AltosPreferences.callsign()); } - public void set_channel(int channel) { + public void set_channel(int in_channel) { + channel = in_channel; if (altos != null) { if (monitor_mode) - printf("m 0\nc r %d\nm 1\n", channel); + printf("m 0\nc r %d\nm %d\n", channel, telemetry); else printf("c r %d\n", channel); flush_output(); } } + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + if (altos != null) { + if (monitor_mode) + printf("m 0\nm %d\n", telemetry); + flush_output(); + } + } + void set_monitor(boolean monitor) { monitor_mode = monitor; if (altos != null) { if (monitor) - printf("m 1\n"); + printf("m %d\n", telemetry); else printf("m 0\n"); flush_output(); @@ -285,6 +299,7 @@ public class AltosSerial implements Runnable { device = in_device; line = ""; monitor_mode = false; + telemetry = Altos.ao_telemetry_full; monitors = new LinkedList> (); reply_queue = new LinkedBlockingQueue (); open(); diff --git a/altosui/AltosState.java b/altosui/AltosState.java index 4e165f80..0ff2479e 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -80,7 +80,6 @@ public class AltosState { ground_altitude = data.ground_altitude(); height = data.filtered_height(); - System.out.printf("height %g\n", height); report_time = System.currentTimeMillis(); diff --git a/altosui/AltosTelemetry.java b/altosui/AltosTelemetry.java index 3eb0efa8..91b6d048 100644 --- a/altosui/AltosTelemetry.java +++ b/altosui/AltosTelemetry.java @@ -253,12 +253,8 @@ public class AltosTelemetry extends AltosRecord { accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, MISSING); /* flight computer values */ - acceleration = map.get_int(AO_TELEM_KALMAN_ACCEL, MISSING); - if (acceleration != MISSING) - acceleration /= 16.0; - speed = map.get_int(AO_TELEM_KALMAN_SPEED, MISSING); - if (speed != MISSING) - speed /= 16.0; + acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, MISSING, 1/16.0); + speed = map.get_double(AO_TELEM_KALMAN_SPEED, MISSING, 1/16.0); height = map.get_int(AO_TELEM_KALMAN_HEIGHT, MISSING); flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, MISSING); diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 6c5a9397..980391b4 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -47,6 +47,11 @@ class AltosTelemetryReader extends AltosFlightReader { AltosPreferences.set_channel(device.getSerial(), channel); } + void set_telemetry(int telemetry) { + serial.set_telemetry(telemetry); + AltosPreferences.set_telemetry(device.getSerial(), telemetry); + } + public AltosTelemetryReader (AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException, IOException { device = in_device; -- cgit v1.2.3 From dea80af81b388cc3d7073444919f4e98b12fa730 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 25 Mar 2011 21:29:50 -0700 Subject: altosui: Remove a bunch of debug printfs from the eeprom manager code Just noise on stdout. Signed-off-by: Keith Packard --- altosui/AltosEepromDelete.java | 3 --- altosui/AltosEepromList.java | 7 ------- altosui/AltosEepromLog.java | 7 ------- altosui/AltosEepromManage.java | 1 - altosui/AltosEepromSelect.java | 3 --- 5 files changed, 21 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index c95eda15..ecd82c18 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -49,11 +49,9 @@ public class AltosEepromDelete implements Runnable { */ serial_line.flush_input(); serial_line.printf("d %d\n", log.flight); - System.out.printf("Attempt to delete flight %d\n", log.flight); for (;;) { /* It can take a while to erase the flash... */ String line = serial_line.get_reply(20000); - System.out.printf("got back line %s\n", line); if (line == null) throw new TimeoutException(); if (line.equals("Erased")) @@ -96,7 +94,6 @@ public class AltosEepromDelete implements Runnable { DeleteLog(log); } } - System.out.printf("All flights successfully deleted\n"); success = true; } catch (IOException ee) { show_error (ee.getLocalizedMessage(), diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index a932dd12..575c0bc2 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -83,7 +83,6 @@ public class AltosEepromList extends ArrayList { if (line.contains("Syntax")) continue; String[] tokens = line.split("\\s+"); - System.out.printf("got line %s (%d tokens)\n", line, tokens.length); if (tokens.length < 6) break; @@ -95,7 +94,6 @@ public class AltosEepromList extends ArrayList { start = AltosParse.parse_hex(tokens[3]); if (tokens[4].equals("end")) end = AltosParse.parse_hex(tokens[5]); - System.out.printf("parsed flight %d %x %x\n", flight, start, end); if (flight > 0 && start >= 0 && end > 0) flights.add(new AltosEepromFlight(flight, start, end)); } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); } @@ -115,7 +113,6 @@ public class AltosEepromList extends ArrayList { * firmware, this will also extract the flight number. */ for (AltosEepromFlight flight : flights) { - System.out.printf("Scanning flight %d %x %x\n", flight.flight, flight.start, flight.end); add(new AltosEepromLog(serial_line, config_data.serial, flight.start, flight.end)); } @@ -124,9 +121,5 @@ public class AltosEepromList extends ArrayList { serial_line.stop_remote(); serial_line.flush_output(); } - for (int i = 0; i < size(); i++) { - AltosEepromLog l = get(i); - System.out.printf("Found flight %d at %x - %x\n", l.flight, l.start_block, l.end_block); - } } } \ No newline at end of file diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index f284f103..10befad4 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -103,12 +103,5 @@ public class AltosEepromLog { if (has_gps && has_flight) break; } - System.out.printf("Serial %d start block %d end block %d\n", - serial, start_block, end_block); - if (has_flight) - System.out.printf("Flight %d\n", flight); - if (has_gps) - System.out.printf("%d-%d-%d %d:%02d:%02d Lat %f Lon %f\n", - year, month, day, hour, minute, second, lat, lon); } } diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index d10f7954..b12d95fa 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -69,7 +69,6 @@ public class AltosEepromManage implements ActionListener { boolean success = e.getID() != 0; boolean running = false; - System.out.printf("Eeprom manager action %s %d\n", cmd, e.getID()); if (cmd.equals("download")) { if (success) { if (any_delete) { diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index a3069f06..cb71524d 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -35,13 +35,10 @@ class AltosEepromItem implements ActionListener { JCheckBox delete; public void actionPerformed(ActionEvent e) { - System.out.printf("eeprom item action %s %d\n", e.getActionCommand(), e.getID()); if (e.getSource() == download) { log.download = download.isSelected(); - System.out.printf("download for flight %d set to %b\n", log.flight, log.download); } else if (e.getSource() == delete) { log.delete = delete.isSelected(); - System.out.printf("delete for flight %d set to %b\n", log.flight, log.delete); } } -- cgit v1.2.3 From 011615d40b3cb1d1c0ab9fa41e139e263a6a51e7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 25 Mar 2011 21:34:31 -0700 Subject: altosui: Add support for downloading TeleMini/TeleNano flight logs Splits the eeprom downloading code into eeprom block downloading and separate eeprom data parsing so that the new data logging format can share the data downloading code. Signed-off-by: Keith Packard --- altosui/Altos.java | 1 + altosui/AltosEepromBlock.java | 7 +- altosui/AltosEepromChunk.java | 88 ++++++++++++++++++++++ altosui/AltosEepromDownload.java | 153 +++++++++++++++++++++++++++++---------- altosui/AltosEepromIterable.java | 5 +- altosui/AltosEepromLog.java | 11 ++- altosui/AltosEepromRecord.java | 45 +++++------- altosui/Makefile.am | 1 + 8 files changed, 239 insertions(+), 72 deletions(-) create mode 100644 altosui/AltosEepromChunk.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 9d5b2e02..3ef4d799 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -34,6 +34,7 @@ public class Altos { static final int AO_LOG_GPS_ALT = 'H'; static final int AO_LOG_GPS_SAT = 'V'; static final int AO_LOG_GPS_DATE = 'Y'; + static final int AO_LOG_HEIGHT = 'h'; /* Added for header fields in eeprom files */ static final int AO_LOG_CONFIG_VERSION = 1000; diff --git a/altosui/AltosEepromBlock.java b/altosui/AltosEepromBlock.java index d59fd39e..650920d1 100644 --- a/altosui/AltosEepromBlock.java +++ b/altosui/AltosEepromBlock.java @@ -46,7 +46,7 @@ public class AltosEepromBlock extends ArrayList { int hour, minute, second; ParseException parse_exception = null; - public AltosEepromBlock (AltosSerial serial_line, int block) throws TimeoutException, InterruptedException { + public AltosEepromBlock (AltosEepromChunk chunk) { int addr; boolean done = false; @@ -56,10 +56,9 @@ public class AltosEepromBlock extends ArrayList { has_lat = false; has_lon = false; has_time = false; - serial_line.printf("e %x\n", block); - for (addr = 0; addr < 0x100;) { + for (addr = 0; addr < chunk.chunk_size;) { try { - AltosEepromRecord r = new AltosEepromRecord(serial_line, block * 256 + addr); + AltosEepromRecord r = new AltosEepromRecord(chunk, addr); if (r.cmd == Altos.AO_LOG_FLIGHT) { flight = r.b; diff --git a/altosui/AltosEepromChunk.java b/altosui/AltosEepromChunk.java new file mode 100644 index 00000000..8eec407d --- /dev/null +++ b/altosui/AltosEepromChunk.java @@ -0,0 +1,88 @@ +/* + * 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 altosui; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +public class AltosEepromChunk { + + static final int chunk_size = 256; + static final int per_line = 8; + + public int data[]; + public int address; + public ParseException parse_exception = null; + + int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + int data(int offset) { + return data[offset]; + } + + int data16(int offset) { + return data[offset] | (data[offset + 1] << 8); + } + + public AltosEepromChunk(AltosSerial serial_line, int block) + throws TimeoutException, InterruptedException { + + int offset; + + data = new int[chunk_size]; + address = block * chunk_size; + serial_line.printf("e %x\n", block); + + for (offset = 0; offset < chunk_size; offset += per_line) { + try { + String line = serial_line.get_reply(5000); + + if (line == null) + throw new TimeoutException(); + + int[] values = ParseHex(line); + + if (values == null || values.length != per_line + 1) + throw new ParseException(String.format("invalid line %s", line), 0); + if (values[0] != offset) + throw new ParseException(String.format("data address out of sync at 0x%x", + address + offset), 0); + for (int i = 0; i < per_line; i++) + data[offset + i] = values[1 + i]; + } catch (ParseException pe) { + for (int i = 0; i < per_line; i++) + data[offset + i] = 0xff; + if (parse_exception == null) + parse_exception = pe; + } + } + } +} \ No newline at end of file diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 1da94a67..f96a3dc9 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -78,11 +78,105 @@ public class AltosEepromDownload implements Runnable { } } + void Log(AltosEepromRecord r) throws IOException { + if (r.cmd != Altos.AO_LOG_INVALID) { + String log_line = String.format("%c %4x %4x %4x\n", + r.cmd, r.tick, r.a, r.b); + if (eeprom_file != null) + eeprom_file.write(log_line); + else + eeprom_pending.add(log_line); + } + } + + static final int log_full = 1; + static final int log_tiny = 2; + + boolean done; + int state; + + void CaptureFull(AltosEepromChunk eechunk) throws IOException { + AltosEepromBlock eeblock = new AltosEepromBlock(eechunk); + + if (eeblock.has_flight) { + flight = eeblock.flight; + monitor.set_flight(flight); + } + if (eeblock.has_date) { + year = eeblock.year; + month = eeblock.month; + day = eeblock.day; + want_file = true; + } + + if (eeblock.size() == 0 || + eeblock.has_state && eeblock.state == Altos.ao_flight_landed) + done = true; + + /* Monitor state transitions to update display */ + if (eeblock.has_state) { + if (eeblock.state > Altos.ao_flight_pad) + want_file = true; + if (eeblock.state > state) + state = eeblock.state; + } + + if (parse_exception == null && eeblock.parse_exception != null) + parse_exception = eeblock.parse_exception; + + CheckFile(false); + + for (int record = 0; record < eeblock.size(); record++) + Log(eeblock.get(record)); + } + + boolean start; + int tiny_tick; + + void CaptureTiny (AltosEepromChunk eechunk) throws IOException { + boolean some_reasonable_data = false; + + for (int i = 0; i < eechunk.data.length; i += 2) { + int v = eechunk.data16(i); + + if (i == 0 && start) { + tiny_tick = 0; + start = false; + flight = v; + Log(new AltosEepromRecord(Altos.AO_LOG_FLIGHT, tiny_tick, 0, v)); + some_reasonable_data = true; + } else { + int s = v ^ 0x8000; + if (Altos.ao_flight_startup <= s && s <= Altos.ao_flight_invalid) { + Log(new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, s, 0)); + if (s == Altos.ao_flight_landed) { + done = true; + break; + } + some_reasonable_data = true; + } else { + if (v != 0xffff) + some_reasonable_data = true; + Log(new AltosEepromRecord(Altos.AO_LOG_HEIGHT, tiny_tick, v, 0)); + if (state < Altos.ao_flight_drogue) + tiny_tick += 10; + else + tiny_tick += 100; + } + } + } + CheckFile(false); + if (!some_reasonable_data) + done = true; + } + void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException { int block, state_block = 0; - int state = 0; - boolean done = false; - int record; + int log_style = 0; + + state = 0; + done = false; + start = true; if (flights.config_data.serial == 0) throw new IOException("no serial number found"); @@ -104,47 +198,26 @@ public class AltosEepromDownload implements Runnable { for (block = log.start_block; !done && block < log.end_block; block++) { monitor.set_value(Altos.state_to_string[state], state, block - state_block); - AltosEepromBlock eeblock = new AltosEepromBlock(serial_line, block); + AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block); - if (eeblock.has_flight) { - flight = eeblock.flight; - monitor.set_flight(flight); - } - if (eeblock.has_date) { - year = eeblock.year; - month = eeblock.month; - day = eeblock.day; - want_file = true; - } + /* + * Figure out what kind of data is there + */ - if (eeblock.size() == 0 || - eeblock.has_state && eeblock.state == Altos.ao_flight_landed) - done = true; - - /* Monitor state transitions to update display */ - if (eeblock.has_state) { - if (eeblock.state > Altos.ao_flight_pad) - want_file = true; - if (eeblock.state > state) - state = eeblock.state; + if (block == log.start_block) { + if (eechunk.data(0) == Altos.AO_LOG_FLIGHT) + log_style = log_full; + else + log_style = log_tiny; } - if (parse_exception == null && eeblock.parse_exception != null) - parse_exception = eeblock.parse_exception; - - CheckFile(false); - - for (record = 0; record < eeblock.size(); record++) { - AltosEepromRecord r = eeblock.get(record); - - if (r.cmd != Altos.AO_LOG_INVALID) { - String log_line = String.format("%c %4x %4x %4x\n", - r.cmd, r.tick, r.a, r.b); - if (eeprom_file != null) - eeprom_file.write(log_line); - else - eeprom_pending.add(log_line); - } + switch (log_style) { + case log_full: + CaptureFull(eechunk); + break; + case log_tiny: + CaptureTiny(eechunk); + break; } } CheckFile(true); diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index f8e6d7e5..bb7c7bef 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -124,6 +124,10 @@ public class AltosEepromIterable extends AltosRecordIterable { } eeprom.seen |= seen_sensor; break; + case Altos.AO_LOG_HEIGHT: + state.height = record.a; + eeprom.seen |= seen_sensor; + break; case Altos.AO_LOG_TEMP_VOLT: state.temp = record.a; state.batt = record.b; @@ -155,7 +159,6 @@ public class AltosEepromIterable extends AltosRecordIterable { int flags = (record.b >> 8); state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0; state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0; - state.gps.date_valid = (flags & Altos.AO_GPS_DATE_VALID) != 0; state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT; break; diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index 10befad4..4c6deaa0 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -73,7 +73,16 @@ public class AltosEepromLog { in_end_block = in_start_block + 2; for (block = in_start_block; block < in_end_block; block++) { - AltosEepromBlock eeblock = new AltosEepromBlock(serial_line, block); + AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block); + + if (block == in_start_block) { + if (eechunk.data(0) != Altos.AO_LOG_FLIGHT) { + flight = eechunk.data16(0); + has_flight = true; + break; + } + } + AltosEepromBlock eeblock = new AltosEepromBlock(eechunk); if (eeblock.has_flight) { flight = eeblock.flight; has_flight = true; diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index e5196c50..5787af86 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -38,6 +38,8 @@ public class AltosEepromRecord { public String data; public boolean tick_valid; + static final int record_length = 8; + int[] ParseHex(String line) { String[] tokens = line.split("\\s+"); int[] array = new int[tokens.length]; @@ -51,44 +53,35 @@ public class AltosEepromRecord { return array; } - int checksum(int[] line) { + int checksum(int[] data, int start) { int csum = 0x5a; - for (int i = 1; i < line.length; i++) - csum += line[i]; + for (int i = 0; i < record_length; i++) + csum += data[i + start]; return csum & 0xff; } - public AltosEepromRecord (AltosSerial serial_line, int addr) - throws TimeoutException, ParseException, InterruptedException { - String line = serial_line.get_reply(5000); - if (line == null) - throw new TimeoutException(); - int[] values = ParseHex(line); + public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException { + + cmd = chunk.data(start); + tick_valid = true; - if (values == null || values.length < 9) { - System.out.printf("invalid line %s", line); - throw new ParseException(String.format("inalid line %s", line), 0); - } - if (values[0] != (addr & 0xff)) - throw new ParseException(String.format("data address out of sync at 0x%x", - addr), 0); int i; - for (i = 1; i < values.length; i++) - if (values[i] != 0xff) + for (i = 0; i < record_length; i++) + if (chunk.data[start + i] != 0xff) break; - cmd = values[1]; - tick_valid = true; - if (i != values.length) { - if (checksum(values) != 0) - throw new ParseException(String.format("invalid checksum at 0x%x in line %s", addr, line), 0); + if (i != 8) { + if (checksum(chunk.data, start) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); } else { cmd = Altos.AO_LOG_INVALID; tick_valid = false; } - tick = values[3] + (values[4] << 8); - a = values[5] + (values[6] << 8); - b = values[7] + (values[8] << 8); + tick = chunk.data16(start + 2); + a = chunk.data16(start + 4); + b = chunk.data16(start + 6); + data = null; } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 49f34ce3..9a9d0d36 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -28,6 +28,7 @@ altosui_JAVA = \ AltosDevice.java \ AltosDisplayThread.java \ AltosEepromBlock.java \ + AltosEepromChunk.java \ AltosEepromDelete.java \ AltosEepromDownload.java \ AltosEepromList.java \ -- cgit v1.2.3 From b155647472ddfacb07c5ffa832e4d1f4a13ad342 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 25 Mar 2011 22:01:18 -0700 Subject: altosui: Remove extra AltosEepromBlock layer This was interposed between the download layer and the eeprom layer to hold a eeprom block full of flight log records. The addition of the tiny log format required reworking the code to hold chunks full of eeprom data without regard to their content, so this content-specific layer didn't seem useful anymore. Signed-off-by: Keith Packard --- altosui/AltosEepromBlock.java | 111 --------------------------------------- altosui/AltosEepromDownload.java | 89 +++++++++++++++++-------------- altosui/AltosEepromLog.java | 49 +++++++---------- altosui/Makefile.am | 3 +- 4 files changed, 69 insertions(+), 183 deletions(-) delete mode 100644 altosui/AltosEepromBlock.java (limited to 'altosui') diff --git a/altosui/AltosEepromBlock.java b/altosui/AltosEepromBlock.java deleted file mode 100644 index 650920d1..00000000 --- a/altosui/AltosEepromBlock.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; -import java.lang.reflect.Array; - -import libaltosJNI.*; - -public class AltosEepromBlock extends ArrayList { - boolean has_flight; - int flight; - boolean has_state; - int state; - boolean has_date; - int year, month, day; - boolean has_lat; - double lat; - boolean has_lon; - double lon; - boolean has_time; - int hour, minute, second; - ParseException parse_exception = null; - - public AltosEepromBlock (AltosEepromChunk chunk) { - int addr; - boolean done = false; - - has_flight = false; - has_state = false; - has_date = false; - has_lat = false; - has_lon = false; - has_time = false; - for (addr = 0; addr < chunk.chunk_size;) { - try { - AltosEepromRecord r = new AltosEepromRecord(chunk, addr); - - if (r.cmd == Altos.AO_LOG_FLIGHT) { - flight = r.b; - has_flight = true; - } - - /* Monitor state transitions to update display */ - if (r.cmd == Altos.AO_LOG_STATE && r.a <= Altos.ao_flight_landed) { - if (!has_state || r.a > state) { - state = r.a; - has_state = true; - } - } - - if (r.cmd == Altos.AO_LOG_GPS_DATE) { - year = 2000 + (r.a & 0xff); - month = (r.a >> 8) & 0xff; - day = (r.b & 0xff); - has_date = true; - } - if (r.cmd == Altos.AO_LOG_GPS_TIME) { - hour = (r.a & 0xff); - minute = (r.a >> 8); - second = (r.b & 0xff); - has_time = true; - } - if (r.cmd == Altos.AO_LOG_GPS_LAT) { - lat = (double) (r.a | (r.b << 16)) / 1e7; - has_lat = true; - } - if (r.cmd == Altos.AO_LOG_GPS_LON) { - lon = (double) (r.a | (r.b << 16)) / 1e7; - has_lon = true; - } - if (!done) - add(addr / 8, r); - if (r.cmd == Altos.AO_LOG_STATE && r.a == Altos.ao_flight_landed) - done = true; - } catch (ParseException pe) { - AltosEepromRecord r = new AltosEepromRecord(Altos.AO_LOG_INVALID, - 0, 0, 0); - if (parse_exception == null) - parse_exception = pe; - if (!done) - add(addr/8, r); - } - addr += 8; - } - } -} \ No newline at end of file diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index f96a3dc9..a03d2b43 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -96,77 +96,88 @@ public class AltosEepromDownload implements Runnable { int state; void CaptureFull(AltosEepromChunk eechunk) throws IOException { - AltosEepromBlock eeblock = new AltosEepromBlock(eechunk); - - if (eeblock.has_flight) { - flight = eeblock.flight; - monitor.set_flight(flight); - } - if (eeblock.has_date) { - year = eeblock.year; - month = eeblock.month; - day = eeblock.day; - want_file = true; - } + boolean any_valid = false; + for (int i = 0; i < eechunk.chunk_size && !done; i += AltosEepromRecord.record_length) { + try { + AltosEepromRecord r = new AltosEepromRecord(eechunk, i); + if (r.cmd == Altos.AO_LOG_FLIGHT) { + flight = r.b; + monitor.set_flight(flight); + } - if (eeblock.size() == 0 || - eeblock.has_state && eeblock.state == Altos.ao_flight_landed) - done = true; + /* Monitor state transitions to update display */ + if (r.cmd == Altos.AO_LOG_STATE && r.a <= Altos.ao_flight_landed) { + state = r.a; + if (state > Altos.ao_flight_pad) + want_file = true; + } - /* Monitor state transitions to update display */ - if (eeblock.has_state) { - if (eeblock.state > Altos.ao_flight_pad) - want_file = true; - if (eeblock.state > state) - state = eeblock.state; + if (r.cmd == Altos.AO_LOG_GPS_DATE) { + year = 2000 + (r.a & 0xff); + month = (r.a >> 8) & 0xff; + day = (r.b & 0xff); + want_file = true; + } + if (r.cmd == Altos.AO_LOG_STATE && r.a == Altos.ao_flight_landed) + done = true; + any_valid = true; + Log(r); + } catch (ParseException pe) { + if (parse_exception == null) + parse_exception = pe; + } } - if (parse_exception == null && eeblock.parse_exception != null) - parse_exception = eeblock.parse_exception; + if (!any_valid) + done = true; CheckFile(false); - - for (int record = 0; record < eeblock.size(); record++) - Log(eeblock.get(record)); } boolean start; int tiny_tick; void CaptureTiny (AltosEepromChunk eechunk) throws IOException { - boolean some_reasonable_data = false; + boolean any_valid = false; - for (int i = 0; i < eechunk.data.length; i += 2) { - int v = eechunk.data16(i); + for (int i = 0; i < eechunk.data.length && !done; i += 2) { + int v = eechunk.data16(i); + AltosEepromRecord r; if (i == 0 && start) { tiny_tick = 0; start = false; flight = v; - Log(new AltosEepromRecord(Altos.AO_LOG_FLIGHT, tiny_tick, 0, v)); - some_reasonable_data = true; + monitor.set_flight(flight); + r = new AltosEepromRecord(Altos.AO_LOG_FLIGHT, tiny_tick, 0, v); + any_valid = true; } else { int s = v ^ 0x8000; + if (Altos.ao_flight_startup <= s && s <= Altos.ao_flight_invalid) { - Log(new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, s, 0)); - if (s == Altos.ao_flight_landed) { + r = new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, s, 0); + if (s == Altos.ao_flight_landed) done = true; - break; - } - some_reasonable_data = true; + any_valid = true; } else { if (v != 0xffff) - some_reasonable_data = true; - Log(new AltosEepromRecord(Altos.AO_LOG_HEIGHT, tiny_tick, v, 0)); + any_valid = true; + r = new AltosEepromRecord(Altos.AO_LOG_HEIGHT, tiny_tick, v, 0); + + /* + * The flight software records ascent data every 100ms, and descent + * data every 1s. + */ if (state < Altos.ao_flight_drogue) tiny_tick += 10; else tiny_tick += 100; } } + Log(r); } CheckFile(false); - if (!some_reasonable_data) + if (!any_valid) done = true; } diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index 4c6deaa0..f7fb39e1 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -41,10 +41,7 @@ public class AltosEepromLog { int start_block; int end_block; - boolean has_gps; int year, month, day; - int hour, minute, second; - double lat, lon; boolean download; boolean delete; @@ -54,7 +51,7 @@ public class AltosEepromLog { throws InterruptedException, TimeoutException { int block; - boolean has_date = false, has_time = false, has_lat = false, has_lon = false; + boolean has_date = false; start_block = in_start_block; end_block = in_end_block; @@ -82,34 +79,24 @@ public class AltosEepromLog { break; } } - AltosEepromBlock eeblock = new AltosEepromBlock(eechunk); - if (eeblock.has_flight) { - flight = eeblock.flight; - has_flight = true; - } - if (eeblock.has_date) { - year = eeblock.year; - month = eeblock.month; - day = eeblock.day; - has_date = true; - } - if (eeblock.has_time) { - hour = eeblock.hour; - minute = eeblock.minute; - second = eeblock.second; - has_time = true; - } - if (eeblock.has_lat) { - lat = eeblock.lat; - has_lat = true; - } - if (eeblock.has_lon) { - lon = eeblock.lon; - has_lon = true; + for (int i = 0; i < eechunk.chunk_size; i += AltosEepromRecord.record_length) { + try { + AltosEepromRecord r = new AltosEepromRecord(eechunk, i); + + if (r.cmd == Altos.AO_LOG_FLIGHT) { + flight = r.b; + has_flight = true; + } + if (r.cmd == Altos.AO_LOG_GPS_DATE) { + year = 2000 + (r.a & 0xff); + month = (r.a >> 8) & 0xff; + day = (r.b & 0xff); + has_date = true; + } + } catch (ParseException pe) { + } } - if (has_date && has_time && has_lat && has_lon) - has_gps = true; - if (has_gps && has_flight) + if (has_date && has_flight) break; } } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 9a9d0d36..01fe50c8 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS=libaltos JAVAROOT=classes -AM_JAVACFLAGS=-encoding UTF-8 +AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation man_MANS=altosui.1 @@ -27,7 +27,6 @@ altosui_JAVA = \ AltosDeviceDialog.java \ AltosDevice.java \ AltosDisplayThread.java \ - AltosEepromBlock.java \ AltosEepromChunk.java \ AltosEepromDelete.java \ AltosEepromDownload.java \ -- cgit v1.2.3 From 2c121f1ef495e8af3eb39210baa40e212b691894 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 25 Mar 2011 22:04:09 -0700 Subject: altosui: swing hide/show methods are deprecated I don't know why, but they are, so just replace them with setVisible calls. Signed-off-by: Keith Packard --- altosui/AltosAscent.java | 8 ++++---- altosui/AltosDescent.java | 32 ++++++++++++++++---------------- altosui/AltosLanded.java | 8 ++++---- altosui/AltosPad.java | 20 ++++++++++---------- 4 files changed, 34 insertions(+), 34 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index 0fbc5de2..8a4aa58b 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -89,13 +89,13 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { } void show() { - label.show(); - value.show(); + label.setVisible(true); + value.setVisible(true); } void hide() { - label.hide(); - value.hide(); + label.setVisible(false); + value.setVisible(false); } public AscentValue (GridBagLayout layout, int y, String text) { GridBagConstraints c = new GridBagConstraints(); diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 594a7a09..addd6878 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -39,15 +39,15 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { abstract void show(AltosState state, int crc_errors); void show() { - label.show(); - value.show(); - lights.show(); + label.setVisible(true); + value.setVisible(true); + lights.setVisible(true); } void hide() { - label.hide(); - value.hide(); - lights.hide(); + label.setVisible(false); + value.setVisible(false); + lights.setVisible(false); } void reset() { @@ -104,13 +104,13 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { abstract void show(AltosState state, int crc_errors); void show() { - label.show(); - value.show(); + label.setVisible(true); + value.setVisible(true); } void hide() { - label.hide(); - value.hide(); + label.setVisible(false); + value.setVisible(false); } void show(String format, double v) { @@ -158,15 +158,15 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { } void show() { - label.show(); - value1.show(); - value2.show(); + label.setVisible(true); + value1.setVisible(true); + value2.setVisible(true); } void hide() { - label.hide(); - value1.hide(); - value2.hide(); + label.setVisible(false); + value1.setVisible(false); + value2.setVisible(false); } abstract void show(AltosState state, int crc_errors); diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 0717ffe2..63a2daf6 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -43,13 +43,13 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { } void show() { - label.show(); - value.show(); + label.setVisible(true); + value.setVisible(true); } void hide() { - label.hide(); - value.hide(); + label.setVisible(false); + value.setVisible(false); } void show(String format, double v) { diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index 2f59e879..2d800e8a 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -43,15 +43,15 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { } public void show() { - label.show(); - value.show(); - lights.show(); + label.setVisible(true); + value.setVisible(true); + lights.setVisible(true); } public void hide() { - label.hide(); - value.hide(); - lights.hide(); + label.setVisible(false); + value.setVisible(false); + lights.setVisible(false); } public LaunchStatus (GridBagLayout layout, int y, String text) { @@ -96,13 +96,13 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { void show(AltosState state, int crc_errors) {} void show() { - label.show(); - value.show(); + label.setVisible(true); + value.setVisible(true); } void hide() { - label.hide(); - value.hide(); + label.setVisible(false); + value.setVisible(false); } void reset() { -- cgit v1.2.3 From 97517ee585462c2d355f23f999fb8d9ebd908ec1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 26 Mar 2011 00:01:22 -0700 Subject: altosui: Allow TM config connection to be canceled. This leaves the config UI connection attempt running and pops up a dialog box when it takes 'too long' in the remote case so that users with Tm or Tn devices can bring up the UI, and then boot the Tm/Tn without needing to time things carefully. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 235 +++++++++++++++++++++++++++++++---------------- altosui/AltosIgnite.java | 13 +-- altosui/AltosSerial.java | 95 +++++++++++++++++-- 3 files changed, 247 insertions(+), 96 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 47de6156..854d5384 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -109,86 +109,188 @@ public class AltosConfig implements ActionListener { void start_serial() throws InterruptedException { serial_started = true; - if (remote) { - serial_line.set_radio(); - serial_line.printf("p\nE 0\n"); - serial_line.flush_input(); - } + if (remote) + serial_line.start_remote(); } void stop_serial() throws InterruptedException { if (!serial_started) return; serial_started = false; - if (remote) { - serial_line.printf("~"); - serial_line.flush_output(); + if (remote) + serial_line.stop_remote(); + } + + void update_ui() { + config_ui.set_serial(serial.get()); + config_ui.set_product(product.get()); + config_ui.set_version(version.get()); + config_ui.set_main_deploy(main_deploy.get()); + config_ui.set_apogee_delay(apogee_delay.get()); + config_ui.set_radio_channel(radio_channel.get()); + config_ui.set_radio_calibration(radio_calibration.get()); + config_ui.set_flight_log_max(flight_log_max.get()); + config_ui.set_callsign(callsign.get()); + config_ui.set_clean(); + config_ui.make_visible(); + } + + void process_line(String line) { + if (line == null) { + System.out.printf("timeout\n"); + abort(); + return; } + if (line.equals("done")) { + System.out.printf("done\n"); + if (serial_line != null) + update_ui(); + return; + } + get_int(line, "serial-number", serial); + get_int(line, "Main deploy:", main_deploy); + get_int(line, "Apogee delay:", apogee_delay); + get_int(line, "Radio channel:", radio_channel); + get_int(line, "Radio cal:", radio_calibration); + get_int(line, "Max flight log:", flight_log_max); + get_string(line, "Callsign:", callsign); + get_string(line,"software-version", version); + get_string(line,"product", product); } - void get_data() throws InterruptedException, TimeoutException { - try { - start_serial(); - serial_line.printf("c s\nv\n"); - for (;;) { - String line = serial_line.get_reply(5000); - if (line == null) - throw new TimeoutException(); - get_int(line, "serial-number", serial); - get_int(line, "Main deploy:", main_deploy); - get_int(line, "Apogee delay:", apogee_delay); - get_int(line, "Radio channel:", radio_channel); - get_int(line, "Radio cal:", radio_calibration); - get_int(line, "Max flight log:", flight_log_max); - get_string(line, "Callsign:", callsign); - get_string(line,"software-version", version); - get_string(line,"product", product); - - /* signals the end of the version info */ - if (line.startsWith("software-version")) - break; + final static int serial_mode_read = 0; + final static int serial_mode_save = 1; + final static int serial_mode_reboot = 2; + + class SerialData implements Runnable { + AltosConfig config; + int serial_mode; + + void process_line(String line) { + config.process_line(line); + } + void callback(String in_line) { + final String line = in_line; + Runnable r = new Runnable() { + public void run() { + process_line(line); + } + }; + SwingUtilities.invokeLater(r); + } + + void get_data() { + try { + config.start_serial(); + config.serial_line.printf("c s\nv\n"); + for (;;) { + try { + String line = config.serial_line.get_reply(5000); + if (line == null) + stop_serial(); + callback(line); + if (line.startsWith("software-version")) + break; + } catch (Exception e) { + break; + } + } + } catch (InterruptedException ie) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + callback("done"); + } + + void save_data() { + try { + start_serial(); + serial_line.printf("c m %d\n", main_deploy.get()); + serial_line.printf("c d %d\n", apogee_delay.get()); + if (!remote) { + serial_line.printf("c r %d\n", radio_channel.get()); + serial_line.printf("c f %d\n", radio_calibration.get()); + } + serial_line.printf("c c %s\n", callsign.get()); + if (flight_log_max.get() != 0) + serial_line.printf("c l %d\n", flight_log_max.get()); + serial_line.printf("c w\n"); + } catch (InterruptedException ie) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + } + + void reboot() { + try { + start_serial(); + serial_line.printf("r eboot\n"); + serial_line.flush_output(); + } catch (InterruptedException ie) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + serial_line.close(); } - } finally { - stop_serial(); + } + + public void run () { + switch (serial_mode) { + case serial_mode_save: + save_data(); + /* fall through ... */ + case serial_mode_read: + get_data(); + break; + case serial_mode_reboot: + reboot(); + break; + } + } + + public SerialData(AltosConfig in_config, int in_serial_mode) { + config = in_config; + serial_mode = in_serial_mode; } } + void run_serial_thread(int serial_mode) { + SerialData sd = new SerialData(this, serial_mode); + Thread st = new Thread(sd); + st.start(); + } + void init_ui () throws InterruptedException, TimeoutException { config_ui = new AltosConfigUI(owner, remote); config_ui.addActionListener(this); + serial_line.set_frame(owner); set_ui(); } void abort() { + serial_line.close(); + serial_line = null; JOptionPane.showMessageDialog(owner, String.format("Connection to \"%s\" failed", device.toShortString()), "Connection Failed", JOptionPane.ERROR_MESSAGE); - try { - stop_serial(); - } catch (InterruptedException ie) { - } - serial_line.close(); - serial_line = null; + config_ui.setVisible(false); } void set_ui() throws InterruptedException, TimeoutException { if (serial_line != null) - get_data(); - config_ui.set_serial(serial.get()); - config_ui.set_product(product.get()); - config_ui.set_version(version.get()); - config_ui.set_main_deploy(main_deploy.get()); - config_ui.set_apogee_delay(apogee_delay.get()); - config_ui.set_radio_channel(radio_channel.get()); - config_ui.set_radio_calibration(radio_calibration.get()); - config_ui.set_flight_log_max(flight_log_max.get()); - config_ui.set_callsign(callsign.get()); - config_ui.set_clean(); - } - - void run_dialog() { + run_serial_thread(serial_mode_read); + else + update_ui(); } void save_data() { @@ -198,25 +300,7 @@ public class AltosConfig implements ActionListener { radio_calibration.set(config_ui.radio_calibration()); flight_log_max.set(config_ui.flight_log_max()); callsign.set(config_ui.callsign()); - try { - start_serial(); - serial_line.printf("c m %d\n", main_deploy.get()); - serial_line.printf("c d %d\n", apogee_delay.get()); - if (!remote) { - serial_line.printf("c r %d\n", radio_channel.get()); - serial_line.printf("c f %d\n", radio_calibration.get()); - } - serial_line.printf("c c %s\n", callsign.get()); - if (flight_log_max.get() != 0) - serial_line.printf("c l %d\n", flight_log_max.get()); - serial_line.printf("c w\n"); - } catch (InterruptedException ie) { - } finally { - try { - stop_serial(); - } catch (InterruptedException ie) { - } - } + run_serial_thread(serial_mode_save); } public void actionPerformed(ActionEvent e) { @@ -224,17 +308,11 @@ public class AltosConfig implements ActionListener { try { if (cmd.equals("Save")) { save_data(); - set_ui(); } else if (cmd.equals("Reset")) { set_ui(); } else if (cmd.equals("Reboot")) { - if (serial_line != null) { - start_serial(); - serial_line.printf("r eboot\n"); - serial_line.flush_output(); - stop_serial(); - serial_line.close(); - } + if (serial_line != null) + run_serial_thread(serial_mode_reboot); } else if (cmd.equals("Close")) { if (serial_line != null) serial_line.close(); @@ -267,7 +345,6 @@ public class AltosConfig implements ActionListener { remote = true; try { init_ui(); - config_ui.make_visible(); } catch (InterruptedException ie) { abort(); } catch (TimeoutException te) { diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index 3cbd8a75..d3638140 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -36,11 +36,8 @@ public class AltosIgnite { private void start_serial() throws InterruptedException { serial_started = true; - if (remote) { - serial.set_radio(); - serial.printf("p\nE 0\n"); - serial.flush_input(); - } + if (remote) + serial.start_remote(); } private void stop_serial() throws InterruptedException { @@ -49,10 +46,8 @@ public class AltosIgnite { serial_started = false; if (serial == null) return; - if (remote) { - serial.printf("~"); - serial.flush_output(); - } + if (remote) + serial.stop_remote(); } class string_ref { diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index a8ba66bd..88b38bb1 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -25,6 +25,11 @@ import java.lang.*; import java.io.*; import java.util.concurrent.*; import java.util.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; import libaltosJNI.*; @@ -36,7 +41,7 @@ import libaltosJNI.*; public class AltosSerial implements Runnable { - static List devices_opened = Collections.synchronizedList(new LinkedList()); + static java.util.List devices_opened = Collections.synchronizedList(new LinkedList()); AltosDevice device; SWIGTYPE_p_altos_file altos; @@ -52,6 +57,7 @@ public class AltosSerial implements Runnable { static boolean debug; boolean remote; LinkedList pending_output = new LinkedList(); + Frame frame; static void set_debug(boolean new_debug) { debug = new_debug; @@ -126,6 +132,59 @@ public class AltosSerial implements Runnable { } } + boolean abort; + JDialog timeout_dialog; + boolean timeout_started = false; + + private void stop_timeout_dialog() { + System.out.printf("stop_timeout_dialog\n"); + Runnable r = new Runnable() { + public void run() { + if (timeout_dialog != null) + timeout_dialog.setVisible(false); + } + }; + SwingUtilities.invokeLater(r); + } + + private void start_timeout_dialog_internal() { + System.out.printf("Creating timeout dialog\n"); + Object[] options = { "Cancel" }; + + JOptionPane pane = new JOptionPane(); + pane.setMessage(String.format("Connecting to %s", device.getPath())); + pane.setOptions(options); + pane.setInitialValue(null); + + timeout_dialog = pane.createDialog(frame, "Connecting..."); + + timeout_dialog.setVisible(true); + + Object o = pane.getValue(); + if (o == null) + return; + if (options[0].equals(o)) + abort = true; + } + + private boolean check_timeout() { + if (!timeout_started && frame != null) { + timeout_started = true; + System.out.printf("Starting timeout dialog\n"); + if (SwingUtilities.isEventDispatchThread()) { + start_timeout_dialog_internal(); + } else { + Runnable r = new Runnable() { + public void run() { + start_timeout_dialog_internal(); + } + }; + SwingUtilities.invokeLater(r); + } + } + return abort; + } + public void flush_input() { flush_output(); boolean got_some; @@ -156,10 +215,21 @@ public class AltosSerial implements Runnable { public String get_reply(int timeout) throws InterruptedException { flush_output(); - AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); - if (line == null) - return null; - return line.line; + if (remote) { + timeout = 300; + System.out.printf("Doing remote timout\n"); + } + abort = false; + timeout_started = false; + for (;;) { + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) { + stop_timeout_dialog(); + return line.line; + } + if (!remote || check_timeout()) + return null; + } } public void add_monitor(LinkedBlockingQueue q) { @@ -289,16 +359,25 @@ public class AltosSerial implements Runnable { public void stop_remote() { if (debug) System.out.printf("stop remote\n"); - flush_input(); - printf ("~"); - flush_output(); + try { + flush_input(); + } finally { + System.out.printf("Sending tilde\n"); + printf ("~\n"); + flush_output(); + } remote = false; } + public void set_frame(Frame in_frame) { + frame = in_frame; + } + public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { device = in_device; line = ""; monitor_mode = false; + frame = null; telemetry = Altos.ao_telemetry_full; monitors = new LinkedList> (); reply_queue = new LinkedBlockingQueue (); -- cgit v1.2.3 From 91a75279b6d306ba9d068a28c64917d5312122e8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 27 Mar 2011 00:12:01 -0700 Subject: altosui: Off-by-one error in telemetry format configuration UI The telemetry format menu uses 0 for full and 1 for tiny, but the telemetry configuration uses 1 for full and 2 for tiny. One direction (config to UI) was right, the other (UI to config) was wrong. Signed-off-by: Keith Packard --- altosui/AltosFlightUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 286b2a4e..66dcdad5 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -162,7 +162,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { telemetries.setMaximumRowCount(2); telemetries.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - int telemetry = telemetries.getSelectedIndex(); + int telemetry = telemetries.getSelectedIndex() + 1; reader.set_telemetry(telemetry); } }); -- cgit v1.2.3 From 067b21993e9a97fceadb355e571e5610535336a8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 27 Mar 2011 00:13:38 -0700 Subject: altosui: Allow radio channel to be configured over the radio link TeleMini/TeleNano can't be configured via USB, so we need to allow the radio channel to be set over the radio link. This change carefully sets the new radio channel, disables the remote link and then sets the teledongle channel to the new value and brings the link back up. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 13 ++++++++++--- altosui/AltosConfigUI.java | 2 -- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 854d5384..f45e2040 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -207,13 +207,20 @@ public class AltosConfig implements ActionListener { void save_data() { try { + int channel; start_serial(); serial_line.printf("c m %d\n", main_deploy.get()); serial_line.printf("c d %d\n", apogee_delay.get()); - if (!remote) { - serial_line.printf("c r %d\n", radio_channel.get()); - serial_line.printf("c f %d\n", radio_calibration.get()); + channel = radio_channel.get(); + serial_line.printf("c r %d\n", channel); + if (remote) { + serial_line.stop_remote(); + serial_line.set_channel(channel); + AltosPreferences.set_channel(device.getSerial(), channel); + serial_line.start_remote(); } + if (!remote) + serial_line.printf("c f %d\n", radio_calibration.get()); serial_line.printf("c c %s\n", callsign.get()); if (flight_log_max.get() != 0) serial_line.printf("c l %d\n", flight_log_max.get()); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index e09eab25..f835ee2e 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -252,8 +252,6 @@ public class AltosConfigUI radio_channel_value = new JComboBox(radio_channel_values); radio_channel_value.setEditable(false); radio_channel_value.addItemListener(this); - if (remote) - radio_channel_value.setEnabled(false); pane.add(radio_channel_value, c); /* Radio Calibration */ -- cgit v1.2.3 From f23d0f3cbf1fb0c8eab497e266625f6410b69ba3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 27 Mar 2011 00:46:19 -0700 Subject: altosui: Tell serial device which frame to use for timeout dialogs For the timeout dialog to appear, a frame must be configured for it to appear near. This patch sends the frame from the eeprom download functions to the serial code. That path doesn't yet work as the eeprom download is still trying to talk to the serial device from the swing event thread, which prevents the cancel dialog from working. Signed-off-by: Keith Packard --- altosui/AltosEepromDownload.java | 1 + altosui/AltosEepromManage.java | 2 ++ 2 files changed, 3 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index a03d2b43..fad16460 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -328,6 +328,7 @@ public class AltosEepromDownload implements Runnable { frame = given_frame; serial_line = given_serial_line; + serial_line.set_frame(frame); remote = given_remote; flights = given_flights; success = false; diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index b12d95fa..fe1db9c7 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -106,6 +106,8 @@ public class AltosEepromManage implements ActionListener { if (!device.matchProduct(AltosDevice.product_telemetrum)) remote = true; + serial_line.set_frame(frame); + flights = new AltosEepromList(serial_line, remote); if (flights.size() == 0) { -- cgit v1.2.3 From 006de838bbb096b9443863a46b8a125b1e6b5600 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 27 Mar 2011 00:48:07 -0700 Subject: altosui: Handle serial calls from swing thread Calls from the swing thread cannot be canceled as there's no way to put up the cancel dialog. In this case, simply use the 5 second timeout and fail if no communication occurs within that amount of time. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 88b38bb1..57e13448 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -137,7 +137,6 @@ public class AltosSerial implements Runnable { boolean timeout_started = false; private void stop_timeout_dialog() { - System.out.printf("stop_timeout_dialog\n"); Runnable r = new Runnable() { public void run() { if (timeout_dialog != null) @@ -148,7 +147,6 @@ public class AltosSerial implements Runnable { } private void start_timeout_dialog_internal() { - System.out.printf("Creating timeout dialog\n"); Object[] options = { "Cancel" }; JOptionPane pane = new JOptionPane(); @@ -170,10 +168,7 @@ public class AltosSerial implements Runnable { private boolean check_timeout() { if (!timeout_started && frame != null) { timeout_started = true; - System.out.printf("Starting timeout dialog\n"); - if (SwingUtilities.isEventDispatchThread()) { - start_timeout_dialog_internal(); - } else { + if (!SwingUtilities.isEventDispatchThread()) { Runnable r = new Runnable() { public void run() { start_timeout_dialog_internal(); @@ -208,16 +203,22 @@ public class AltosSerial implements Runnable { } public String get_reply() throws InterruptedException { + if (SwingUtilities.isEventDispatchThread()) + System.out.printf("Uh-oh, reading serial device from swing thread\n"); flush_output(); AltosLine line = reply_queue.take(); return line.line; } public String get_reply(int timeout) throws InterruptedException { + boolean can_cancel = true; + if (SwingUtilities.isEventDispatchThread()) { + can_cancel = false; + System.out.printf("Uh-oh, reading serial device from swing thread\n"); + } flush_output(); - if (remote) { + if (remote && can_cancel) { timeout = 300; - System.out.printf("Doing remote timout\n"); } abort = false; timeout_started = false; @@ -227,7 +228,7 @@ public class AltosSerial implements Runnable { stop_timeout_dialog(); return line.line; } - if (!remote || check_timeout()) + if (!remote || !can_cancel || check_timeout()) return null; } } @@ -362,7 +363,6 @@ public class AltosSerial implements Runnable { try { flush_input(); } finally { - System.out.printf("Sending tilde\n"); printf ("~\n"); flush_output(); } -- cgit v1.2.3 From c71a145daefb86d2c1297abec68e54bd951e3adf Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 28 Mar 2011 23:35:05 -0700 Subject: altosui: Clean up packet link connecting dialog Make sure the dialog is destroyed after use (otherwise, it hangs around on the screen sometimes). Switch timeout before showing dialog to 500ms -- that brings the dialog up less often when unnecessary. Use 'timeout_started' boolean to indicate whether the I/O thread has queued the dialog for display and whether it needs to queue a call to close it down. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 57e13448..111bd771 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -137,16 +137,19 @@ public class AltosSerial implements Runnable { boolean timeout_started = false; private void stop_timeout_dialog() { - Runnable r = new Runnable() { - public void run() { - if (timeout_dialog != null) + if (timeout_started) { + timeout_started = false; + Runnable r = new Runnable() { + public void run() { timeout_dialog.setVisible(false); - } - }; - SwingUtilities.invokeLater(r); + } + }; + SwingUtilities.invokeLater(r); + } } private void start_timeout_dialog_internal() { + Object[] options = { "Cancel" }; JOptionPane pane = new JOptionPane(); @@ -163,12 +166,14 @@ public class AltosSerial implements Runnable { return; if (options[0].equals(o)) abort = true; + timeout_dialog.dispose(); + timeout_dialog = null; } private boolean check_timeout() { if (!timeout_started && frame != null) { - timeout_started = true; if (!SwingUtilities.isEventDispatchThread()) { + timeout_started = true; Runnable r = new Runnable() { public void run() { start_timeout_dialog_internal(); @@ -186,7 +191,7 @@ public class AltosSerial implements Runnable { int timeout = 100; if (remote) - timeout = 300; + timeout = 500; do { try { Thread.sleep(timeout); @@ -210,15 +215,19 @@ public class AltosSerial implements Runnable { return line.line; } + int in_reply; + public String get_reply(int timeout) throws InterruptedException { boolean can_cancel = true; + ++in_reply; + if (SwingUtilities.isEventDispatchThread()) { can_cancel = false; System.out.printf("Uh-oh, reading serial device from swing thread\n"); } flush_output(); if (remote && can_cancel) { - timeout = 300; + timeout = 500; } abort = false; timeout_started = false; @@ -226,10 +235,13 @@ public class AltosSerial implements Runnable { AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); if (line != null) { stop_timeout_dialog(); + --in_reply; return line.line; } - if (!remote || !can_cancel || check_timeout()) + if (!remote || !can_cancel || check_timeout()) { + --in_reply; return null; + } } } @@ -245,6 +257,9 @@ public class AltosSerial implements Runnable { } public void close() { + if (in_reply != 0) + System.out.printf("Uh-oh. Closing active serial device\n"); + if (altos != null) { libaltos.altos_close(altos); } -- cgit v1.2.3 From 573edcd7dfe10ac3251396eae88eece55d82bcb6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 28 Mar 2011 23:38:02 -0700 Subject: altosui: Make flight log downloading handle 'Connecting...' dialog This required moving all of the serial communication to a separate thread and making the bulk of the download operation run after that has finished. Signed-off-by: Keith Packard --- altosui/AltosEepromManage.java | 160 +++++++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 60 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index fe1db9c7..5fb70a84 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -89,6 +89,103 @@ public class AltosEepromManage implements ActionListener { finish(); } + public void got_flights(AltosEepromList in_flights) { + boolean running = false;; + + flights = in_flights; + try { + if (flights.size() == 0) { + JOptionPane.showMessageDialog(frame, + String.format("No flights available on %d", + device.getSerial()), + serial_line.device.toShortString(), + JOptionPane.INFORMATION_MESSAGE); + } else { + AltosEepromSelect select = new AltosEepromSelect(frame, flights); + + if (select.run()) { + for (AltosEepromLog flight : flights) { + any_download = any_download || flight.download; + any_delete = any_delete || flight.delete; + } + if (any_download) { + download = new AltosEepromDownload(frame, + serial_line, + remote, + flights); + download.addActionListener(this); + } + + if (any_delete) { + delete = new AltosEepromDelete(frame, + serial_line, + remote, + flights); + delete.addActionListener(this); + } + + /* + * Start flight log download + */ + + if (any_download) { + download.start(); + running = true; + } + else if (any_delete) { + delete.start(); + running = true; + } + } + } + if (!running) + finish(); + } catch (Exception e) { + got_exception(e); + } + } + + public void got_exception(Exception e) { + if (e instanceof IOException) { + IOException ee = (IOException) e; + JOptionPane.showMessageDialog(frame, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } else if (e instanceof TimeoutException) { + TimeoutException te = (TimeoutException) e; + JOptionPane.showMessageDialog(frame, + String.format("Communications failed with \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } + finish(); + } + + class EepromGetList implements Runnable { + + AltosEepromManage manage; + + public void run () { + try { + flights = new AltosEepromList(serial_line, remote); + Runnable r = new Runnable() { + public void run() { + manage.got_flights(flights); + } + }; + SwingUtilities.invokeLater(r); + } catch (Exception e) { + manage.got_exception(e); + } + } + + public EepromGetList(AltosEepromManage in_manage) { + manage = in_manage; + } + } + public AltosEepromManage(JFrame given_frame) { boolean running = false; @@ -108,52 +205,9 @@ public class AltosEepromManage implements ActionListener { serial_line.set_frame(frame); - flights = new AltosEepromList(serial_line, remote); - - if (flights.size() == 0) { - JOptionPane.showMessageDialog(frame, - String.format("No flights available on %d", - device.getSerial()), - serial_line.device.toShortString(), - JOptionPane.INFORMATION_MESSAGE); - } else { - AltosEepromSelect select = new AltosEepromSelect(frame, flights); - - if (select.run()) { - for (AltosEepromLog flight : flights) { - any_download = any_download || flight.download; - any_delete = any_delete || flight.delete; - } - if (any_download) { - download = new AltosEepromDownload(frame, - serial_line, - remote, - flights); - download.addActionListener(this); - } - - if (any_delete) { - delete = new AltosEepromDelete(frame, - serial_line, - remote, - flights); - delete.addActionListener(this); - } - - /* - * Start flight log download - */ - - if (any_download) { - download.start(); - running = true; - } - else if (any_delete) { - delete.start(); - running = true; - } - } - } + EepromGetList get_list = new EepromGetList(this); + Thread t = new Thread(get_list); + t.start(); } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(frame, String.format("Cannot open device \"%s\"", @@ -166,21 +220,7 @@ public class AltosEepromManage implements ActionListener { device.toShortString()), "Device in use", JOptionPane.ERROR_MESSAGE); - } catch (IOException ee) { - JOptionPane.showMessageDialog(frame, - device.toShortString(), - ee.getLocalizedMessage(), - JOptionPane.ERROR_MESSAGE); - } catch (TimeoutException te) { - JOptionPane.showMessageDialog(frame, - String.format("Communications failed with \"%s\"", - device.toShortString()), - "Cannot open target device", - JOptionPane.ERROR_MESSAGE); - } catch (InterruptedException ie) { } - if (!running) - finish(); } } } -- cgit v1.2.3 From 2f9be009ef26e3d7539f5932d267d7a8a7bcb7eb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 29 Mar 2011 09:37:11 -0700 Subject: altosui: Make deployment testing handle Connecting... dialog Supporting the Connecting... dialog requires moving all serial communication to a separate thread. This was done by creating a worker thread and command queue to communicate between the UI and the serial line. Signed-off-by: Keith Packard --- altosui/AltosIgnite.java | 12 +++- altosui/AltosIgniteUI.java | 148 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 127 insertions(+), 33 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index d3638140..1171d2ed 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -19,6 +19,12 @@ package altosui; import java.io.*; import java.util.concurrent.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; public class AltosIgnite { AltosDevice device; @@ -115,7 +121,7 @@ public class AltosIgnite { return status; } - public String status_string(int status) { + public static String status_string(int status) { switch (status) { case Unknown: return "Unknown"; case Ready: return "Ready"; @@ -156,6 +162,10 @@ public class AltosIgnite { serial = null; } + public void set_frame(Frame frame) { + serial.set_frame(frame); + } + public AltosIgnite(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { device = in_device; diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index d542729c..000adc98 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -34,7 +34,6 @@ public class AltosIgniteUI implements ActionListener { AltosDevice device; - AltosIgnite ignite; JFrame owner; JLabel label; JRadioButton apogee; @@ -53,6 +52,70 @@ public class AltosIgniteUI int time_remaining; boolean timer_running; + LinkedBlockingQueue command_queue; + + class IgniteHandler implements Runnable { + AltosIgnite ignite; + + public void run () { + for (;;) { + Runnable r; + + try { + String command = command_queue.take(); + String reply = null; + + if (command.equals("get_status")) { + apogee_status = ignite.status(AltosIgnite.Apogee); + main_status = ignite.status(AltosIgnite.Main); + reply = "status"; + } else if (command.equals("main")) { + ignite.fire(AltosIgnite.Main); + reply = "fired"; + } else if (command.equals("apogee")) { + ignite.fire(AltosIgnite.Apogee); + reply = "fired"; + } else if (command.equals("quit")) { + ignite.close(); + break; + } else { + throw new ParseException(String.format("invalid command %s", command), 0); + } + final String f_reply = reply; + r = new Runnable() { + public void run() { + ignite_reply(f_reply); + } + }; + } catch (Exception e) { + final Exception f_e = e; + r = new Runnable() { + public void run() { + ignite_exception(f_e); + } + }; + } + SwingUtilities.invokeLater(r); + } + } + + public IgniteHandler(AltosIgnite in_ignite) { + ignite = in_ignite; + } + } + + void ignite_exception(Exception e) { + abort(); + } + + void ignite_reply(String reply) { + if (reply.equals("status")) { + set_ignite_status(); + } else if (reply.equals("fired")) { + fired(); + } + } + void set_arm_text() { if (arm.isSelected()) arm.setText(String.format("%d", time_remaining)); @@ -82,21 +145,53 @@ public class AltosIgniteUI stop_timer(); } - void get_ignite_status() throws InterruptedException, TimeoutException { - apogee_status = ignite.status(AltosIgnite.Apogee); - main_status = ignite.status(AltosIgnite.Main); + void send_command(String command) { + try { + command_queue.put(command); + } catch (Exception ex) { + abort(); + } + } + + boolean getting_status = false; + + boolean visible = false; + void set_ignite_status() { + getting_status = false; + apogee_status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(apogee_status))); + main_status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(main_status))); + if (!visible) { + visible = true; + setVisible(true); + } + } + + void poll_ignite_status() { + if (!getting_status) { + getting_status = true; + send_command("get_status"); + } + } + + boolean firing = false; + + void start_fire(String which) { + if (!firing) { + firing = true; + send_command(which); + } } - void set_ignite_status() throws InterruptedException, TimeoutException { - get_ignite_status(); - apogee_status_label.setText(String.format("\"%s\"", ignite.status_string(apogee_status))); - main_status_label.setText(String.format("\"%s\"", ignite.status_string(main_status))); + void fired() { + firing = false; + cancel(); } void close() { + send_command("quit"); timer.stop(); setVisible(false); - ignite.close(); + dispose(); } void abort() { @@ -116,23 +211,17 @@ public class AltosIgniteUI else set_arm_text(); } - try { - set_ignite_status(); - } catch (InterruptedException ie) { - abort(); - } catch (TimeoutException te) { - abort(); - } + poll_ignite_status(); } void fire() { if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) { - int igniter = AltosIgnite.None; + String igniter = "none"; if (apogee.isSelected() && !main.isSelected()) - igniter = AltosIgnite.Apogee; + igniter = "apogee"; else if (main.isSelected() && !apogee.isSelected()) - igniter = AltosIgnite.Main; - ignite.fire(igniter); + igniter = "main"; + send_command(igniter); cancel(); } } @@ -184,10 +273,16 @@ public class AltosIgniteUI } private boolean open() { + command_queue = new LinkedBlockingQueue(); + device = AltosDeviceDialog.show(owner, AltosDevice.product_any); if (device != null) { try { - ignite = new AltosIgnite(device); + AltosIgnite ignite = new AltosIgnite(device); + IgniteHandler handler = new IgniteHandler(ignite); + Thread t = new Thread(handler); + ignite.set_frame(owner); + t.start(); return true; } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(owner, @@ -278,16 +373,6 @@ public class AltosIgniteUI main_status_label = new JLabel(); pane.add(main_status_label, c); - try { - set_ignite_status(); - } catch (InterruptedException ie) { - abort(); - return; - } catch (TimeoutException te) { - abort(); - return; - } - c.gridx = 0; c.gridy = 3; c.gridwidth = 1; @@ -310,7 +395,6 @@ public class AltosIgniteUI pack(); setLocationRelativeTo(owner); - setVisible(true); addWindowListener(new ConfigListener(this)); } -- cgit v1.2.3 From 8ade7d99f02df825e70d0a964b4648156101ef78 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 29 Mar 2011 09:38:23 -0700 Subject: altosui: Display exception messages from swing thread Flight log management exceptions were getting displayed from the log serial I/O thread instead of the swing thread. That's a bad plan. Signed-off-by: Keith Packard --- altosui/AltosEepromManage.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index 5fb70a84..b46364db 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -168,17 +168,23 @@ public class AltosEepromManage implements ActionListener { AltosEepromManage manage; public void run () { + Runnable r; try { flights = new AltosEepromList(serial_line, remote); - Runnable r = new Runnable() { + r = new Runnable() { public void run() { - manage.got_flights(flights); + got_flights(flights); } }; - SwingUtilities.invokeLater(r); } catch (Exception e) { - manage.got_exception(e); + final Exception f_e = e; + r = new Runnable() { + public void run() { + got_exception(f_e); + } + }; } + SwingUtilities.invokeLater(r); } public EepromGetList(AltosEepromManage in_manage) { -- cgit v1.2.3 From 56d045040c49728a854741e99545766f3723da5e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 29 Mar 2011 09:39:27 -0700 Subject: altosui: Don't display 0000-00-00 for missing flight log dates With Tm/Tn not having GPS to get the current date, it's no longer unusual to have no date for a flight log, so don't show the 0000-00-00 piece in that case. Signed-off-by: Keith Packard --- altosui/AltosEepromSelect.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index cb71524d..0a6eec17 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -45,8 +45,14 @@ class AltosEepromItem implements ActionListener { public AltosEepromItem(AltosEepromLog in_log) { log = in_log; - label = new JLabel(String.format("Flight #%02d - %04d-%02d-%02d", - log.flight, log.year, log.month, log.day)); + String text; + if (log.year != 0) + text = String.format("Flight #%02d - %04d-%02d-%02d", + log.flight, log.year, log.month, log.day); + else + text = String.format("Flight #%02d", log.flight); + + label = new JLabel(text); download = new JCheckBox("", log.download); download.addActionListener(this); -- cgit v1.2.3 From a9df9fc257eb2d7038d66ac7c2539aae4474bf12 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 30 Mar 2011 11:47:07 -0700 Subject: altosui: Parse and export Max flight log value New configuration field might as well get dumped to the .csv files. Signed-off-by: Keith Packard --- altosui/Altos.java | 9 +++++---- altosui/AltosEepromIterable.java | 3 +++ altosui/AltosEepromRecord.java | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 3ef4d799..1f791da5 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -44,10 +44,11 @@ public class Altos { static final int AO_LOG_CALLSIGN = 1004; static final int AO_LOG_ACCEL_CAL = 1005; static final int AO_LOG_RADIO_CAL = 1006; - static final int AO_LOG_MANUFACTURER = 1007; - static final int AO_LOG_PRODUCT = 1008; - static final int AO_LOG_SERIAL_NUMBER = 1009; - static final int AO_LOG_SOFTWARE_VERSION = 1010; + static final int AO_LOG_MAX_FLIGHT_LOG = 1007; + static final int AO_LOG_MANUFACTURER = 2000; + static final int AO_LOG_PRODUCT = 2001; + static final int AO_LOG_SERIAL_NUMBER = 2002; + static final int AO_LOG_SOFTWARE_VERSION = 9999; /* Added to flag invalid records */ static final int AO_LOG_INVALID = -1; diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index bb7c7bef..a7fd742f 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -281,6 +281,9 @@ public class AltosEepromIterable extends AltosRecordIterable { case Altos.AO_LOG_RADIO_CAL: out.printf ("# Radio cal: %d\n", record.a); break; + case Altos.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", record.a); + break; case Altos.AO_LOG_MANUFACTURER: out.printf ("# Manufacturer: %s\n", record.data); break; diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index 5787af86..52acb435 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -131,6 +131,9 @@ public class AltosEepromRecord { } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { cmd = Altos.AO_LOG_RADIO_CAL; a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { + cmd = Altos.AO_LOG_MAX_FLIGHT_LOG; + a = Integer.parseInt(tokens[3]); } else if (tokens[0].equals("manufacturer")) { cmd = Altos.AO_LOG_MANUFACTURER; data = tokens[1]; -- cgit v1.2.3 From f558cfa1df77c36a459168c1953d0945ee5a7f9f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 30 Mar 2011 11:48:03 -0700 Subject: altosui: Only plot acceleration when present in data file Eliminates a bogus axis and data line for devices which do not have an accelerometer. Signed-off-by: Keith Packard --- altosui/AltosDataPointReader.java | 10 ++++++++-- altosui/AltosEepromIterable.java | 20 ++++++++++++++++++-- altosui/AltosGraphUI.java | 33 ++++++++++++++++++++------------- altosui/AltosRecord.java | 20 +++++++++++++------- altosui/AltosRecordIterable.java | 3 +++ altosui/AltosTelemetryIterable.java | 13 +++++++++++++ 6 files changed, 75 insertions(+), 24 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index ee57d2ce..4335421c 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -14,12 +14,18 @@ class AltosDataPointReader implements Iterable { Iterator iter; AltosState state; AltosRecord record; + boolean has_gps; + boolean has_accel; + boolean has_ignite; final static int MISSING = AltosRecord.MISSING; - public AltosDataPointReader(Iterable reader) { + public AltosDataPointReader(AltosRecordIterable reader) { this.iter = reader.iterator(); this.state = null; + has_accel = reader.has_accel(); + has_gps = reader.has_gps(); + has_ignite = reader.has_ignite(); } private void read_next_record() @@ -46,7 +52,7 @@ class AltosDataPointReader implements Iterable { public double acceleration() { return record.acceleration(); } public double pressure() { return record.raw_pressure(); } public double altitude() { return record.raw_altitude(); } - public double height() { return record.raw_height(); } + public double height() { return record.raw_height(); } public double accel_speed() { return record.accel_speed(); } public double baro_speed() { return state.baro_speed; } public double temperature() { return record.temperature(); } diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index a7fd742f..624e1dd3 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -57,6 +57,11 @@ class AltosOrderedRecord extends AltosEepromRecord implements Comparable> Altos.AO_GPS_NUM_SAT_SHIFT; + has_gps = true; break; case Altos.AO_LOG_GPS_LAT: int lat32 = record.a | (record.b << 16); @@ -254,6 +266,10 @@ public class AltosEepromIterable extends AltosRecordIterable { return list.iterator(); } + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; } + public void write_comments(PrintStream out) { Iterator iterator = records.iterator(); out.printf("# Comments\n"); diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index cd158651..e98c302b 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -96,10 +96,14 @@ public class AltosGraphUI extends JFrame public ArrayList graphs() { ArrayList graphs = new ArrayList(); - graphs.add( myAltosGraphTime("Summary") - .addElement(height) - .addElement(speed) - .addElement(acceleration) ); + graphs.add( myAltosGraphTime("Summary") + .addElement(height) + .addElement(speed) + .addElement(acceleration) ); + + graphs.add( myAltosGraphTime("Summary") + .addElement(height) + .addElement(speed)); graphs.add( myAltosGraphTime("Altitude") .addElement(height) ); @@ -107,15 +111,15 @@ public class AltosGraphUI extends JFrame graphs.add( myAltosGraphTime("Speed") .addElement(speed) ); - graphs.add( myAltosGraphTime("Acceleration") - .addElement(acceleration) ); + graphs.add( myAltosGraphTime("Acceleration") + .addElement(acceleration) ); graphs.add( myAltosGraphTime("Temperature") .addElement(temperature) ); - graphs.add( myAltosGraphTime("Continuity") - .addElement(drogue_voltage) - .addElement(main_voltage) ); + graphs.add( myAltosGraphTime("Continuity") + .addElement(drogue_voltage) + .addElement(main_voltage) ); return graphs; } @@ -154,20 +158,23 @@ public class AltosGraphUI extends JFrame public AltosGraphUI(AltosRecordIterable records) { super("Altos Graph"); - Iterable reader = new AltosDataPointReader (records); + AltosDataPointReader reader = new AltosDataPointReader (records); if (reader == null) return; - init(reader, 0); + if (reader.has_accel) + init(reader, 0); + else + init(reader, 1); } - public AltosGraphUI(Iterable data, int which) + public AltosGraphUI(AltosDataPointReader data, int which) { super("Altos Graph"); init(data, which); } - private void init(Iterable data, int which) { + private void init(AltosDataPointReader data, int which) { AltosGraph graph = createGraph(data, which); JFreeChart chart = graph.createChart(); diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index 46e96b95..200fffe5 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -139,7 +139,7 @@ public class AltosRecord { double g = ground_altitude(); if (r == MISSING || g == MISSING) - return MISSING; + return height; return r - g; } @@ -246,6 +246,9 @@ public class AltosRecord { ground_pres = old.ground_pres; accel_plus_g = old.accel_plus_g; accel_minus_g = old.accel_minus_g; + acceleration = old.acceleration; + speed = old.speed; + height = old.height; gps = new AltosGPS(old.gps); } @@ -258,12 +261,12 @@ public class AltosRecord { status = 0; state = Altos.ao_flight_startup; tick = 0; - accel = 0; - pres = 0; - temp = 0; - batt = 0; - drogue = 0; - main = 0; + accel = MISSING; + pres = MISSING; + temp = MISSING; + batt = MISSING; + drogue = MISSING; + main = MISSING; flight_accel = 0; ground_accel = 0; flight_vel = 0; @@ -271,6 +274,9 @@ public class AltosRecord { ground_pres = 0; accel_plus_g = 0; accel_minus_g = 0; + acceleration = MISSING; + speed = MISSING; + height = MISSING; gps = new AltosGPS(); } } diff --git a/altosui/AltosRecordIterable.java b/altosui/AltosRecordIterable.java index a7df92d1..45843b92 100644 --- a/altosui/AltosRecordIterable.java +++ b/altosui/AltosRecordIterable.java @@ -31,4 +31,7 @@ import java.util.concurrent.LinkedBlockingQueue; public abstract class AltosRecordIterable implements Iterable { public abstract Iterator iterator(); public void write_comments(PrintStream out) { } + public boolean has_accel() { return false; } + public boolean has_gps() { return false; } + public boolean has_ignite() { return false; }; } diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java index 14b5f27f..44e5ad8f 100644 --- a/altosui/AltosTelemetryIterable.java +++ b/altosui/AltosTelemetryIterable.java @@ -28,6 +28,13 @@ public class AltosTelemetryIterable extends AltosRecordIterable { return records.iterator(); } + boolean has_gps = false; + boolean has_accel = false; + boolean has_ignite = false; + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; }; + public AltosTelemetryIterable (FileInputStream input) { boolean saw_boost = false; int current_tick = 0; @@ -59,6 +66,12 @@ public class AltosTelemetryIterable extends AltosRecordIterable { saw_boost = true; boost_tick = record.tick; } + if (record.accel != AltosRecord.MISSING) + has_accel = true; + if (record.gps != null) + has_gps = true; + if (record.main != AltosRecord.MISSING) + has_ignite = true; records.add(record); } catch (ParseException pe) { System.out.printf("parse exception %s\n", pe.getMessage()); -- cgit v1.2.3 From 835ab3a8c2741a09b27de58c37439a193c9919ce Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Apr 2011 19:35:00 -0700 Subject: altosui: Add missing AltosTelemetryMap.java file Signed-off-by: Keith Packard --- altosui/.gitignore | 2 ++ altosui/AltosTelemetryMap.java | 63 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 altosui/AltosTelemetryMap.java (limited to 'altosui') diff --git a/altosui/.gitignore b/altosui/.gitignore index 89be1d53..6d65611f 100644 --- a/altosui/.gitignore +++ b/altosui/.gitignore @@ -4,10 +4,12 @@ macosx/ fat/ Manifest.txt Manifest-fat.txt +AltosVersion.java libaltosJNI classes altosui altosui-test +altosui-jdb classaltosui.stamp Altos-Linux-*.tar.bz2 Altos-Mac-*.zip diff --git a/altosui/AltosTelemetryMap.java b/altosui/AltosTelemetryMap.java new file mode 100644 index 00000000..d906100f --- /dev/null +++ b/altosui/AltosTelemetryMap.java @@ -0,0 +1,63 @@ +/* + * 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 altosui; +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryMap extends HashMap { + public boolean has(String key) { + return containsKey(key); + } + + public String get_string(String key) throws ParseException { + if (!has(key)) + throw new ParseException ("missing " + key, 0); + return (String) get(key); + } + + public String get_string(String key, String def) { + if (has(key)) + return get(key); + else + return def; + } + + public int get_int(String key) throws ParseException { + return AltosParse.parse_int(get_string(key)); + } + + public int get_int(String key, int def) throws ParseException { + if (has(key)) + return get_int(key); + else + return def; + } + + public double get_double(String key, double def, double scale) throws ParseException { + if (has(key)) + return get_int(key) * scale; + else + return def; + } + + public AltosTelemetryMap(String[] words, int start) { + for (int i = start; i < words.length - 1; i += 2) + put(words[i], words[i+1]); + } +} -- cgit v1.2.3 From bf1c7df5301a1727e871a8447f835fe75bdce3fc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 8 Apr 2011 10:12:50 -0700 Subject: altosui: Add TeleBT USB device support TeleBT can work just like a TeleDongle over USB. Signed-off-by: Keith Packard --- altosui/AltosDevice.java | 14 +++++++++++--- altosui/libaltos/libaltos.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosDevice.java b/altosui/AltosDevice.java index f0fda57b..b7aa38f6 100644 --- a/altosui/AltosDevice.java +++ b/altosui/AltosDevice.java @@ -81,15 +81,21 @@ public class AltosDevice extends altos_device { return 0x000d; } + static int usb_product_telebt() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_TELEBT; + return 0x000e; + } + public final static int vendor_altusmetrum = usb_vendor_altusmetrum(); public final static int product_altusmetrum = usb_product_altusmetrum(); public final static int product_telemetrum = usb_product_telemetrum(); public final static int product_teledongle = usb_product_teledongle(); public final static int product_teleterra = usb_product_teleterra(); + public final static int product_telebt = usb_product_telebt(); public final static int product_altusmetrum_min = usb_product_altusmetrum_min(); public final static int product_altusmetrum_max = usb_product_altusmetrum_max(); - public final static int product_any = 0x10000; public final static int product_basestation = 0x10000 + 1; @@ -98,7 +104,7 @@ public class AltosDevice extends altos_device { if (name == null) name = "Altus Metrum"; return String.format("%-20.20s %4d %s", - getName(), getSerial(), getPath()); + name, getSerial(), getPath()); } public String toShortString() { @@ -129,7 +135,9 @@ public class AltosDevice extends altos_device { return true; if (want_product == product_basestation) - return matchProduct(product_teledongle) || matchProduct(product_teleterra); + return matchProduct(product_teledongle) || + matchProduct(product_teleterra) || + matchProduct(product_telebt); int have_product = getProduct(); diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h index 6e94899e..0e5691cb 100644 --- a/altosui/libaltos/libaltos.h +++ b/altosui/libaltos/libaltos.h @@ -40,6 +40,7 @@ #define USB_PRODUCT_TELEMETRUM 0x000b #define USB_PRODUCT_TELEDONGLE 0x000c #define USB_PRODUCT_TELETERRA 0x000d +#define USB_PRODUCT_TELEBT 0x000e #define USB_PRODUCT_ALTUSMETRUM_MIN 0x000a #define USB_PRODUCT_ALTUSMETRUM_MAX 0x0013 -- cgit v1.2.3 From 8dd455204cf8712fa8c142b0c0517cec1bf5fd0f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 8 Apr 2011 10:13:55 -0700 Subject: altosui: Add low-level Bluetooth APIs Adds the JNI functions to query and connect to arbitrary bluetooth devices. Adds Java wrappers to construct a list of proximate bluetooth devices. Signed-off-by: Keith Packard --- altosui/AltosBTDevice.java | 142 ++++++++++ altosui/AltosEepromDownload.java | 1 + altosui/Makefile.am | 1 + altosui/libaltos/Makefile.am | 2 +- altosui/libaltos/cjnitest.c | 26 ++ altosui/libaltos/libaltos.c | 574 ++++++++++++++++++++++++--------------- altosui/libaltos/libaltos.h | 21 ++ 7 files changed, 543 insertions(+), 224 deletions(-) create mode 100644 altosui/AltosBTDevice.java (limited to 'altosui') diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java new file mode 100644 index 00000000..8eb18bb9 --- /dev/null +++ b/altosui/AltosBTDevice.java @@ -0,0 +1,142 @@ +/* + * 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 altosui; +import java.lang.*; +import java.util.*; +import libaltosJNI.*; + +public class AltosBTDevice extends altos_bt_device { + + 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) { + loaded_library = false; + } + initialized = true; + } + return loaded_library; + } + + static String bt_product_telebt() { + if (load_library()) + return libaltosConstants.BLUETOOTH_PRODUCT_TELEBT; + return "TeleBT"; + } + + public final static String bt_product_telebt = bt_product_telebt(); + public final static String bt_product_any = "Any"; + public final static String bt_product_basestation = "Basestation"; + + public String getProduct() { + String name = getName(); + if (name == null) + return "Altus Metrum"; + int dash = name.lastIndexOf("-"); + if (dash < 0) + return name; + return name.substring(0,dash); + } + + public int getSerial() { + String name = getName(); + if (name == null) + return 0; + int dash = name.lastIndexOf("-"); + if (dash < 0 || dash >= name.length()) + return 0; + String sn = name.substring(dash + 1, name.length()); + try { + return Integer.parseInt(sn); + } catch (NumberFormatException ne) { + return 0; + } + } + + public String toString() { + String name = getName(); + if (name == null) + name = "Altus Metrum"; + return String.format("%-20.20s %4d %s", + getProduct(), getSerial(), getAddr()); + } + + public String toShortString() { + String name = getName(); + if (name == null) + name = "Altus Metrum"; + return String.format("%s %d %s", + getProduct(), getSerial(), getAddr()); + + } + + public boolean isAltusMetrum() { + if (getName().startsWith(bt_product_telebt)) + return true; + return false; + } + + public boolean matchProduct(String want_product) { + + if (!isAltusMetrum()) + return false; + + if (want_product.equals(bt_product_any)) + return true; + + if (want_product.equals(bt_product_basestation)) + return matchProduct(bt_product_telebt); + + if (want_product.equals(getProduct())) + return true; + + return false; + } + + static AltosBTDevice[] list(String product) { + if (!load_library()) + return null; + + SWIGTYPE_p_altos_bt_list list = libaltos.altos_bt_list_start(); + + ArrayList device_list = new ArrayList(); + if (list != null) { + SWIGTYPE_p_altos_file file; + + for (;;) { + AltosBTDevice device = new AltosBTDevice(); + if (libaltos.altos_bt_list_next(list, device) == 0) + break; + if (device.matchProduct(product)) + device_list.add(device); + } + libaltos.altos_bt_list_finish(list); + } + + AltosBTDevice[] devices = new AltosBTDevice[device_list.size()]; + for (int i = 0; i < device_list.size(); i++) + devices[i] = device_list.get(i); + return devices; + } +} \ No newline at end of file diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index fad16460..5c704968 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -158,6 +158,7 @@ public class AltosEepromDownload implements Runnable { r = new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, s, 0); if (s == Altos.ao_flight_landed) done = true; + state = s; any_valid = true; } else { if (v != 0xffff) diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 01fe50c8..5b11d1b0 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -26,6 +26,7 @@ altosui_JAVA = \ AltosDescent.java \ AltosDeviceDialog.java \ AltosDevice.java \ + AltosBTDevice.java \ AltosDisplayThread.java \ AltosEepromChunk.java \ AltosEepromDelete.java \ diff --git a/altosui/libaltos/Makefile.am b/altosui/libaltos/Makefile.am index 388d2104..3f5f3ee2 100644 --- a/altosui/libaltos/Makefile.am +++ b/altosui/libaltos/Makefile.am @@ -16,7 +16,7 @@ noinst_PROGRAMS=cjnitest cjnitest_LDADD=libaltos.la -LIBS= +LIBS=-lbluetooth HFILES=libaltos.h diff --git a/altosui/libaltos/cjnitest.c b/altosui/libaltos/cjnitest.c index c6d6e069..79561643 100644 --- a/altosui/libaltos/cjnitest.c +++ b/altosui/libaltos/cjnitest.c @@ -14,6 +14,8 @@ 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(); @@ -39,5 +41,29 @@ main () altos_close(file); } altos_list_finish(list); + bt_list = altos_bt_list_start(); + 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); altos_fini(); + return 0; } diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 465f0ac8..13635a0d 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -56,6 +56,230 @@ altos_strndup (const char *s, size_t n) #define altos_strndup strndup #endif +#ifdef POSIX_TTY + +#include +#include +#include +#include +#include + +#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; +}; + +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) + return NULL; + + file->fd = open(device->path, O_RDWR | O_NOCTTY); + if (file->fd < 0) { + perror(device->path); + 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) { + perror(device->path); + close(file->fd); + free(file); + return NULL; + } +#endif + ret = tcgetattr(file->fd, &term); + if (ret < 0) { + perror("tcgetattr"); + 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) { + perror("tcsetattr"); + 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) + return -errno; + 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 0; +} + +#ifdef USE_POLL +#include +#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) { + perror("altos_getchar"); + 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) { + perror("altos_getchar"); + 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 */ @@ -68,6 +292,10 @@ altos_strndup (const char *s, size_t n) #include #include #include +#include +#include +#include +#include static char * cc_fullname (char *dir, char *file) @@ -354,6 +582,129 @@ altos_list_finish(struct altos_list *usbdevs) free(usbdevs); } +struct altos_bt_list { + inquiry_info *ii; + int sock; + int dev_id; + int rsp; + int num_rsp; +}; + +#define INQUIRY_MAX_RSP 255 +#define INQUIRY_LEN 8 + +struct altos_bt_list * +altos_bt_list_start(void) +{ + 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_LEN, + 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); +} + +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) + 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) { + perror("connect"); + goto no_link; + } + +#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 @@ -468,229 +819,6 @@ altos_list_finish(struct altos_list *list) #endif -#ifdef POSIX_TTY - -#include -#include -#include -#include -#include - -#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; -}; - -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) - return NULL; - - file->fd = open(device->path, O_RDWR | O_NOCTTY); - if (file->fd < 0) { - perror(device->path); - 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) { - perror(device->path); - close(file->fd); - free(file); - return NULL; - } -#endif - ret = tcgetattr(file->fd, &term); - if (ret < 0) { - perror("tcgetattr"); - 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) { - perror("tcsetattr"); - 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) - return -errno; - 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 0; -} - -#ifdef USE_POLL -#include -#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) { - perror("altos_getchar"); - 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) { - perror("altos_getchar"); - 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 */ #ifdef WINDOWS diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h index 0e5691cb..9c3f9655 100644 --- a/altosui/libaltos/libaltos.h +++ b/altosui/libaltos/libaltos.h @@ -58,6 +58,15 @@ struct altos_device { //%mutable; }; +#define BLUETOOTH_PRODUCT_TELEBT "TeleBT" + +struct altos_bt_device { + //%immutable; + char name[256]; + char addr[20]; + //%mutable; +}; + #define LIBALTOS_SUCCESS 0 #define LIBALTOS_ERROR -1 #define LIBALTOS_TIMEOUT -2 @@ -100,4 +109,16 @@ altos_flush(struct altos_file *file); PUBLIC int altos_getchar(struct altos_file *file, int timeout); +PUBLIC struct altos_bt_list * +altos_bt_list_start(void); + +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 struct altos_file * +altos_bt_open(struct altos_bt_device *device); + #endif /* _LIBALTOS_H_ */ -- cgit v1.2.3 From 7f49d694e776819e03b2c708e1c4ee23ba311430 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 9 Apr 2011 22:53:12 -0700 Subject: altos/altosui: Log averaged baro sensor data in Tm/Tn Instead of logging the best height guess from the kalman filter, log barometer data. The logged data consists of the average value betwen log points to reduce noise. Signed-off-by: Keith Packard --- altosui/Altos.java | 2 +- altosui/AltosDataPoint.java | 1 + altosui/AltosDataPointReader.java | 1 + altosui/AltosEepromDownload.java | 3 ++- altosui/AltosEepromIterable.java | 9 +++++++-- altosui/AltosGraphUI.java | 2 +- src/ao_log_tiny.c | 35 +++++++++++++++++++++++++---------- 7 files changed, 38 insertions(+), 15 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 1f791da5..54aced32 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -34,7 +34,7 @@ public class Altos { static final int AO_LOG_GPS_ALT = 'H'; static final int AO_LOG_GPS_SAT = 'V'; static final int AO_LOG_GPS_DATE = 'Y'; - static final int AO_LOG_HEIGHT = 'h'; + static final int AO_LOG_PRESSURE = 'P'; /* Added for header fields in eeprom files */ static final int AO_LOG_CONFIG_VERSION = 1000; diff --git a/altosui/AltosDataPoint.java b/altosui/AltosDataPoint.java index 66313e03..5e077320 100644 --- a/altosui/AltosDataPoint.java +++ b/altosui/AltosDataPoint.java @@ -25,5 +25,6 @@ interface AltosDataPoint { double battery_voltage(); double drogue_voltage(); double main_voltage(); + boolean has_accel(); } diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index 4335421c..fa48013f 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -59,6 +59,7 @@ class AltosDataPointReader implements Iterable { public double battery_voltage() { return record.battery_voltage(); } public double drogue_voltage() { return record.drogue_voltage(); } public double main_voltage() { return record.main_voltage(); } + public boolean has_accel() { return has_accel; } }; } diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index fad16460..a42f401c 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -162,7 +162,8 @@ public class AltosEepromDownload implements Runnable { } else { if (v != 0xffff) any_valid = true; - r = new AltosEepromRecord(Altos.AO_LOG_HEIGHT, tiny_tick, v, 0); + + r = new AltosEepromRecord(Altos.AO_LOG_PRESSURE, tiny_tick, 0, v); /* * The flight software records ascent data every 100ms, and descent diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index 624e1dd3..16349b88 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -134,8 +134,13 @@ public class AltosEepromIterable extends AltosRecordIterable { eeprom.seen |= seen_sensor; has_accel = true; break; - case Altos.AO_LOG_HEIGHT: - state.height = (short) record.a; + case Altos.AO_LOG_PRESSURE: + state.pres = record.b; + state.flight_pres = state.pres; + if (eeprom.n_pad_samples == 0) { + eeprom.n_pad_samples++; + state.ground_pres = state.pres; + } eeprom.seen |= seen_sensor; break; case Altos.AO_LOG_TEMP_VOLT: diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index e98c302b..4b994b47 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -35,7 +35,7 @@ public class AltosGraphUI extends JFrame AltosGraphTime.Element speed = new AltosGraphTime.TimeSeries("Speed (m/s)", "Vertical Speed", green) { public void gotTimeData(double time, AltosDataPoint d) { - if (d.state() < Altos.ao_flight_drogue) { + if (d.state() < Altos.ao_flight_drogue && d.has_accel()) { series.add(time, d.accel_speed()); } else { series.add(time, d.baro_speed()); diff --git a/src/ao_log_tiny.c b/src/ao_log_tiny.c index f0c0662a..6c2468fc 100644 --- a/src/ao_log_tiny.c +++ b/src/ao_log_tiny.c @@ -44,9 +44,12 @@ static void ao_log_tiny_data(uint16_t d) void ao_log(void) { - uint16_t time; - int16_t delay; + uint16_t last_time; + uint16_t now; enum ao_flight_state ao_log_tiny_state; + int32_t sum; + int16_t count; + uint8_t ao_log_adc; ao_storage_setup(); @@ -57,9 +60,19 @@ ao_log(void) while (!ao_log_running) ao_sleep(&ao_log_running); - time = ao_time(); ao_log_tiny_data(ao_flight_number); + ao_log_tiny_data(ao_ground_pres); + sum = 0; + count = 0; + ao_log_adc = ao_sample_adc; + last_time = ao_time(); for (;;) { + ao_sleep(DATA_TO_XDATA(&ao_sample_adc)); + while (ao_log_adc != ao_sample_adc) { + sum += ao_adc_ring[ao_log_adc].pres; + count++; + ao_log_adc = ao_adc_ring_next(ao_log_adc); + } if (ao_flight_state != ao_log_tiny_state) { ao_log_tiny_data(ao_flight_state | 0x8000); ao_log_tiny_state = ao_flight_state; @@ -69,14 +82,16 @@ ao_log(void) if (ao_log_tiny_state == ao_flight_landed) ao_log_stop(); } - ao_log_tiny_data(ao_height); - time += ao_log_tiny_interval; - delay = time - ao_time(); - if (delay > 0) - ao_delay(delay); /* Stop logging when told to */ - while (!ao_log_running) - ao_sleep(&ao_log_running); + if (!ao_log_running) + ao_exit(); + now = ao_time(); + if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) { + ao_log_tiny_data(sum / count); + sum = 0; + count = 0; + last_time = now; + } } } -- cgit v1.2.3 From a0fb471ce10642fc4a4bd40e4a81f8d6fe7a7c21 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 13 Apr 2011 20:27:38 -0700 Subject: altosui: oops - lost state changes when downloading eeprom data. This would cause the reader to just keep reading past the end of the flight. Signed-off-by: Keith Packard --- altosui/AltosEepromDownload.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index a42f401c..3dd5b12f 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -155,8 +155,9 @@ public class AltosEepromDownload implements Runnable { int s = v ^ 0x8000; if (Altos.ao_flight_startup <= s && s <= Altos.ao_flight_invalid) { - r = new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, s, 0); - if (s == Altos.ao_flight_landed) + state = s; + r = new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, state, 0); + if (state == Altos.ao_flight_landed) done = true; any_valid = true; } else { -- cgit v1.2.3 From 5b3f18b38d80aa041b971204bf7a94278bd9584a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 8 Apr 2011 19:46:15 -0700 Subject: altosui: Add primitive bluetooth device manager UI. This isn't useful, but does inquire for available bluetooth devices and show them in a list. Signed-off-by: Keith Packard --- altosui/AltosBTDevice.java | 26 ----- altosui/AltosBTDeviceIterator.java | 68 ++++++++++++++ altosui/AltosBTManage.java | 188 +++++++++++++++++++++++++++++++++++++ altosui/AltosConfigureUI.java | 17 +++- altosui/AltosUI.java | 4 + altosui/Makefile.am | 2 + 6 files changed, 278 insertions(+), 27 deletions(-) create mode 100644 altosui/AltosBTDeviceIterator.java create mode 100644 altosui/AltosBTManage.java (limited to 'altosui') diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index 8eb18bb9..233037de 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -113,30 +113,4 @@ public class AltosBTDevice extends altos_bt_device { return false; } - - static AltosBTDevice[] list(String product) { - if (!load_library()) - return null; - - SWIGTYPE_p_altos_bt_list list = libaltos.altos_bt_list_start(); - - ArrayList device_list = new ArrayList(); - if (list != null) { - SWIGTYPE_p_altos_file file; - - for (;;) { - AltosBTDevice device = new AltosBTDevice(); - if (libaltos.altos_bt_list_next(list, device) == 0) - break; - if (device.matchProduct(product)) - device_list.add(device); - } - libaltos.altos_bt_list_finish(list); - } - - AltosBTDevice[] devices = new AltosBTDevice[device_list.size()]; - for (int i = 0; i < device_list.size(); i++) - devices[i] = device_list.get(i); - return devices; - } } \ No newline at end of file diff --git a/altosui/AltosBTDeviceIterator.java b/altosui/AltosBTDeviceIterator.java new file mode 100644 index 00000000..935bf822 --- /dev/null +++ b/altosui/AltosBTDeviceIterator.java @@ -0,0 +1,68 @@ +/* + * 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 altosui; +import java.lang.*; +import java.util.*; +import libaltosJNI.*; + +public class AltosBTDeviceIterator implements Iterator { + String product; + AltosBTDevice current; + boolean done; + SWIGTYPE_p_altos_bt_list list; + + public boolean hasNext() { + System.out.printf ("BT has next?\n"); + if (list == null) + return false; + if (current != null) + return true; + if (done) + return false; + current = new AltosBTDevice(); + while (libaltos.altos_bt_list_next(list, current) != 0) { + System.out.printf("Got BT device %s\n", current.toString()); +// if (current.matchProduct(product)) + return true; + } + current = null; + done = true; + return false; + } + + public AltosBTDevice next() { + if (hasNext()) { + AltosBTDevice next = current; + current = null; + return next; + } + return null; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public AltosBTDeviceIterator(String in_product) { + product = in_product; + done = false; + current = null; + list = libaltos.altos_bt_list_start(); + System.out.printf("Iteration of BT list started\n"); + } +} diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java new file mode 100644 index 00000000..8e9e0f73 --- /dev/null +++ b/altosui/AltosBTManage.java @@ -0,0 +1,188 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosBTManage extends JDialog implements ActionListener { + String product; + LinkedBlockingQueue found_devices; + JFrame frame; + + class DeviceList extends JList implements Iterable { + LinkedList devices; + DefaultListModel list_model; + + public void add (AltosBTDevice device) { + devices.add(device); + list_model.addElement(device); + } + + //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); + } + + public Iterator iterator() { + return devices.iterator(); + } + + public DeviceList() { + devices = new LinkedList(); + list_model = new DefaultListModel(); + setModel(list_model); + setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + setLayoutOrientation(JList.HORIZONTAL_WRAP); + setVisibleRowCount(-1); + } + } + + DeviceList visible_devices; + + DeviceList selected_devices; + + public void actionPerformed(ActionEvent e) { + } + + public void got_visible_device() { + while (!found_devices.isEmpty()) { + AltosBTDevice device = found_devices.remove(); + visible_devices.add(device); + } + } + + class BTGetVisibleDevices implements Runnable { + public void run () { + + try { + AltosBTDeviceIterator i = new AltosBTDeviceIterator(product); + AltosBTDevice device; + + while ((device = i.next()) != null) { + Runnable r; + + found_devices.add(device); + r = new Runnable() { + public void run() { + got_visible_device(); + } + }; + SwingUtilities.invokeLater(r); + } + } catch (Exception e) { + System.out.printf("uh-oh, exception %s\n", e.toString()); + } + } + } + + public AltosBTManage(String product, JFrame in_frame) { + frame = in_frame; + BTGetVisibleDevices get_visible_devices = new BTGetVisibleDevices(); + Thread t = new Thread(get_visible_devices); + t.start(); + + found_devices = new LinkedBlockingQueue(); + + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(this); + + final JButton selectButton = new JButton("Select"); + selectButton.setActionCommand("select"); + selectButton.addActionListener(this); + getRootPane().setDefaultButton(selectButton); + + selected_devices = new DeviceList(); + JScrollPane selected_list_scroller = new JScrollPane(selected_devices); + selected_list_scroller.setPreferredSize(new Dimension(400, 80)); + selected_list_scroller.setAlignmentX(LEFT_ALIGNMENT); + + visible_devices = new DeviceList(); + JScrollPane visible_list_scroller = new JScrollPane(visible_devices); + visible_list_scroller.setPreferredSize(new Dimension(400, 80)); + visible_list_scroller.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(selected_devices); + listPane.add(label); + listPane.add(Box.createRigidArea(new Dimension(0,5))); + listPane.add(selected_list_scroller); + listPane.add(visible_list_scroller); + 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(cancelButton); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(selectButton); + + //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. +// list.setSelectedValue(initial, true); + pack(); + setLocationRelativeTo(frame); + setVisible(true); + } +} diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index 9a292c91..a2755a06 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -49,6 +49,8 @@ public class AltosConfigureUI JRadioButton serial_debug; + JButton manage_bluetooth; + /* DocumentListener interface methods */ public void changedUpdate(DocumentEvent e) { AltosPreferences.set_callsign(callsign_value.getText()); @@ -199,6 +201,19 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.WEST; pane.add(serial_debug, c); + manage_bluetooth = new JButton("Manage Bluetooth"); + manage_bluetooth.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + new AltosBTManage(AltosBTDevice.bt_product_any, owner); + } + }); + c.gridx = 1; + c.gridy = 6; + c.gridwidth = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(manage_bluetooth, c); + /* And a close button at the bottom */ close = new JButton("Close"); close.addActionListener(new ActionListener() { @@ -207,7 +222,7 @@ public class AltosConfigureUI } }); c.gridx = 0; - c.gridy = 6; + c.gridy = 7; c.gridwidth = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 4d17b0d2..73ddf979 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -198,6 +198,10 @@ public class AltosUI extends JFrame { } private void ConnectToDevice() { + AltosBTManage bt_manage; + + bt_manage = new AltosBTManage(AltosBTDevice.bt_product_any, this); + bt_manage.list(); AltosDevice device = AltosDeviceDialog.show(AltosUI.this, AltosDevice.product_basestation); diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 5b11d1b0..37a40eaa 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -27,6 +27,8 @@ altosui_JAVA = \ AltosDeviceDialog.java \ AltosDevice.java \ AltosBTDevice.java \ + AltosBTDeviceIterator.java \ + AltosBTManage.java \ AltosDisplayThread.java \ AltosEepromChunk.java \ AltosEepromDelete.java \ -- cgit v1.2.3 From 9cdef76c1275b343099d0d01af82d7eadd36a410 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 14 Apr 2011 10:12:29 -0700 Subject: altosui: Create abstract AltosDevice class This will wrap either USB or BT devices. The USB device constants have been moved to Altos.java Signed-off-by: Keith Packard --- altosui/Altos.java | 79 ++++++++++++++++ altosui/AltosConfig.java | 4 +- altosui/AltosDevice.java | 166 ++------------------------------- altosui/AltosDeviceDialog.java | 2 +- altosui/AltosEepromManage.java | 4 +- altosui/AltosFlashUI.java | 2 +- altosui/AltosIgnite.java | 2 +- altosui/AltosIgniteUI.java | 2 +- altosui/AltosSerial.java | 2 +- altosui/AltosSerialInUseException.java | 6 +- altosui/AltosUI.java | 6 +- altosui/AltosUSBDevice.java | 103 ++++++++++++++++++++ altosui/Makefile.am | 1 + 13 files changed, 206 insertions(+), 173 deletions(-) create mode 100644 altosui/AltosUSBDevice.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 1f791da5..5df004c5 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -21,6 +21,8 @@ import java.awt.*; import java.util.*; import java.text.*; +import libaltosJNI.*; + public class Altos { /* EEProm command letters */ static final int AO_LOG_FLIGHT = 'F'; @@ -222,4 +224,81 @@ public class Altos { input = input.substring(0,dot); return input.concat(extension); } + + 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) { + loaded_library = false; + } + initialized = true; + } + return loaded_library; + } + + static int usb_vendor_altusmetrum() { + if (load_library()) + return libaltosConstants.USB_VENDOR_ALTUSMETRUM; + return 0x000a; + } + + static int usb_product_altusmetrum() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_ALTUSMETRUM; + return 0x000a; + } + + static int usb_product_altusmetrum_min() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MIN; + return 0x000a; + } + + static int usb_product_altusmetrum_max() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MAX; + return 0x000d; + } + + static int usb_product_telemetrum() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_TELEMETRUM; + return 0x000b; + } + + static int usb_product_teledongle() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_TELEDONGLE; + return 0x000c; + } + + static int usb_product_teleterra() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_TELETERRA; + return 0x000d; + } + + static int usb_product_telebt() { + if (load_library()) + return libaltosConstants.USB_PRODUCT_TELEBT; + return 0x000e; + } + + public final static int vendor_altusmetrum = usb_vendor_altusmetrum(); + public final static int product_altusmetrum = usb_product_altusmetrum(); + public final static int product_telemetrum = usb_product_telemetrum(); + public final static int product_teledongle = usb_product_teledongle(); + public final static int product_teleterra = usb_product_teleterra(); + public final static int product_telebt = usb_product_telebt(); + public final static int product_altusmetrum_min = usb_product_altusmetrum_min(); + public final static int product_altusmetrum_max = usb_product_altusmetrum_max(); + + public final static int product_any = 0x10000; + public final static int product_basestation = 0x10000 + 1; } diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index f45e2040..c5de83f2 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -344,11 +344,11 @@ public class AltosConfig implements ActionListener { version = new string_ref("unknown"); product = new string_ref("unknown"); - device = AltosDeviceDialog.show(owner, AltosDevice.product_any); + device = AltosDeviceDialog.show(owner, Altos.product_any); if (device != null) { try { serial_line = new AltosSerial(device); - if (!device.matchProduct(AltosDevice.product_telemetrum)) + if (!device.matchProduct(Altos.product_telemetrum)) remote = true; try { init_ui(); diff --git a/altosui/AltosDevice.java b/altosui/AltosDevice.java index b7aa38f6..3357c550 100644 --- a/altosui/AltosDevice.java +++ b/altosui/AltosDevice.java @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Keith Packard + * 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 @@ -20,159 +20,11 @@ import java.lang.*; import java.util.*; import libaltosJNI.*; -public class AltosDevice extends altos_device { - - 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) { - loaded_library = false; - } - initialized = true; - } - return loaded_library; - } - - static int usb_vendor_altusmetrum() { - if (load_library()) - return libaltosConstants.USB_VENDOR_ALTUSMETRUM; - return 0x000a; - } - - static int usb_product_altusmetrum() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_ALTUSMETRUM; - return 0x000a; - } - - static int usb_product_altusmetrum_min() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MIN; - return 0x000a; - } - - static int usb_product_altusmetrum_max() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MAX; - return 0x000d; - } - - static int usb_product_telemetrum() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_TELEMETRUM; - return 0x000b; - } - - static int usb_product_teledongle() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_TELEDONGLE; - return 0x000c; - } - - static int usb_product_teleterra() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_TELETERRA; - return 0x000d; - } - - static int usb_product_telebt() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_TELEBT; - return 0x000e; - } - - public final static int vendor_altusmetrum = usb_vendor_altusmetrum(); - public final static int product_altusmetrum = usb_product_altusmetrum(); - public final static int product_telemetrum = usb_product_telemetrum(); - public final static int product_teledongle = usb_product_teledongle(); - public final static int product_teleterra = usb_product_teleterra(); - public final static int product_telebt = usb_product_telebt(); - public final static int product_altusmetrum_min = usb_product_altusmetrum_min(); - public final static int product_altusmetrum_max = usb_product_altusmetrum_max(); - - public final static int product_any = 0x10000; - public final static int product_basestation = 0x10000 + 1; - - 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 boolean isAltusMetrum() { - if (getVendor() != vendor_altusmetrum) - return false; - if (getProduct() < product_altusmetrum_min) - return false; - if (getProduct() > product_altusmetrum_max) - return false; - return true; - } - - public boolean matchProduct(int want_product) { - - if (!isAltusMetrum()) - return false; - - if (want_product == product_any) - return true; - - if (want_product == product_basestation) - return matchProduct(product_teledongle) || - matchProduct(product_teleterra) || - matchProduct(product_telebt); - - int have_product = getProduct(); - - if (have_product == product_altusmetrum) /* old devices match any request */ - return true; - - if (want_product == have_product) - return true; - - return false; - } - - static AltosDevice[] list(int product) { - if (!load_library()) - return null; - - SWIGTYPE_p_altos_list list = libaltos.altos_list_start(); - - ArrayList device_list = new ArrayList(); - if (list != null) { - SWIGTYPE_p_altos_file file; - - for (;;) { - AltosDevice device = new AltosDevice(); - if (libaltos.altos_list_next(list, device) == 0) - break; - if (device.matchProduct(product)) - device_list.add(device); - } - libaltos.altos_list_finish(list); - } - - AltosDevice[] devices = new AltosDevice[device_list.size()]; - for (int i = 0; i < device_list.size(); i++) - devices[i] = device_list.get(i); - return devices; - } -} \ No newline at end of file +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 SWIGTYPE_p_altos_file open(); +} diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index 2966ad1e..154bf20b 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -37,7 +37,7 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { Frame frame = JOptionPane.getFrameForComponent(frameComp); AltosDevice[] devices; - devices = AltosDevice.list(product); + devices = AltosUSBDevice.list(product); if (devices != null && devices.length > 0) { value = null; diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index b46364db..cd2b74fe 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -197,7 +197,7 @@ public class AltosEepromManage implements ActionListener { boolean running = false; frame = given_frame; - device = AltosDeviceDialog.show(frame, AltosDevice.product_any); + device = AltosDeviceDialog.show(frame, Altos.product_any); remote = false; any_download = false; @@ -206,7 +206,7 @@ public class AltosEepromManage implements ActionListener { if (device != null) { try { serial_line = new AltosSerial(device); - if (!device.matchProduct(AltosDevice.product_telemetrum)) + if (!device.matchProduct(Altos.product_telemetrum)) remote = true; serial_line.set_frame(frame); diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 0302ccd3..ad7aeac8 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -151,7 +151,7 @@ public class AltosFlashUI build_dialog(); - debug_dongle = AltosDeviceDialog.show(frame, AltosDevice.product_any); + debug_dongle = AltosDeviceDialog.show(frame, Altos.product_any); if (debug_dongle == null) return; diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index 1171d2ed..7a06c63d 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -172,7 +172,7 @@ public class AltosIgnite { serial = new AltosSerial(device); remote = false; - if (!device.matchProduct(AltosDevice.product_telemetrum)) + if (!device.matchProduct(Altos.product_telemetrum)) remote = true; } } \ No newline at end of file diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 000adc98..ad5b7cfb 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -275,7 +275,7 @@ public class AltosIgniteUI private boolean open() { command_queue = new LinkedBlockingQueue(); - device = AltosDeviceDialog.show(owner, AltosDevice.product_any); + device = AltosDeviceDialog.show(owner, Altos.product_any); if (device != null) { try { AltosIgnite ignite = new AltosIgnite(device); diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 111bd771..6c80b66f 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -304,7 +304,7 @@ public class AltosSerial implements Runnable { throw new AltosSerialInUseException(device); devices_opened.add(device.getPath()); } - altos = libaltos.altos_open(device); + altos = device.open(); if (altos == null) { close(); throw new FileNotFoundException(device.toShortString()); diff --git a/altosui/AltosSerialInUseException.java b/altosui/AltosSerialInUseException.java index 4b108c7c..7380f331 100644 --- a/altosui/AltosSerialInUseException.java +++ b/altosui/AltosSerialInUseException.java @@ -17,12 +17,10 @@ package altosui; -import libaltosJNI.*; - public class AltosSerialInUseException extends Exception { - public altos_device device; + public AltosDevice device; - public AltosSerialInUseException (altos_device in_device) { + public AltosSerialInUseException (AltosDevice in_device) { device = in_device; } } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 73ddf979..0fc6583c 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -34,7 +34,7 @@ public class AltosUI extends JFrame { public AltosVoice voice = new AltosVoice(); public static boolean load_library(Frame frame) { - if (!AltosDevice.load_library()) { + if (!Altos.load_library()) { JOptionPane.showMessageDialog(frame, String.format("No AltOS library in \"%s\"", System.getProperty("java.library.path","")), @@ -203,7 +203,7 @@ public class AltosUI extends JFrame { bt_manage = new AltosBTManage(AltosBTDevice.bt_product_any, this); bt_manage.list(); AltosDevice device = AltosDeviceDialog.show(AltosUI.this, - AltosDevice.product_basestation); + Altos.product_basestation); if (device != null) telemetry_window(device); @@ -401,7 +401,7 @@ public class AltosUI extends JFrame { AltosUI altosui = new AltosUI(); altosui.setVisible(true); - AltosDevice[] devices = AltosDevice.list(AltosDevice.product_basestation); + AltosDevice[] devices = AltosUSBDevice.list(Altos.product_basestation); for (int i = 0; i < devices.length; i++) altosui.telemetry_window(devices[i]); } diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java new file mode 100644 index 00000000..03ddf5a8 --- /dev/null +++ b/altosui/AltosUSBDevice.java @@ -0,0 +1,103 @@ +/* + * 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 altosui; +import java.lang.*; +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 SWIGTYPE_p_altos_file open() { + return libaltos.altos_open(this); + } + + public 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); + + 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 AltosUSBDevice[] list(int product) { + if (!Altos.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); + } + + AltosUSBDevice[] devices = new AltosUSBDevice[device_list.size()]; + for (int i = 0; i < device_list.size(); i++) + devices[i] = device_list.get(i); + return devices; + } +} \ No newline at end of file diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 37a40eaa..f2de4a3a 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -26,6 +26,7 @@ altosui_JAVA = \ AltosDescent.java \ AltosDeviceDialog.java \ AltosDevice.java \ + AltosUSBDevice.java \ AltosBTDevice.java \ AltosBTDeviceIterator.java \ AltosBTManage.java \ -- cgit v1.2.3 From 84163eee7847a09fe78f8762b28f857d76bf5755 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 14 Apr 2011 10:22:30 -0700 Subject: altosui: Make AltosBTDevice implement AltosDevice interface This will allow the use of either USB or BT devices through the AltosDevice interface. Signed-off-by: Keith Packard --- altosui/Altos.java | 8 ++++++ altosui/AltosBTDevice.java | 59 ++++++++++++++++++--------------------------- altosui/AltosUSBDevice.java | 2 +- 3 files changed, 32 insertions(+), 37 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 5df004c5..d221077e 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -301,4 +301,12 @@ public class Altos { public final static int product_any = 0x10000; public final static int product_basestation = 0x10000 + 1; + + static String bt_product_telebt() { + if (load_library()) + return libaltosConstants.BLUETOOTH_PRODUCT_TELEBT; + return "TeleBT"; + } + + public final static String bt_product_telebt = bt_product_telebt(); } diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index 233037de..5e946415 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -20,36 +20,9 @@ import java.lang.*; import java.util.*; import libaltosJNI.*; -public class AltosBTDevice extends altos_bt_device { - - 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) { - loaded_library = false; - } - initialized = true; - } - return loaded_library; - } - - static String bt_product_telebt() { - if (load_library()) - return libaltosConstants.BLUETOOTH_PRODUCT_TELEBT; - return "TeleBT"; - } - - public final static String bt_product_telebt = bt_product_telebt(); - public final static String bt_product_any = "Any"; - public final static String bt_product_basestation = "Basestation"; +public class AltosBTDevice extends altos_bt_device implements AltosDevice { - public String getProduct() { + public String getProductName() { String name = getName(); if (name == null) return "Altus Metrum"; @@ -59,6 +32,16 @@ public class AltosBTDevice extends altos_bt_device { return name.substring(0,dash); } + public int getProduct() { + if (Altos.bt_product_telebt.equals(getProductName())) + return Altos.product_telebt; + return 0; + } + + public String getPath() { + return getAddr(); + } + public int getSerial() { String name = getName(); if (name == null) @@ -91,24 +74,28 @@ public class AltosBTDevice extends altos_bt_device { } - public boolean isAltusMetrum() { - if (getName().startsWith(bt_product_telebt)) + public SWIGTYPE_p_altos_file open() { + return libaltos.altos_bt_open(this); + } + + private boolean isAltusMetrum() { + if (getName().startsWith(Altos.bt_product_telebt)) return true; return false; } - public boolean matchProduct(String want_product) { + public boolean matchProduct(int want_product) { if (!isAltusMetrum()) return false; - if (want_product.equals(bt_product_any)) + if (want_product == Altos.product_any) return true; - if (want_product.equals(bt_product_basestation)) - return matchProduct(bt_product_telebt); + if (want_product == Altos.product_basestation) + return matchProduct(Altos.product_telebt); - if (want_product.equals(getProduct())) + if (want_product == getProduct()) return true; return false; diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java index 03ddf5a8..deed0056 100644 --- a/altosui/AltosUSBDevice.java +++ b/altosui/AltosUSBDevice.java @@ -43,7 +43,7 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { return libaltos.altos_open(this); } - public boolean isAltusMetrum() { + private boolean isAltusMetrum() { if (getVendor() != Altos.vendor_altusmetrum) return false; if (getProduct() < Altos.product_altusmetrum_min) -- cgit v1.2.3 From f249e5926f5fd9f86c41e7f0a414193533d4d8b0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 18 Apr 2011 18:16:38 -0500 Subject: altosui: Make bluetooth dialog modal This allows it to be displayed correctly while the device dialog box (also modal) is up. Signed-off-by: Keith Packard --- altosui/AltosBTDevice.java | 2 +- altosui/AltosBTDeviceIterator.java | 4 +- altosui/AltosBTManage.java | 21 ++++++--- altosui/AltosDeviceDialog.java | 91 ++++++++++++++++++++------------------ altosui/AltosUI.java | 4 -- 5 files changed, 65 insertions(+), 57 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index 5e946415..ff2be49a 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -62,7 +62,7 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { if (name == null) name = "Altus Metrum"; return String.format("%-20.20s %4d %s", - getProduct(), getSerial(), getAddr()); + getProductName(), getSerial(), getAddr()); } public String toShortString() { diff --git a/altosui/AltosBTDeviceIterator.java b/altosui/AltosBTDeviceIterator.java index 935bf822..63ce3674 100644 --- a/altosui/AltosBTDeviceIterator.java +++ b/altosui/AltosBTDeviceIterator.java @@ -21,7 +21,7 @@ import java.util.*; import libaltosJNI.*; public class AltosBTDeviceIterator implements Iterator { - String product; + int product; AltosBTDevice current; boolean done; SWIGTYPE_p_altos_bt_list list; @@ -58,7 +58,7 @@ public class AltosBTDeviceIterator implements Iterator { throw new UnsupportedOperationException(); } - public AltosBTDeviceIterator(String in_product) { + public AltosBTDeviceIterator(int in_product) { product = in_product; done = false; current = null; diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index 8e9e0f73..66e1210e 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -31,9 +31,8 @@ import java.util.concurrent.*; import libaltosJNI.*; public class AltosBTManage extends JDialog implements ActionListener { - String product; LinkedBlockingQueue found_devices; - JFrame frame; + Frame frame; class DeviceList extends JList implements Iterable { LinkedList devices; @@ -104,7 +103,7 @@ public class AltosBTManage extends JDialog implements ActionListener { public void run () { try { - AltosBTDeviceIterator i = new AltosBTDeviceIterator(product); + AltosBTDeviceIterator i = new AltosBTDeviceIterator(Altos.product_any); AltosBTDevice device; while ((device = i.next()) != null) { @@ -124,9 +123,21 @@ public class AltosBTManage extends JDialog implements ActionListener { } } - public AltosBTManage(String product, JFrame in_frame) { + public static void show(Component frameComp) { + Frame frame = JOptionPane.getFrameForComponent(frameComp); + AltosBTManage dialog; + + dialog = new AltosBTManage(frame); + dialog.setVisible(true); + } + + public AltosBTManage(Frame in_frame) { + super(in_frame, "Manage Bluetooth Devices", true); + frame = in_frame; + BTGetVisibleDevices get_visible_devices = new BTGetVisibleDevices(); + Thread t = new Thread(get_visible_devices); t.start(); @@ -182,7 +193,5 @@ public class AltosBTManage extends JDialog implements ActionListener { //Initialize values. // list.setSelectedValue(initial, true); pack(); - setLocationRelativeTo(frame); - setVisible(true); } } diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index 154bf20b..fa20f867 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -22,59 +22,55 @@ import java.util.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; -import libaltosJNI.libaltos; -import libaltosJNI.altos_device; -import libaltosJNI.SWIGTYPE_p_altos_file; -import libaltosJNI.SWIGTYPE_p_altos_list; +import libaltosJNI.*; public class AltosDeviceDialog extends JDialog implements ActionListener { - private static AltosDeviceDialog dialog; - private static AltosDevice value = null; - private JList list; - public static AltosDevice show (Component frameComp, int product) { Frame frame = JOptionPane.getFrameForComponent(frameComp); AltosDevice[] devices; devices = AltosUSBDevice.list(product); + AltosDeviceDialog dialog; - if (devices != null && devices.length > 0) { - value = null; - dialog = new AltosDeviceDialog(frame, frameComp, - devices, - devices[0]); - - dialog.setVisible(true); - return value; - } else { - /* check for missing altos JNI library, which - * will put up its own error dialog - */ - if (AltosUI.load_library(frame)) { - JOptionPane.showMessageDialog(frame, - "No AltOS devices available", - "No AltOS devices", - JOptionPane.ERROR_MESSAGE); - } - return null; - } + dialog = new AltosDeviceDialog(frame, frameComp, + devices); + dialog.setVisible(true); + return dialog.getValue(); + } + + private AltosDevice value; + private JList list; + private JButton cancel_button; + private JButton select_button; + private JButton manage_bluetooth_button; + private Frame frame; + + private AltosDevice getValue() { + return value; } - private AltosDeviceDialog (Frame frame, Component location, - AltosDevice[] devices, - AltosDevice initial) { - super(frame, "Device Selection", true); + private AltosDeviceDialog (Frame in_frame, Component location, + AltosDevice[] devices) { + super(in_frame, "Device Selection", true); + frame = in_frame; value = null; - JButton cancelButton = new JButton("Cancel"); - cancelButton.addActionListener(this); + 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); - final JButton selectButton = new JButton("Select"); - selectButton.setActionCommand("select"); - selectButton.addActionListener(this); - getRootPane().setDefaultButton(selectButton); + 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 @@ -112,7 +108,7 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { list.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { - selectButton.doClick(); //emulate button click + select_button.doClick(); //emulate button click } } }); @@ -139,9 +135,11 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS)); buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); buttonPane.add(Box.createHorizontalGlue()); - buttonPane.add(cancelButton); + buttonPane.add(cancel_button); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); - buttonPane.add(selectButton); + 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(); @@ -149,7 +147,8 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { contentPane.add(buttonPane, BorderLayout.PAGE_END); //Initialize values. - list.setSelectedValue(initial, true); + if (devices != null && devices.length > 0) + list.setSelectedValue(devices[0], true); pack(); setLocationRelativeTo(location); } @@ -157,8 +156,12 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { //Handle clicks on the Set and Cancel buttons. public void actionPerformed(ActionEvent e) { if ("select".equals(e.getActionCommand())) - AltosDeviceDialog.value = (AltosDevice)(list.getSelectedValue()); - AltosDeviceDialog.dialog.setVisible(false); + value = (AltosDevice)(list.getSelectedValue()); + if ("manage".equals(e.getActionCommand())) { + AltosBTManage.show(frame); + return; + } + setVisible(false); } } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 0fc6583c..4b808c41 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -198,10 +198,6 @@ public class AltosUI extends JFrame { } private void ConnectToDevice() { - AltosBTManage bt_manage; - - bt_manage = new AltosBTManage(AltosBTDevice.bt_product_any, this); - bt_manage.list(); AltosDevice device = AltosDeviceDialog.show(AltosUI.this, Altos.product_basestation); -- cgit v1.2.3 From 17f38e045fcd8ca0224095c0b2b7b098df77a8d8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 19 Apr 2011 08:43:40 -0700 Subject: altosui: Use persistent list of bluetooth devices for device dialogs Store a list of known bluetooth devices as preferences. Always include those in device dialogs with an option to go browse for more devices in both the device dialog and the Configure AltosUI dialog. Signed-off-by: Keith Packard --- altosui/Altos.java | 2 + altosui/AltosBTDevice.java | 24 ++- altosui/AltosBTDeviceIterator.java | 7 +- altosui/AltosBTKnown.java | 97 +++++++++++++ altosui/AltosBTManage.java | 291 ++++++++++++++++++++++++++++--------- altosui/AltosConfigureUI.java | 2 +- altosui/AltosDeviceDialog.java | 53 ++++--- altosui/AltosFlightUI.java | 2 +- altosui/AltosPreferences.java | 25 +++- altosui/AltosSiteMap.java | 2 - altosui/AltosUI.java | 8 +- altosui/AltosUSBDevice.java | 9 +- altosui/Makefile.am | 1 + altosui/libaltos/cjnitest.c | 2 +- altosui/libaltos/libaltos.c | 16 +- altosui/libaltos/libaltos.h | 5 +- 16 files changed, 423 insertions(+), 123 deletions(-) create mode 100644 altosui/AltosBTKnown.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index d221077e..a087f73a 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -309,4 +309,6 @@ public class Altos { } public final static String bt_product_telebt = bt_product_telebt(); + + public static AltosBTKnown bt_known = new AltosBTKnown(); } diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index ff2be49a..c2721b26 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -86,8 +86,9 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { public boolean matchProduct(int want_product) { - if (!isAltusMetrum()) - return false; + System.out.printf("matchProduct %s %d\n", toString(), want_product); +// if (!isAltusMetrum()) +// return false; if (want_product == Altos.product_any) return true; @@ -100,4 +101,23 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { return false; } + + public boolean equals(Object o) { + if (!(o instanceof AltosBTDevice)) + return false; + AltosBTDevice other = (AltosBTDevice) o; + System.out.printf("AltosBTDevice equals %s == %s\n", toString(), other.toString()); + return getName().equals(other.getName()) && getAddr().equals(other.getAddr()); + } + + public int hashCode() { + return getName().hashCode() ^ getAddr().hashCode(); + } + + public AltosBTDevice(String name, String addr) { + libaltos.altos_bt_fill_in(name, addr,this); + } + + public AltosBTDevice() { + } } \ No newline at end of file diff --git a/altosui/AltosBTDeviceIterator.java b/altosui/AltosBTDeviceIterator.java index 63ce3674..7c360705 100644 --- a/altosui/AltosBTDeviceIterator.java +++ b/altosui/AltosBTDeviceIterator.java @@ -21,7 +21,6 @@ import java.util.*; import libaltosJNI.*; public class AltosBTDeviceIterator implements Iterator { - int product; AltosBTDevice current; boolean done; SWIGTYPE_p_altos_bt_list list; @@ -58,11 +57,9 @@ public class AltosBTDeviceIterator implements Iterator { throw new UnsupportedOperationException(); } - public AltosBTDeviceIterator(int in_product) { - product = in_product; + public AltosBTDeviceIterator(int inquiry_time) { done = false; current = null; - list = libaltos.altos_bt_list_start(); - System.out.printf("Iteration of BT list started\n"); + list = libaltos.altos_bt_list_start(inquiry_time); } } diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java new file mode 100644 index 00000000..95830637 --- /dev/null +++ b/altosui/AltosBTKnown.java @@ -0,0 +1,97 @@ +/* + * 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 altosui; +import java.lang.*; +import java.util.*; +import libaltosJNI.*; +import java.util.prefs.*; + +public class AltosBTKnown implements Iterable { + LinkedList devices = new LinkedList(); + Preferences bt_pref = AltosPreferences.bt_devices(); + + private String get_address(String name) { + return bt_pref.get(name, ""); + } + + private void set_address(String name, String addr) { + bt_pref.put(name, addr); + System.out.printf("saving known %s %s\n", name, addr); + } + + private void remove(String name) { + bt_pref.remove(name); + } + + private void load() { + try { + String[] names = bt_pref.keys(); + for (int i = 0; i < names.length; i++) { + String name = names[i]; + String addr = get_address(name); + System.out.printf("Known device %s %s\n", name, addr); + devices.add(new AltosBTDevice(name, addr)); + } + } catch (BackingStoreException be) { + } catch (IllegalStateException ie) { + } + } + + public Iterator iterator() { + return devices.iterator(); + } + + private void flush() { + AltosPreferences.flush_preferences(); + } + + public void set(Iterable new_devices) { + for (AltosBTDevice old : devices) { + boolean found = false; + for (AltosBTDevice new_device : new_devices) { + if (new_device.equals(old)) { + found = true; + break; + } + } + if (!found) + remove(old.getName()); + } + devices = new LinkedList(); + for (AltosBTDevice new_device : new_devices) { + devices.add(new_device); + set_address(new_device.getName(), new_device.getAddr()); + } + flush(); + } + + public List list(int product) { + LinkedList list = new LinkedList(); + for (AltosBTDevice device : devices) { + if (device.matchProduct(product)) + list.add(device); + } + return list; + } + + public AltosBTKnown() { + devices = new LinkedList(); + bt_pref = AltosPreferences.bt_devices(); + load(); + } +} \ No newline at end of file diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index 66e1210e..98a8b757 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -22,6 +22,8 @@ import java.awt.event.*; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.*; +import javax.swing.event.*; +import javax.swing.plaf.basic.*; import java.io.*; import java.util.*; import java.text.*; @@ -30,17 +32,32 @@ import java.util.concurrent.*; import libaltosJNI.*; -public class AltosBTManage extends JDialog implements ActionListener { +public class AltosBTManage extends JDialog implements ActionListener, Iterable { LinkedBlockingQueue found_devices; Frame frame; + LinkedList listeners; + AltosBTKnown bt_known; class DeviceList extends JList implements Iterable { LinkedList devices; DefaultListModel list_model; public void add (AltosBTDevice device) { - devices.add(device); - list_model.addElement(device); + if (!devices.contains(device)) { + devices.add(device); + list_model.addElement(device); + } + } + + public void remove (AltosBTDevice device) { + if (devices.contains(device)) { + devices.remove(device); + list_model.removeElement(device); + } + } + + public boolean contains(AltosBTDevice device) { + return devices.contains(device); } //Subclass JList to workaround bug 4832765, which can cause the @@ -75,6 +92,14 @@ public class AltosBTManage extends JDialog implements ActionListener { return devices.iterator(); } + public java.util.List selected_list() { + java.util.LinkedList l = new java.util.LinkedList(); + Object[] a = getSelectedValues(); + for (int i = 0; i < a.length; i++) + l.add((AltosBTDevice)a[i]); + return l; + } + public DeviceList() { devices = new LinkedList(); list_model = new DefaultListModel(); @@ -87,111 +112,233 @@ public class AltosBTManage extends JDialog implements ActionListener { DeviceList visible_devices; - DeviceList selected_devices; + DeviceList known_devices; + Thread bt_thread; + + public Iterator iterator() { + return known_devices.iterator(); + } + + public void commit() { + bt_known.set(this); + } + + public void add_known() { + for (AltosBTDevice device : visible_devices.selected_list()) { + System.out.printf("Add known %s\n", device.toString()); + known_devices.add(device); + visible_devices.remove(device); + } + } + + public void remove_known() { + for (AltosBTDevice device : known_devices.selected_list()) { + System.out.printf("Remove known %s\n", device.toString()); + known_devices.remove(device); + visible_devices.add(device); + } + } + + public void addActionListener(ActionListener l) { + listeners.add(l); + } + + private void forwardAction(ActionEvent e) { + for (ActionListener l : listeners) + l.actionPerformed(e); + } public void actionPerformed(ActionEvent e) { + String command = e.getActionCommand(); + System.out.printf("manage command %s\n", command); + if ("ok".equals(command)) { + bt_thread.interrupt(); + commit(); + setVisible(false); + forwardAction(e); + } else if ("cancel".equals(command)) { + bt_thread.interrupt(); + setVisible(false); + forwardAction(e); + } else if ("select".equals(command)) { + add_known(); + } else if ("deselect".equals(command)) { + remove_known(); + } } public void got_visible_device() { while (!found_devices.isEmpty()) { AltosBTDevice device = found_devices.remove(); - visible_devices.add(device); + if (!known_devices.contains(device)) + visible_devices.add(device); } } class BTGetVisibleDevices implements Runnable { public void run () { - - try { - AltosBTDeviceIterator i = new AltosBTDeviceIterator(Altos.product_any); - AltosBTDevice device; - - while ((device = i.next()) != null) { - Runnable r; - - found_devices.add(device); - r = new Runnable() { - public void run() { - got_visible_device(); - } - }; - SwingUtilities.invokeLater(r); + for (;;) + for (int time = 1; time <= 8; time <<= 1) { + AltosBTDeviceIterator i = new AltosBTDeviceIterator(time); + AltosBTDevice device; + + if (Thread.interrupted()) + return; + try { + while ((device = i.next()) != null) { + Runnable r; + + if (Thread.interrupted()) + return; + found_devices.add(device); + r = new Runnable() { + public void run() { + got_visible_device(); + } + }; + SwingUtilities.invokeLater(r); + } + } catch (Exception e) { + System.out.printf("uh-oh, exception %s\n", e.toString()); + } } - } catch (Exception e) { - System.out.printf("uh-oh, exception %s\n", e.toString()); - } } } - public static void show(Component frameComp) { + public static void show(Component frameComp, AltosBTKnown known) { Frame frame = JOptionPane.getFrameForComponent(frameComp); AltosBTManage dialog; - dialog = new AltosBTManage(frame); + dialog = new AltosBTManage(frame, known); dialog.setVisible(true); } - public AltosBTManage(Frame in_frame) { + public AltosBTManage(Frame in_frame, AltosBTKnown in_known) { super(in_frame, "Manage Bluetooth Devices", true); frame = in_frame; - + bt_known = in_known; BTGetVisibleDevices get_visible_devices = new BTGetVisibleDevices(); + bt_thread = new Thread(get_visible_devices); + bt_thread.start(); - Thread t = new Thread(get_visible_devices); - t.start(); + listeners = new LinkedList(); found_devices = new LinkedBlockingQueue(); - JButton cancelButton = new JButton("Cancel"); - cancelButton.addActionListener(this); - - final JButton selectButton = new JButton("Select"); - selectButton.setActionCommand("select"); - selectButton.addActionListener(this); - getRootPane().setDefaultButton(selectButton); - - selected_devices = new DeviceList(); - JScrollPane selected_list_scroller = new JScrollPane(selected_devices); - selected_list_scroller.setPreferredSize(new Dimension(400, 80)); - selected_list_scroller.setAlignmentX(LEFT_ALIGNMENT); + Container pane = getContentPane(); + pane.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(4,4,4,4); + + /* + * Known devices label and list + */ + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 1; + c.gridheight = 1; + pane.add(new JLabel("Known Devices"), c); + + known_devices = new DeviceList(); + for (AltosBTDevice device : bt_known) + known_devices.add(device); + + JScrollPane known_list_scroller = new JScrollPane(known_devices); + known_list_scroller.setPreferredSize(new Dimension(400, 80)); + known_list_scroller.setAlignmentX(LEFT_ALIGNMENT); + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.WEST; + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 1; + c.gridheight = 2; + pane.add(known_list_scroller, c); + + /* + * Visible devices label and list + */ + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 2; + c.gridy = 0; + c.gridwidth = 1; + c.gridheight = 1; + pane.add(new JLabel("Visible Devices"), c); visible_devices = new DeviceList(); JScrollPane visible_list_scroller = new JScrollPane(visible_devices); visible_list_scroller.setPreferredSize(new Dimension(400, 80)); visible_list_scroller.setAlignmentX(LEFT_ALIGNMENT); + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.WEST; + c.gridx = 2; + c.gridy = 1; + c.gridheight = 2; + c.gridwidth = 1; + pane.add(visible_list_scroller, c); + + /* + * Arrows between the two lists + */ + BasicArrowButton select_arrow = new BasicArrowButton(SwingConstants.WEST); + select_arrow.setActionCommand("select"); + select_arrow.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.SOUTH; + c.gridx = 1; + c.gridy = 1; + c.gridheight = 1; + c.gridwidth = 1; + pane.add(select_arrow, c); + + BasicArrowButton deselect_arrow = new BasicArrowButton(SwingConstants.EAST); + deselect_arrow.setActionCommand("deselect"); + deselect_arrow.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.NORTH; + c.gridx = 1; + c.gridy = 2; + c.gridheight = 1; + c.gridwidth = 1; + pane.add(deselect_arrow, c); + + JButton cancel_button = new JButton("Cancel"); + cancel_button.setActionCommand("cancel"); + cancel_button.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 0; + c.gridy = 3; + c.gridheight = 1; + c.gridwidth = 1; + pane.add(cancel_button, c); + + JButton ok_button = new JButton("OK"); + ok_button.setActionCommand("ok"); + ok_button.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 2; + c.gridy = 3; + c.gridheight = 1; + c.gridwidth = 1; + pane.add(ok_button, c); + + getRootPane().setDefaultButton(ok_button); - //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(selected_devices); - listPane.add(label); - listPane.add(Box.createRigidArea(new Dimension(0,5))); - listPane.add(selected_list_scroller); - listPane.add(visible_list_scroller); - 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(cancelButton); - buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); - buttonPane.add(selectButton); - - //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. -// list.setSelectedValue(initial, true); pack(); + setLocationRelativeTo(frame); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + bt_thread.interrupt(); + setVisible(false); + } + }); } } diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index a2755a06..0f5e4a3b 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -204,7 +204,7 @@ public class AltosConfigureUI manage_bluetooth = new JButton("Manage Bluetooth"); manage_bluetooth.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - new AltosBTManage(AltosBTDevice.bt_product_any, owner); + AltosBTManage.show(owner, Altos.bt_known); } }); c.gridx = 1; diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index fa20f867..e17504e2 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -26,37 +26,46 @@ import libaltosJNI.*; public class AltosDeviceDialog extends JDialog implements ActionListener { - public static AltosDevice show (Component frameComp, int product) { - - Frame frame = JOptionPane.getFrameForComponent(frameComp); - AltosDevice[] devices; - devices = AltosUSBDevice.list(product); - AltosDeviceDialog dialog; - - dialog = new AltosDeviceDialog(frame, frameComp, - devices); - dialog.setVisible(true); - return dialog.getValue(); - } - 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 AltosDeviceDialog (Frame in_frame, Component location, - AltosDevice[] devices) { + private AltosDevice[] devices() { + java.util.List usb_devices = AltosUSBDevice.list(product); + java.util.List bt_devices = Altos.bt_known.list(product); + AltosDevice[] devices = new AltosDevice[usb_devices.size() + bt_devices.size()]; + + 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); @@ -147,7 +156,7 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { contentPane.add(buttonPane, BorderLayout.PAGE_END); //Initialize values. - if (devices != null && devices.length > 0) + if (devices != null && devices.length != 0) list.setSelectedValue(devices[0], true); pack(); setLocationRelativeTo(location); @@ -158,10 +167,20 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { if ("select".equals(e.getActionCommand())) value = (AltosDevice)(list.getSelectedValue()); if ("manage".equals(e.getActionCommand())) { - AltosBTManage.show(frame); + AltosBTManage.show(frame, Altos.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/AltosFlightUI.java b/altosui/AltosFlightUI.java index 66dcdad5..eb6c6d9d 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -122,7 +122,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { JComboBox telemetries; public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) { - AltosPreferences.init(this); + AltosPreferences.set_component(this); voice = in_voice; reader = in_reader; diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index 5f827655..b1192be1 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -79,11 +79,9 @@ class AltosPreferences { /* Serial debug */ static boolean serial_debug; - public static void init(Component ui) { + public static void init() { preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); - component = ui; - /* Initialize logdir from preferences */ String logdir_string = preferences.get(logdirPreference, null); if (logdir_string != null) @@ -116,14 +114,23 @@ class AltosPreferences { AltosSerial.set_debug(serial_debug); } + static { init(); } + + static void set_component(Component in_component) { + component = in_component; + } + static void flush_preferences() { try { preferences.flush(); } catch (BackingStoreException ee) { - JOptionPane.showMessageDialog(component, - preferences.absolutePath(), - "Cannot save prefernces", - JOptionPane.ERROR_MESSAGE); + if (component != null) + JOptionPane.showMessageDialog(component, + preferences.absolutePath(), + "Cannot save prefernces", + JOptionPane.ERROR_MESSAGE); + else + System.err.printf("Cannot save preferences\n"); } } @@ -262,4 +269,8 @@ class AltosPreferences { public static boolean serial_debug() { return serial_debug; } + + public static Preferences bt_devices() { + return preferences.node("bt_devices"); + } } diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index f4b6b7e0..7575c10e 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -164,8 +164,6 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { } public static void prefetchMaps(double lat, double lng, int w, int h) { - AltosPreferences.init(null); - AltosSiteMap asm = new AltosSiteMap(true); asm.centre = asm.getBaseLocation(lat, lng); diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 4b808c41..7955c1c2 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -99,7 +99,7 @@ public class AltosUI extends JFrame { if (imgURL != null) setIconImage(new ImageIcon(imgURL).getImage()); - AltosPreferences.init(this); + AltosPreferences.set_component(this); pane = getContentPane(); gridbag = new GridBagLayout(); @@ -397,9 +397,9 @@ public class AltosUI extends JFrame { AltosUI altosui = new AltosUI(); altosui.setVisible(true); - AltosDevice[] devices = AltosUSBDevice.list(Altos.product_basestation); - for (int i = 0; i < devices.length; i++) - altosui.telemetry_window(devices[i]); + java.util.List devices = AltosUSBDevice.list(Altos.product_basestation); + for (AltosDevice device : devices) + altosui.telemetry_window(device); } } } diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java index deed0056..dc746a64 100644 --- a/altosui/AltosUSBDevice.java +++ b/altosui/AltosUSBDevice.java @@ -77,13 +77,13 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { return false; } - static AltosUSBDevice[] list(int product) { + static java.util.List list(int product) { if (!Altos.load_library()) return null; SWIGTYPE_p_altos_list list = libaltos.altos_list_start(); - ArrayList device_list = new ArrayList(); + ArrayList device_list = new ArrayList(); if (list != null) { for (;;) { AltosUSBDevice device = new AltosUSBDevice(); @@ -95,9 +95,6 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { libaltos.altos_list_finish(list); } - AltosUSBDevice[] devices = new AltosUSBDevice[device_list.size()]; - for (int i = 0; i < device_list.size(); i++) - devices[i] = device_list.get(i); - return devices; + return device_list; } } \ No newline at end of file diff --git a/altosui/Makefile.am b/altosui/Makefile.am index f2de4a3a..f4d84ad2 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -30,6 +30,7 @@ altosui_JAVA = \ AltosBTDevice.java \ AltosBTDeviceIterator.java \ AltosBTManage.java \ + AltosBTKnown.java \ AltosDisplayThread.java \ AltosEepromChunk.java \ AltosEepromDelete.java \ diff --git a/altosui/libaltos/cjnitest.c b/altosui/libaltos/cjnitest.c index 79561643..88e40d73 100644 --- a/altosui/libaltos/cjnitest.c +++ b/altosui/libaltos/cjnitest.c @@ -41,7 +41,7 @@ main () altos_close(file); } altos_list_finish(list); - bt_list = altos_bt_list_start(); + 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) { diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 13635a0d..2c47f3e5 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -591,10 +591,9 @@ struct altos_bt_list { }; #define INQUIRY_MAX_RSP 255 -#define INQUIRY_LEN 8 struct altos_bt_list * -altos_bt_list_start(void) +altos_bt_list_start(int inquiry_time) { struct altos_bt_list *bt_list; @@ -614,7 +613,7 @@ altos_bt_list_start(void) goto no_sock; bt_list->num_rsp = hci_inquiry(bt_list->dev_id, - INQUIRY_LEN, + inquiry_time, INQUIRY_MAX_RSP, NULL, &bt_list->ii, @@ -665,6 +664,15 @@ 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) { @@ -768,7 +776,7 @@ get_number(io_object_t object, CFStringRef entry, int *result) } struct altos_list * -altos_list_start(void) +altos_list_start(int time) { struct altos_list *list = calloc (sizeof (struct altos_list), 1); CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice"); diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h index 9c3f9655..f710919c 100644 --- a/altosui/libaltos/libaltos.h +++ b/altosui/libaltos/libaltos.h @@ -110,7 +110,7 @@ PUBLIC int altos_getchar(struct altos_file *file, int timeout); PUBLIC struct altos_bt_list * -altos_bt_list_start(void); +altos_bt_list_start(int inquiry_time); PUBLIC int altos_bt_list_next(struct altos_bt_list *list, struct altos_bt_device *device); @@ -118,6 +118,9 @@ 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); -- cgit v1.2.3 From 6b5957d5f6f8181da7be98c9bce49a0ec0b4a713 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 19 Apr 2011 10:41:28 -0700 Subject: altosui: Wait two seconds after bluetooth connect XXX "something" isn't quite ready to communicate right after the device is connected, so we stick a delay in. There should be a better fix. Signed-off-by: Keith Packard --- altosui/libaltos/libaltos.c | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 2c47f3e5..c5bcf900 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -698,6 +698,7 @@ altos_bt_open(struct altos_bt_device *device) perror("connect"); goto no_link; } + sleep(2); #ifdef USE_POLL pipe(file->pipe); -- cgit v1.2.3 From d41edb3384b6336f3482e61b0c9f9400a8b4f519 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 19 Apr 2011 15:29:39 -0700 Subject: altosui: Make flight data download work through TeleBT This required flushing input before reading data blocks and adjusting some delays. Signed-off-by: Keith Packard --- altosui/AltosEepromChunk.java | 1 + altosui/AltosEepromList.java | 2 +- altosui/AltosEepromLog.java | 7 ++++--- altosui/libaltos/libaltos.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromChunk.java b/altosui/AltosEepromChunk.java index 8eec407d..1e42077f 100644 --- a/altosui/AltosEepromChunk.java +++ b/altosui/AltosEepromChunk.java @@ -59,6 +59,7 @@ public class AltosEepromChunk { data = new int[chunk_size]; address = block * chunk_size; + serial_line.flush_input(); serial_line.printf("e %x\n", block); for (offset = 0; offset < chunk_size; offset += per_line) { diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index 575c0bc2..185fec91 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -114,7 +114,7 @@ public class AltosEepromList extends ArrayList { */ for (AltosEepromFlight flight : flights) { add(new AltosEepromLog(serial_line, config_data.serial, - flight.start, flight.end)); + flight.flight, flight.start, flight.end)); } } finally { if (remote) diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index f7fb39e1..0cf420d9 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -47,7 +47,8 @@ public class AltosEepromLog { boolean delete; public AltosEepromLog(AltosSerial serial_line, int in_serial, - int in_start_block, int in_end_block) + int in_flight, int in_start_block, + int in_end_block) throws InterruptedException, TimeoutException { int block; @@ -73,8 +74,8 @@ public class AltosEepromLog { AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block); if (block == in_start_block) { - if (eechunk.data(0) != Altos.AO_LOG_FLIGHT) { - flight = eechunk.data16(0); + if (eechunk.data16(0) == in_flight) { + flight = in_flight; has_flight = true; break; } diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index c5bcf900..5e507cdf 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -698,7 +698,7 @@ altos_bt_open(struct altos_bt_device *device) perror("connect"); goto no_link; } - sleep(2); + sleep(1); #ifdef USE_POLL pipe(file->pipe); -- cgit v1.2.3 From 2e7b7b80432bb251ac39efa1fa05d32b5f250e14 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Apr 2011 21:17:07 -0700 Subject: altosui: Separate out flash debug code to separate thread This avoids blocking the Swing thread while waiting for the serial device. Signed-off-by: Keith Packard --- altosui/AltosFlash.java | 15 ++-- altosui/AltosFlashUI.java | 159 ++++++++++++++++++++++++++++++++---------- altosui/AltosRomconfigUI.java | 10 +++ altosui/AltosUI.java | 2 +- 4 files changed, 139 insertions(+), 47 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlash.java b/altosui/AltosFlash.java index 802adc8c..e91e9806 100644 --- a/altosui/AltosFlash.java +++ b/altosui/AltosFlash.java @@ -28,7 +28,7 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; -public class AltosFlash implements Runnable { +public class AltosFlash { File file; FileInputStream input; AltosHexfile image; @@ -252,9 +252,7 @@ public class AltosFlash implements Runnable { throw new IOException("Failed to execute program on target"); } - Thread thread; - - public void run() { + public void flash() { try { if (!check_rom_config()) throw new IOException("Invalid rom config settings"); @@ -333,15 +331,14 @@ public class AltosFlash implements Runnable { } } - public void flash() { - thread = new Thread(this); - thread.start(); + public void close() { + if (debug != null) + debug.close(); } synchronized public void abort() { aborted = true; - if (debug != null) - debug.close(); + close(); } public void addActionListener(ActionListener l) { diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index ad7aeac8..3874b500 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -26,7 +26,7 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.*; public class AltosFlashUI extends JDialog @@ -41,14 +41,24 @@ public class AltosFlashUI JProgressBar pbar; JButton cancel; - File file; - Thread thread; JFrame frame; + + // Hex file with rom image + File file; + + // Debug connection AltosDevice debug_dongle; + + // Desired Rom configuration + AltosRomconfig rom_config; + + // Flash controller AltosFlash flash; public void actionPerformed(ActionEvent e) { if (e.getSource() == cancel) { + if (flash != null) + flash.abort(); setVisible(false); dispose(); } else { @@ -111,7 +121,7 @@ public class AltosFlashUI c.gridx = 1; c.gridy = 1; c.anchor = GridBagConstraints.LINE_START; c.insets = ir; - file_value = new JLabel(""); + file_value = new JLabel(file.toString()); pane.add(file_value, c); pbar = new JProgressBar(); @@ -144,18 +154,11 @@ public class AltosFlashUI setLocationRelativeTo(frame); } - public AltosFlashUI(JFrame in_frame) { - super(in_frame, "Program Altusmetrum Device", false); - - frame = in_frame; - - build_dialog(); - - debug_dongle = AltosDeviceDialog.show(frame, Altos.product_any); - - if (debug_dongle == null) - return; + void set_serial(int serial_number) { + serial_value.setText(String.format("%d", serial_number)); + } + boolean select_source_file() { JFileChooser hexfile_chooser = new JFileChooser(); File firmwaredir = AltosPreferences.firmwaredir(); @@ -167,46 +170,128 @@ public class AltosFlashUI int returnVal = hexfile_chooser.showOpenDialog(frame); if (returnVal != JFileChooser.APPROVE_OPTION) - return; - + return false; file = hexfile_chooser.getSelectedFile(); + if (file == null) + return false; + AltosPreferences.set_firmwaredir(file.getParentFile()); + return true; + } - if (file != null) - AltosPreferences.set_firmwaredir(file.getParentFile()); + boolean select_debug_dongle() { + debug_dongle = AltosDeviceDialog.show(frame, Altos.product_any); - try { - flash = new AltosFlash(file, debug_dongle); - flash.addActionListener(this); - AltosRomconfigUI romconfig_ui = new AltosRomconfigUI (frame); + if (debug_dongle == null) + return false; + return true; + } - romconfig_ui.set(flash.romconfig()); - AltosRomconfig romconfig = romconfig_ui.showDialog(); + boolean update_rom_config_info(AltosRomconfig existing_config) { + AltosRomconfig new_config; + new_config = AltosRomconfigUI.show(frame, existing_config); + if (new_config == null) + return false; + rom_config = new_config; + set_serial(rom_config.serial_number); + setVisible(true); + return true; + } - if (romconfig != null && romconfig.valid()) { - flash.set_romconfig(romconfig); - serial_value.setText(String.format("%d", - flash.romconfig().serial_number)); - file_value.setText(file.toString()); - setVisible(true); - flash.flash(); - } - } catch (FileNotFoundException ee) { + void exception (Exception e) { + if (e instanceof FileNotFoundException) { JOptionPane.showMessageDialog(frame, "Cannot open image", file.toString(), JOptionPane.ERROR_MESSAGE); - } catch (AltosSerialInUseException si) { + } else if (e instanceof AltosSerialInUseException) { JOptionPane.showMessageDialog(frame, String.format("Device \"%s\" already in use", debug_dongle.toShortString()), "Device in use", JOptionPane.ERROR_MESSAGE); - } catch (IOException e) { + } else if (e instanceof IOException) { JOptionPane.showMessageDialog(frame, e.getMessage(), file.toString(), JOptionPane.ERROR_MESSAGE); - } catch (InterruptedException ie) { } } + + class flash_task implements Runnable { + AltosFlashUI ui; + Thread t; + AltosFlash flash; + + public void run () { + try { + flash = new AltosFlash(ui.file, ui.debug_dongle); + flash.addActionListener(ui); + + final AltosRomconfig current_config = flash.romconfig(); + + final Semaphore await_rom_config = new Semaphore(0); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + ui.flash = flash; + ui.update_rom_config_info(current_config); + System.out.printf("Done updating rom config info\n"); + await_rom_config.release(); + } + }); + System.out.printf("Waiting for rom configuration updates\n"); + await_rom_config.acquire(); + System.out.printf("Got rom config update\n"); + + if (ui.rom_config != null) { + System.out.printf("rom_config not null\n"); + flash.set_romconfig(ui.rom_config); + flash.flash(); + } + } catch (Exception ee) { + final Exception e = ee; + System.out.printf("exception %s\n", e.toString()); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + ui.exception(e); + } + }); + } + if (flash != null) + flash.close(); + } + + public flash_task(AltosFlashUI in_ui) { + ui = in_ui; + t = new Thread(this); + t.start(); + } + } + + flash_task flasher; + + /* + * Execute the steps for flashing + * a device. Note that this returns immediately; + * this dialog is not modal + */ + void showDialog() { + if (!select_debug_dongle()) + return; + if (!select_source_file()) + return; + build_dialog(); + flash_task f = new flash_task(this); + } + + static void show(JFrame frame) { + AltosFlashUI ui = new AltosFlashUI(frame); + + ui.showDialog(); + } + + public AltosFlashUI(JFrame in_frame) { + super(in_frame, "Program Altusmetrum Device", false); + + frame = in_frame; + } } \ No newline at end of file diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java index e1dc974e..7e21735c 100644 --- a/altosui/AltosRomconfigUI.java +++ b/altosui/AltosRomconfigUI.java @@ -126,6 +126,11 @@ public class AltosRomconfigUI setLocationRelativeTo(owner); } + public AltosRomconfigUI(JFrame frame, AltosRomconfig config) { + this(frame); + set(config); + } + boolean selected; /* Listen for events from our buttons */ @@ -183,4 +188,9 @@ public class AltosRomconfigUI return romconfig(); return null; } + + public static AltosRomconfig show(JFrame frame, AltosRomconfig config) { + AltosRomconfigUI ui = new AltosRomconfigUI(frame, config); + return ui.showDialog(); + } } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 7955c1c2..7bb4ba12 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -219,7 +219,7 @@ public class AltosUI extends JFrame { } void FlashImage() { - new AltosFlashUI(AltosUI.this); + AltosFlashUI.show(AltosUI.this); } void FireIgniter() { -- cgit v1.2.3 From aa5caf6310f074109472e6f55d8bd9751fb75c4c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Apr 2011 21:26:21 -0700 Subject: altosui: Fix TeleBT name in flight monitor title Was getting the product number, not the product name. Signed-off-by: Keith Packard --- altosui/AltosBTDevice.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index c2721b26..7a876c25 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -58,19 +58,13 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { } public String toString() { - String name = getName(); - if (name == null) - name = "Altus Metrum"; return String.format("%-20.20s %4d %s", getProductName(), getSerial(), getAddr()); } public String toShortString() { - String name = getName(); - if (name == null) - name = "Altus Metrum"; return String.format("%s %d %s", - getProduct(), getSerial(), getAddr()); + getProductName(), getSerial(), getAddr()); } -- cgit v1.2.3 From 109344d54d3fa4f79342fd1ea2a3f4085475e30c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Apr 2011 22:28:40 -0700 Subject: altosui: Display reader name (usually the device) when an I/O error occurs Access the reader name directly from the reader object instead of a local variable (which wasn't getting set anyways). Signed-off-by: Keith Packard --- altosui/AltosDisplayThread.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java index 84abfae9..ce8d9159 100644 --- a/altosui/AltosDisplayThread.java +++ b/altosui/AltosDisplayThread.java @@ -33,7 +33,6 @@ public class AltosDisplayThread extends Thread { Frame parent; IdleThread idle_thread; AltosVoice voice; - String name; AltosFlightReader reader; int crc_errors; AltosFlightDisplay display; @@ -57,19 +56,18 @@ public class AltosDisplayThread extends Thread { SwingUtilities.invokeLater(r); } - void reading_error_internal(String name) { + void reading_error_internal() { JOptionPane.showMessageDialog(parent, - String.format("Error reading from \"%s\"", name), + String.format("Error reading from \"%s\"", reader.name), "Telemetry Read Error", JOptionPane.ERROR_MESSAGE); } - void reading_error_safely(String in_name) { - final String name = in_name; + void reading_error_safely() { Runnable r = new Runnable() { public void run() { try { - reading_error_internal(name); + reading_error_internal(); } catch (Exception ex) { } } @@ -258,7 +256,7 @@ public class AltosDisplayThread extends Thread { } catch (InterruptedException ee) { interrupted = true; } catch (IOException ie) { - reading_error_safely(name); + reading_error_safely(); } finally { if (!interrupted) idle_thread.report(true); -- cgit v1.2.3 From e3bf13a38d24e95b16df1e2f01952d10f24cda10 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Apr 2011 22:55:08 -0700 Subject: altosui: Move AltosIgniteUI device open out of Swing thread Eliminate more blocking code from the Swing thread. Signed-off-by: Keith Packard --- altosui/AltosIgniteUI.java | 93 +++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 42 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index ad5b7cfb..42120b92 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -56,8 +56,27 @@ public class AltosIgniteUI class IgniteHandler implements Runnable { AltosIgnite ignite; + JFrame owner; + + void send_exception(Exception e) { + final Exception f_e = e; + Runnable r = new Runnable() { + public void run() { + ignite_exception(f_e); + } + }; + SwingUtilities.invokeLater(r); + } public void run () { + try { + ignite = new AltosIgnite(device); + } catch (Exception e) { + send_exception(e); + return; + } + ignite.set_frame(owner); + for (;;) { Runnable r; @@ -87,25 +106,45 @@ public class AltosIgniteUI ignite_reply(f_reply); } }; + SwingUtilities.invokeLater(r); } catch (Exception e) { - final Exception f_e = e; - r = new Runnable() { - public void run() { - ignite_exception(f_e); - } - }; + send_exception(e); } - SwingUtilities.invokeLater(r); } } - public IgniteHandler(AltosIgnite in_ignite) { - ignite = in_ignite; + public IgniteHandler(JFrame in_owner) { + owner = in_owner; } } void ignite_exception(Exception e) { - abort(); + if (e instanceof FileNotFoundException) { + JOptionPane.showMessageDialog(owner, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } else if (e instanceof AltosSerialInUseException) { + JOptionPane.showMessageDialog(owner, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } else if (e instanceof IOException) { + IOException ee = (IOException) e; + JOptionPane.showMessageDialog(owner, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } else { + JOptionPane.showMessageDialog(owner, + String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); + } + close(); } void ignite_reply(String reply) { @@ -149,7 +188,7 @@ public class AltosIgniteUI try { command_queue.put(command); } catch (Exception ex) { - abort(); + ignite_exception(ex); } } @@ -194,15 +233,6 @@ public class AltosIgniteUI dispose(); } - void abort() { - close(); - JOptionPane.showMessageDialog(owner, - String.format("Connection to \"%s\" failed", - device.toShortString()), - "Connection Failed", - JOptionPane.ERROR_MESSAGE); - } - void tick_timer() { if (timer_running) { --time_remaining; @@ -277,31 +307,10 @@ public class AltosIgniteUI device = AltosDeviceDialog.show(owner, Altos.product_any); if (device != null) { - try { - AltosIgnite ignite = new AltosIgnite(device); - IgniteHandler handler = new IgniteHandler(ignite); + IgniteHandler handler = new IgniteHandler(owner); Thread t = new Thread(handler); - ignite.set_frame(owner); t.start(); return true; - } catch (FileNotFoundException ee) { - JOptionPane.showMessageDialog(owner, - String.format("Cannot open device \"%s\"", - device.toShortString()), - "Cannot open target device", - JOptionPane.ERROR_MESSAGE); - } catch (AltosSerialInUseException si) { - JOptionPane.showMessageDialog(owner, - String.format("Device \"%s\" already in use", - device.toShortString()), - "Device in use", - JOptionPane.ERROR_MESSAGE); - } catch (IOException ee) { - JOptionPane.showMessageDialog(owner, - device.toShortString(), - ee.getLocalizedMessage(), - JOptionPane.ERROR_MESSAGE); - } } return false; } -- cgit v1.2.3 From 72a03baa73698fc1213a74320e6253c2380dd8fa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Apr 2011 23:00:42 -0700 Subject: altosui: Fix BT manage dialog so that the device lists resize This makes the device scrolling lists fill any extra space when the window is resized. Signed-off-by: Keith Packard --- altosui/AltosBTManage.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index 98a8b757..10fdab3b 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -241,6 +241,8 @@ public class AltosBTManage extends JDialog implements ActionListener, Iterable Date: Thu, 2 Jun 2011 23:16:30 -0700 Subject: altosui: Handle old TeleDongle receiving kalman telemetry packets The telemetry packets now send the kalman height/speed/accel values instead of the ad-hoc values. If received by an old TeleDongle box, the speed value will be of the form 0x8000abcd, which will be printed as a 32-bit value by TeleDongle. We only want the abcd part, which is the speed * 16. Detect this automatically and compute the correct values for all three. Signed-off-by: Keith Packard --- altosui/AltosTelemetry.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosTelemetry.java b/altosui/AltosTelemetry.java index 91b6d048..7d68b5b5 100644 --- a/altosui/AltosTelemetry.java +++ b/altosui/AltosTelemetry.java @@ -326,6 +326,16 @@ public class AltosTelemetry extends AltosRecord { AltosParse.word(words[i++], "fp:"); flight_pres = AltosParse.parse_int(words[i++]); + /* Old TeleDongle code with kalman-reporting TeleMetrum code */ + if ((flight_vel & 0xffff0000) == 0x80000000) { + speed = ((short) flight_vel) / 16.0; + acceleration = flight_accel / 16.0; + height = flight_pres; + flight_vel = MISSING; + flight_pres = MISSING; + flight_accel = MISSING; + } + AltosParse.word(words[i++], "gp:"); ground_pres = AltosParse.parse_int(words[i++]); -- cgit v1.2.3 From 7fd9b8f720add559b262e81d61ededc9df16ca94 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 28 Jun 2011 01:03:00 -0700 Subject: altosui: Support raw telemetry from TeleDongle Use raw telemetry frames when TeleDongle supports them, this involves parsing the hex dump of the packet instead of having teledongle take the packet apart. Only the legacy format is working at this point; the altos bits for the new split telemetry frames is not written yet. Signed-off-by: Keith Packard --- altosui/Altos.java | 68 +++- altosui/AltosEepromIterable.java | 1 + altosui/AltosFile.java | 2 +- altosui/AltosFlightUI.java | 10 +- altosui/AltosGPS.java | 16 +- altosui/AltosGPSSat.java | 32 ++ altosui/AltosLog.java | 8 +- altosui/AltosPreferences.java | 2 +- altosui/AltosRecord.java | 11 + altosui/AltosSerial.java | 21 +- altosui/AltosTelemetry.java | 153 +-------- altosui/AltosTelemetryIterable.java | 4 +- altosui/AltosTelemetryReader.java | 6 +- altosui/AltosTelemetryRecord.java | 23 ++ altosui/AltosTelemetryRecordGeneral.java | 44 +++ altosui/AltosTelemetryRecordLegacy.java | 512 +++++++++++++++++++++++++++++++ altosui/AltosTelemetryRecordRaw.java | 135 ++++++++ altosui/AltosTelemetryRecordSensor.java | 64 ++++ altosui/Makefile.am | 6 + configure.ac | 2 +- 20 files changed, 948 insertions(+), 172 deletions(-) create mode 100644 altosui/AltosGPSSat.java create mode 100644 altosui/AltosTelemetryRecord.java create mode 100644 altosui/AltosTelemetryRecordGeneral.java create mode 100644 altosui/AltosTelemetryRecordLegacy.java create mode 100644 altosui/AltosTelemetryRecordRaw.java create mode 100644 altosui/AltosTelemetryRecordSensor.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 6a2d9b9b..25d97bcf 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -20,6 +20,7 @@ package altosui; import java.awt.*; import java.util.*; import java.text.*; +import java.nio.charset.Charset; import libaltosJNI.*; @@ -69,8 +70,11 @@ public class Altos { /* Telemetry modes */ static final int ao_telemetry_off = 0; - static final int ao_telemetry_full = 1; - static final int ao_telemetry_tiny = 2; + static final int ao_telemetry_legacy = 1; + static final int ao_telemetry_split = 2; + + static final int ao_telemetry_split_len = 32; + static final int ao_telemetry_legacy_len = 95; static HashMap string_to_state = new HashMap(); @@ -201,6 +205,66 @@ public class Altos { return -1; } + static int int8(int[] bytes, int i) { + return (int) (byte) bytes[i]; + } + + static int uint8(int[] bytes, int i) { + return bytes[i]; + } + + static int int16(int[] bytes, int i) { + return (int) (short) (bytes[i] + (bytes[i+1] << 8)); + } + + static int uint16(int[] bytes, int i) { + return bytes[i] + (bytes[i+1] << 8); + } + + static int uint32(int[] bytes, int i) { + return bytes[i] + + (bytes[i+1] << 8) + + (bytes[i+2] << 16) + + (bytes[i+3] << 24); + } + + static final Charset unicode_set = Charset.forName("UTF-8"); + + static String string(int[] bytes, int s, int l) { + byte[] b = new byte[bytes.length]; + for (int i = 0; i < l; i++) + b[i] = (byte) bytes[s+i]; + return new String(b, unicode_set); + } + + static int hexbyte(String s, int i) { + int c0, c1; + + if (s.length() < i + 2) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + c0 = s.charAt(i); + if (!Altos.ishex(c0)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); + c1 = s.charAt(i+1); + if (!Altos.ishex(c1)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); + return Altos.fromhex(c0) * 16 + Altos.fromhex(c1); + } + + static int[] hexbytes(String s) { + int n; + int[] r; + int i; + + if ((s.length() & 1) != 0) + throw new NumberFormatException(String.format("invalid line \"%s\"", s)); + n = s.length() / 2; + r = new int[n]; + for (i = 0; i < n; i++) + r[i] = Altos.hexbyte(s, i * 2); + return r; + } + static int fromdec(String s) throws NumberFormatException { int c, v = 0; int sign = 1; diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index 16349b88..812e5fc6 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -230,6 +230,7 @@ public class AltosEepromIterable extends AltosRecordIterable { case Altos.AO_LOG_SOFTWARE_VERSION: break; } + state.seen |= eeprom.seen; } LinkedList make_list() { diff --git a/altosui/AltosFile.java b/altosui/AltosFile.java index 06360572..2e33b271 100644 --- a/altosui/AltosFile.java +++ b/altosui/AltosFile.java @@ -38,7 +38,7 @@ class AltosFile extends File { extension); } - public AltosFile(AltosTelemetry telem) { + public AltosFile(AltosRecord telem) { this(telem.serial, telem.flight, "telem"); } } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index eb6c6d9d..5f1fc678 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -156,9 +156,13 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { // Telemetry format menu telemetries = new JComboBox(); - telemetries.addItem("TeleMetrum"); - telemetries.addItem("TeleMini/TeleNano"); - telemetries.setSelectedIndex(AltosPreferences.telemetry(serial) - 1); + telemetries.addItem("Legacy TeleMetrum"); + telemetries.addItem("Split Telemetry"); + int telemetry = 1; + telemetry = AltosPreferences.telemetry(serial); + if (telemetry > Altos.ao_telemetry_split) + telemetry = Altos.ao_telemetry_split; + telemetries.setSelectedIndex(telemetry - 1); telemetries.setMaximumRowCount(2); telemetries.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { diff --git a/altosui/AltosGPS.java b/altosui/AltosGPS.java index 0dbc8364..b5df7c9a 100644 --- a/altosui/AltosGPS.java +++ b/altosui/AltosGPS.java @@ -21,10 +21,6 @@ import java.lang.*; import java.text.*; public class AltosGPS { - public class AltosGPSSat { - int svid; - int c_n0; - } final static int MISSING = AltosRecord.MISSING; @@ -158,9 +154,9 @@ public class AltosGPS { else tracking_channels = AltosParse.parse_int(words[i]); i++; - cc_gps_sat = new AltosGPS.AltosGPSSat[tracking_channels]; + cc_gps_sat = new AltosGPSSat[tracking_channels]; for (int chan = 0; chan < tracking_channels; chan++) { - cc_gps_sat[chan] = new AltosGPS.AltosGPSSat(); + cc_gps_sat[chan] = new AltosGPSSat(); cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); /* Older versions included SiRF status bits */ if (version < 2) @@ -168,7 +164,7 @@ public class AltosGPS { cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); } } else - cc_gps_sat = new AltosGPS.AltosGPSSat[0]; + cc_gps_sat = new AltosGPSSat[0]; } public void set_latitude(int in_lat) { @@ -201,14 +197,14 @@ public class AltosGPS { public void add_sat(int svid, int c_n0) { if (cc_gps_sat == null) { - cc_gps_sat = new AltosGPS.AltosGPSSat[1]; + cc_gps_sat = new AltosGPSSat[1]; } else { - AltosGPSSat[] new_gps_sat = new AltosGPS.AltosGPSSat[cc_gps_sat.length + 1]; + AltosGPSSat[] new_gps_sat = new AltosGPSSat[cc_gps_sat.length + 1]; for (int i = 0; i < cc_gps_sat.length; i++) new_gps_sat[i] = cc_gps_sat[i]; cc_gps_sat = new_gps_sat; } - AltosGPS.AltosGPSSat sat = new AltosGPS.AltosGPSSat(); + AltosGPSSat sat = new AltosGPSSat(); sat.svid = svid; sat.c_n0 = c_n0; cc_gps_sat[cc_gps_sat.length - 1] = sat; diff --git a/altosui/AltosGPSSat.java b/altosui/AltosGPSSat.java new file mode 100644 index 00000000..fb125651 --- /dev/null +++ b/altosui/AltosGPSSat.java @@ -0,0 +1,32 @@ +/* + * 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 altosui; + +public class AltosGPSSat { + int svid; + int c_n0; + + public AltosGPSSat(int s, int c) { + svid = s; + c_n0= c; + } + + public AltosGPSSat() { + } +} + diff --git a/altosui/AltosLog.java b/altosui/AltosLog.java index dd147d21..64275f32 100644 --- a/altosui/AltosLog.java +++ b/altosui/AltosLog.java @@ -54,9 +54,10 @@ class AltosLog implements Runnable { } } - boolean open (AltosTelemetry telem) throws IOException { + boolean open (AltosRecord telem) throws IOException { AltosFile a = new AltosFile(telem); + System.out.printf("open %s\n", a.toString()); log_file = new FileWriter(a, true); if (log_file != null) { while (!pending_queue.isEmpty()) { @@ -74,18 +75,21 @@ class AltosLog implements Runnable { public void run () { try { + AltosRecord previous = null; for (;;) { AltosLine line = input_queue.take(); if (line.line == null) continue; try { - AltosTelemetry telem = new AltosTelemetry(line.line); + AltosRecord telem = AltosTelemetry.parse(line.line, previous); if (telem.serial != serial || telem.flight != flight || log_file == null) { close_log_file(); serial = telem.serial; flight = telem.flight; + System.out.printf("Opening telem %d %d\n", serial, flight); open(telem); } + previous = telem; } catch (ParseException pe) { } catch (AltosCRCException ce) { } diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index b1192be1..5029aff6 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -216,7 +216,7 @@ class AltosPreferences { if (telemetries.containsKey(serial)) return telemetries.get(serial); int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), - Altos.ao_telemetry_full); + Altos.ao_telemetry_split); telemetries.put(serial, telemetry); return telemetry; } diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index 200fffe5..8976edf0 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -25,6 +25,15 @@ import java.io.*; public class AltosRecord { final static int MISSING = 0x7fffffff; + static final int seen_flight = 1; + static final int seen_sensor = 2; + static final int seen_temp_volt = 4; + static final int seen_deploy = 8; + static final int seen_gps_time = 16; + static final int seen_gps_lat = 32; + static final int seen_gps_lon = 64; + int seen; + int version; String callsign; int serial; @@ -226,6 +235,7 @@ public class AltosRecord { public AltosRecord(AltosRecord old) { version = old.version; + seen = old.seen; callsign = old.callsign; serial = old.serial; flight = old.flight; @@ -254,6 +264,7 @@ public class AltosRecord { public AltosRecord() { version = 0; + seen = 0; callsign = "N0CALL"; serial = 0; flight = 0; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 6c80b66f..3666cb41 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -95,7 +95,7 @@ public class AltosSerial implements Runnable { } if (debug) System.out.printf("\t\t\t\t\t%s\n", line); - if (line.startsWith("VERSION") || line.startsWith("CRC")) { + if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { for (int e = 0; e < monitors.size(); e++) { LinkedBlockingQueue q = monitors.get(e); q.put(new AltosLine (line)); @@ -325,11 +325,22 @@ public class AltosSerial implements Runnable { set_callsign(AltosPreferences.callsign()); } + private int telemetry_len() { + switch (telemetry) { + case 1: + default: + return Altos.ao_telemetry_legacy_len; + case 2: + return Altos.ao_telemetry_split_len; + } + } + public void set_channel(int in_channel) { channel = in_channel; if (altos != null) { if (monitor_mode) - printf("m 0\nc r %d\nm %d\n", channel, telemetry); + printf("m 0\nc r %d\nm %x\n", + channel, telemetry_len()); else printf("c r %d\n", channel); flush_output(); @@ -340,7 +351,7 @@ public class AltosSerial implements Runnable { telemetry = in_telemetry; if (altos != null) { if (monitor_mode) - printf("m 0\nm %d\n", telemetry); + printf("m 0\nm %x\n", telemetry_len()); flush_output(); } } @@ -349,7 +360,7 @@ public class AltosSerial implements Runnable { monitor_mode = monitor; if (altos != null) { if (monitor) - printf("m %d\n", telemetry); + printf("m %x\n", telemetry_len()); else printf("m 0\n"); flush_output(); @@ -393,7 +404,7 @@ public class AltosSerial implements Runnable { line = ""; monitor_mode = false; frame = null; - telemetry = Altos.ao_telemetry_full; + telemetry = Altos.ao_telemetry_split; monitors = new LinkedList> (); reply_queue = new LinkedBlockingQueue (); open(); diff --git a/altosui/AltosTelemetry.java b/altosui/AltosTelemetry.java index 7d68b5b5..a05269f4 100644 --- a/altosui/AltosTelemetry.java +++ b/altosui/AltosTelemetry.java @@ -27,6 +27,10 @@ import java.util.HashMap; /* + * The packet format is a simple hex dump of the raw telemetry frame. + * It starts with 'TELEM', then contains hex digits with a checksum as the last + * byte on the line. + * * Version 4 is a replacement with consistent syntax. Each telemetry line * contains a sequence of space-separated names and values, the values are * either integers or strings. The names are all unique. All values are @@ -81,6 +85,7 @@ import java.util.HashMap; */ public class AltosTelemetry extends AltosRecord { + /* * General header fields * @@ -228,151 +233,9 @@ public class AltosTelemetry extends AltosRecord { final static String AO_TELEM_SAT_SVID = "s_v"; final static String AO_TELEM_SAT_C_N_0 = "s_c"; - private void parse_v4(String[] words, int i) throws ParseException { - AltosTelemetryMap map = new AltosTelemetryMap(words, i); - - callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); - serial = map.get_int(AO_TELEM_SERIAL, MISSING); - flight = map.get_int(AO_TELEM_FLIGHT, MISSING); - rssi = map.get_int(AO_TELEM_RSSI, MISSING); - state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); - tick = map.get_int(AO_TELEM_TICK, 0); - - /* raw sensor values */ - accel = map.get_int(AO_TELEM_RAW_ACCEL, MISSING); - pres = map.get_int(AO_TELEM_RAW_BARO, MISSING); - temp = map.get_int(AO_TELEM_RAW_THERMO, MISSING); - batt = map.get_int(AO_TELEM_RAW_BATT, MISSING); - drogue = map.get_int(AO_TELEM_RAW_DROGUE, MISSING); - main = map.get_int(AO_TELEM_RAW_MAIN, MISSING); - - /* sensor calibration information */ - ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, MISSING); - ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, MISSING); - accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, MISSING); - accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, MISSING); - - /* flight computer values */ - acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, MISSING, 1/16.0); - speed = map.get_double(AO_TELEM_KALMAN_SPEED, MISSING, 1/16.0); - height = map.get_int(AO_TELEM_KALMAN_HEIGHT, MISSING); - - flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, MISSING); - flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, MISSING); - flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, MISSING); - - if (map.has(AO_TELEM_GPS_STATE)) - gps = new AltosGPS(map); - else - gps = null; - } - - private void parse_legacy(String[] words, int i) throws ParseException { - - AltosParse.word (words[i++], "CALL"); - callsign = words[i++]; - - AltosParse.word (words[i++], "SERIAL"); - serial = AltosParse.parse_int(words[i++]); - - if (version >= 2) { - AltosParse.word (words[i++], "FLIGHT"); - flight = AltosParse.parse_int(words[i++]); - } else - flight = 0; - - AltosParse.word(words[i++], "RSSI"); - rssi = AltosParse.parse_int(words[i++]); - - /* Older telemetry data had mis-computed RSSI value */ - if (version <= 2) - rssi = (rssi + 74) / 2 - 74; - - AltosParse.word(words[i++], "STATUS"); - status = AltosParse.parse_hex(words[i++]); - - AltosParse.word(words[i++], "STATE"); - state = Altos.state(words[i++]); - - tick = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "a:"); - accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "p:"); - pres = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "t:"); - temp = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "v:"); - batt = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "d:"); - drogue = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "m:"); - main = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fa:"); - flight_accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "ga:"); - ground_accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fv:"); - flight_vel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fp:"); - flight_pres = AltosParse.parse_int(words[i++]); - - /* Old TeleDongle code with kalman-reporting TeleMetrum code */ - if ((flight_vel & 0xffff0000) == 0x80000000) { - speed = ((short) flight_vel) / 16.0; - acceleration = flight_accel / 16.0; - height = flight_pres; - flight_vel = MISSING; - flight_pres = MISSING; - flight_accel = MISSING; - } - - AltosParse.word(words[i++], "gp:"); - ground_pres = AltosParse.parse_int(words[i++]); - - if (version >= 1) { - AltosParse.word(words[i++], "a+:"); - accel_plus_g = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "a-:"); - accel_minus_g = AltosParse.parse_int(words[i++]); - } else { - accel_plus_g = ground_accel; - accel_minus_g = ground_accel + 530; - } - - gps = new AltosGPS(words, i, version); - } - - public AltosTelemetry(String line) throws ParseException, AltosCRCException { - String[] words = line.split("\\s+"); - int i = 0; - - if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(words[i++], "RSSI"); - rssi = AltosParse.parse_int(words[i++]); - throw new AltosCRCException(rssi); - } - if (words[i].equals("CALL")) { - version = 0; - } else { - AltosParse.word (words[i++], "VERSION"); - version = AltosParse.parse_int(words[i++]); - } + static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { + AltosTelemetryRecord r = AltosTelemetryRecordGeneral.parse(line); - if (version < 4) - parse_legacy(words, i); - else - parse_v4(words, i); + return r.update_state(previous); } } diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java index 44e5ad8f..90a08485 100644 --- a/altosui/AltosTelemetryIterable.java +++ b/altosui/AltosTelemetryIterable.java @@ -40,6 +40,7 @@ public class AltosTelemetryIterable extends AltosRecordIterable { int current_tick = 0; int boost_tick = 0; + AltosRecord previous = null; records = new LinkedList (); try { @@ -49,9 +50,10 @@ public class AltosTelemetryIterable extends AltosRecordIterable { break; } try { - AltosTelemetry record = new AltosTelemetry(line); + AltosRecord record = AltosTelemetry.parse(line, previous); if (record == null) break; + previous = record; if (records.isEmpty()) { current_tick = record.tick; } else { diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 980391b4..18f17841 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -26,6 +26,7 @@ class AltosTelemetryReader extends AltosFlightReader { AltosDevice device; AltosSerial serial; AltosLog log; + AltosRecord previous; LinkedBlockingQueue telem; @@ -33,7 +34,9 @@ class AltosTelemetryReader extends AltosFlightReader { AltosLine l = telem.take(); if (l.line == null) throw new IOException("IO error"); - return new AltosTelemetry(l.line); + AltosRecord next = AltosTelemetry.parse(l.line, previous); + previous = next; + return next; } void close(boolean interrupted) { @@ -58,6 +61,7 @@ class AltosTelemetryReader extends AltosFlightReader { serial = new AltosSerial(device); log = new AltosLog(serial); name = device.toShortString(); + previous = null; telem = new LinkedBlockingQueue(); serial.set_radio(); diff --git a/altosui/AltosTelemetryRecord.java b/altosui/AltosTelemetryRecord.java new file mode 100644 index 00000000..cfac309a --- /dev/null +++ b/altosui/AltosTelemetryRecord.java @@ -0,0 +1,23 @@ +/* + * 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 altosui; + +public interface AltosTelemetryRecord { + + public AltosRecord update_state(AltosRecord previous); +} diff --git a/altosui/AltosTelemetryRecordGeneral.java b/altosui/AltosTelemetryRecordGeneral.java new file mode 100644 index 00000000..55f6c495 --- /dev/null +++ b/altosui/AltosTelemetryRecordGeneral.java @@ -0,0 +1,44 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordGeneral { + + static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + String[] word = line.split("\\s+"); + int i =0; + if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(word[i++], "RSSI"); + throw new AltosCRCException(AltosParse.parse_int(word[i++])); + } + + System.out.printf("First word \"%s\"\n", word[i]); + if (word[i].equals("TELEM")) + r = AltosTelemetryRecordRaw.parse(word[i+1]); + else + r = new AltosTelemetryRecordLegacy(line); + return r; + } +} diff --git a/altosui/AltosTelemetryRecordLegacy.java b/altosui/AltosTelemetryRecordLegacy.java new file mode 100644 index 00000000..e3751ee7 --- /dev/null +++ b/altosui/AltosTelemetryRecordLegacy.java @@ -0,0 +1,512 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * The packet format is a simple hex dump of the raw telemetry frame. + * It starts with 'TELEM', then contains hex digits with a checksum as the last + * byte on the line. + * + * Version 4 is a replacement with consistent syntax. Each telemetry line + * contains a sequence of space-separated names and values, the values are + * either integers or strings. The names are all unique. All values are + * optional + * + * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 + * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 + * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 + * + * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 + * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 + * + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + * + * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports + * in 1/2dB increments while this protocol provides only integers. So, + * the syntax didn't change just the interpretation of the RSSI + * values. + * + * Version 2 of the telemetry data stream is a bit of a mess, with no + * consistent formatting. In particular, the GPS data is formatted for + * viewing instead of parsing. However, the key feature is that every + * telemetry line contains all of the information necessary to + * describe the current rocket state, including the calibration values + * for accelerometer and barometer. + * + * GPS unlocked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ + * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ + * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 + * + * GPS locked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ + * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ + * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ + * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ + * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ + * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 + * + */ + +public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTelemetryRecord { + /* + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + */ + + final static String AO_TELEM_VERSION = "VERSION"; + final static String AO_TELEM_CALL = "c"; + final static String AO_TELEM_SERIAL = "n"; + final static String AO_TELEM_FLIGHT = "f"; + final static String AO_TELEM_RSSI = "r"; + final static String AO_TELEM_STATE = "s"; + final static String AO_TELEM_TICK = "t"; + + /* + * Raw sensor values + * + * Name Value + * r_a Accelerometer reading (integer) + * r_b Barometer reading (integer) + * r_t Thermometer reading (integer) + * r_v Battery reading (integer) + * r_d Drogue continuity (integer) + * r_m Main continuity (integer) + */ + + final static String AO_TELEM_RAW_ACCEL = "r_a"; + final static String AO_TELEM_RAW_BARO = "r_b"; + final static String AO_TELEM_RAW_THERMO = "r_t"; + final static String AO_TELEM_RAW_BATT = "r_v"; + final static String AO_TELEM_RAW_DROGUE = "r_d"; + final static String AO_TELEM_RAW_MAIN = "r_m"; + + /* + * Sensor calibration values + * + * Name Value + * c_a Ground accelerometer reading (integer) + * c_b Ground barometer reading (integer) + * c_p Accelerometer reading for +1g + * c_m Accelerometer reading for -1g + */ + + final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; + final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; + final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; + final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; + + /* + * Kalman state values + * + * Name Value + * k_h Height above pad (integer, meters) + * k_s Vertical speeed (integer, m/s * 16) + * k_a Vertical acceleration (integer, m/s² * 16) + */ + + final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; + final static String AO_TELEM_KALMAN_SPEED = "k_s"; + final static String AO_TELEM_KALMAN_ACCEL = "k_a"; + + /* + * Ad-hoc flight values + * + * Name Value + * a_a Acceleration (integer, sensor units) + * a_s Speed (integer, integrated acceleration value) + * a_b Barometer reading (integer, sensor units) + */ + + final static String AO_TELEM_ADHOC_ACCEL = "a_a"; + final static String AO_TELEM_ADHOC_SPEED = "a_s"; + final static String AO_TELEM_ADHOC_BARO = "a_b"; + + /* + * GPS values + * + * Name Value + * g_s GPS state (string): + * l locked + * u unlocked + * e error (missing or broken) + * g_n Number of sats used in solution + * g_ns Latitude (degrees * 10e7) + * g_ew Longitude (degrees * 10e7) + * g_a Altitude (integer meters) + * g_Y GPS year (integer) + * g_M GPS month (integer - 1-12) + * g_D GPS day (integer - 1-31) + * g_h GPS hour (integer - 0-23) + * g_m GPS minute (integer - 0-59) + * g_s GPS second (integer - 0-59) + * g_v GPS vertical speed (integer, cm/sec) + * g_s GPS horizontal speed (integer, cm/sec) + * g_c GPS course (integer, 0-359) + * g_hd GPS hdop (integer * 10) + * g_vd GPS vdop (integer * 10) + * g_he GPS h error (integer) + * g_ve GPS v error (integer) + */ + + final static String AO_TELEM_GPS_STATE = "g"; + final static String AO_TELEM_GPS_STATE_LOCKED = "l"; + final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; + final static String AO_TELEM_GPS_STATE_ERROR = "e"; + final static String AO_TELEM_GPS_NUM_SAT = "g_n"; + final static String AO_TELEM_GPS_LATITUDE = "g_ns"; + final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; + final static String AO_TELEM_GPS_ALTITUDE = "g_a"; + final static String AO_TELEM_GPS_YEAR = "g_Y"; + final static String AO_TELEM_GPS_MONTH = "g_M"; + final static String AO_TELEM_GPS_DAY = "g_D"; + final static String AO_TELEM_GPS_HOUR = "g_h"; + final static String AO_TELEM_GPS_MINUTE = "g_m"; + final static String AO_TELEM_GPS_SECOND = "g_s"; + final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; + final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; + final static String AO_TELEM_GPS_COURSE = "g_c"; + final static String AO_TELEM_GPS_HDOP = "g_hd"; + final static String AO_TELEM_GPS_VDOP = "g_vd"; + final static String AO_TELEM_GPS_HERROR = "g_he"; + final static String AO_TELEM_GPS_VERROR = "g_ve"; + + /* + * GPS satellite values + * + * Name Value + * s_n Number of satellites reported (integer) + * s_v0 Space vehicle ID (integer) for report 0 + * s_c0 C/N0 number (integer) for report 0 + * s_v1 Space vehicle ID (integer) for report 1 + * s_c1 C/N0 number (integer) for report 1 + * ... + */ + + final static String AO_TELEM_SAT_NUM = "s_n"; + final static String AO_TELEM_SAT_SVID = "s_v"; + final static String AO_TELEM_SAT_C_N_0 = "s_c"; + + private void parse_v4(String[] words, int i) throws ParseException { + AltosTelemetryMap map = new AltosTelemetryMap(words, i); + + callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); + serial = map.get_int(AO_TELEM_SERIAL, MISSING); + flight = map.get_int(AO_TELEM_FLIGHT, MISSING); + rssi = map.get_int(AO_TELEM_RSSI, MISSING); + state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + tick = map.get_int(AO_TELEM_TICK, 0); + + /* raw sensor values */ + accel = map.get_int(AO_TELEM_RAW_ACCEL, MISSING); + pres = map.get_int(AO_TELEM_RAW_BARO, MISSING); + temp = map.get_int(AO_TELEM_RAW_THERMO, MISSING); + batt = map.get_int(AO_TELEM_RAW_BATT, MISSING); + drogue = map.get_int(AO_TELEM_RAW_DROGUE, MISSING); + main = map.get_int(AO_TELEM_RAW_MAIN, MISSING); + + /* sensor calibration information */ + ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, MISSING); + ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, MISSING); + accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, MISSING); + accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, MISSING); + + /* flight computer values */ + acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, MISSING, 1/16.0); + speed = map.get_double(AO_TELEM_KALMAN_SPEED, MISSING, 1/16.0); + height = map.get_int(AO_TELEM_KALMAN_HEIGHT, MISSING); + + flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, MISSING); + flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, MISSING); + flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, MISSING); + + if (map.has(AO_TELEM_GPS_STATE)) + gps = new AltosGPS(map); + else + gps = null; + } + + private void parse_legacy(String[] words, int i) throws ParseException { + + AltosParse.word (words[i++], "CALL"); + callsign = words[i++]; + + AltosParse.word (words[i++], "SERIAL"); + serial = AltosParse.parse_int(words[i++]); + + if (version >= 2) { + AltosParse.word (words[i++], "FLIGHT"); + flight = AltosParse.parse_int(words[i++]); + } else + flight = 0; + + AltosParse.word(words[i++], "RSSI"); + rssi = AltosParse.parse_int(words[i++]); + + /* Older telemetry data had mis-computed RSSI value */ + if (version <= 2) + rssi = (rssi + 74) / 2 - 74; + + AltosParse.word(words[i++], "STATUS"); + status = AltosParse.parse_hex(words[i++]); + + AltosParse.word(words[i++], "STATE"); + state = Altos.state(words[i++]); + + tick = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a:"); + accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "p:"); + pres = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "t:"); + temp = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "v:"); + batt = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "d:"); + drogue = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "m:"); + main = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fa:"); + flight_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "ga:"); + ground_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fv:"); + flight_vel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fp:"); + flight_pres = AltosParse.parse_int(words[i++]); + + /* Old TeleDongle code with kalman-reporting TeleMetrum code */ + if ((flight_vel & 0xffff0000) == 0x80000000) { + speed = ((short) flight_vel) / 16.0; + acceleration = flight_accel / 16.0; + height = flight_pres; + flight_vel = MISSING; + flight_pres = MISSING; + flight_accel = MISSING; + } + + AltosParse.word(words[i++], "gp:"); + ground_pres = AltosParse.parse_int(words[i++]); + + if (version >= 1) { + AltosParse.word(words[i++], "a+:"); + accel_plus_g = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a-:"); + accel_minus_g = AltosParse.parse_int(words[i++]); + } else { + accel_plus_g = ground_accel; + accel_minus_g = ground_accel + 530; + } + + gps = new AltosGPS(words, i, version); + } + + public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { + String[] words = line.split("\\s+"); + int i = 0; + + if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(words[i++], "RSSI"); + rssi = AltosParse.parse_int(words[i++]); + throw new AltosCRCException(rssi); + } + if (words[i].equals("CALL")) { + version = 0; + } else { + AltosParse.word (words[i++], "VERSION"); + version = AltosParse.parse_int(words[i++]); + } + + if (version < 4) + parse_legacy(words, i); + else + parse_v4(words, i); + } + + /* + * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that + */ + + int[] bytes; + + private int int8(int i) { + return Altos.int8(bytes, i + 1); + } + private int uint8(int i) { + return Altos.uint8(bytes, i + 1); + } + private int int16(int i) { + return Altos.int16(bytes, i + 1); + } + private int uint16(int i) { + return Altos.uint16(bytes, i + 1); + } + private int uint32(int i) { + return Altos.uint32(bytes, i + 1); + } + private String string(int i, int l) { + return Altos.string(bytes, i + 1, l); + } + + static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); + static final int AO_GPS_NUM_SAT_SHIFT = (0); + + static final int AO_GPS_VALID = (1 << 4); + static final int AO_GPS_RUNNING = (1 << 5); + static final int AO_GPS_DATE_VALID = (1 << 6); + static final int AO_GPS_COURSE_VALID = (1 << 7); + + static class theLock extends Object { + } + static public theLock lockObject = new theLock(); + public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { + bytes = in_bytes; + synchronized(lockObject) { + for (int i = 0; i < in_bytes.length - 2; i++) { + if ((i % 10) == 0) + System.out.printf("%3d:", i); + System.out.printf(" %02x", uint8(i)); + if ((i % 10) == 9 || i == in_bytes.length - 3) + System.out.printf("\n"); + } + } + version = 4; + callsign = string(62, 8); + serial = uint16(0); + flight = uint16(2); + rssi = in_rssi; + status = in_status; + state = uint8(4); + tick = uint16(21); + accel = int16(23); + pres = int16(25); + temp = int16(27); + batt = int16(29); + drogue = int16(31); + main = int16(33); + + ground_accel = int16(7); + ground_pres = int16(15); + accel_plus_g = int16(17); + accel_minus_g = int16(19); + + if (uint16(11) == 0x8000) { + acceleration = int16(5); + speed = int16(9); + height = int16(13); + flight_accel = MISSING; + flight_vel = MISSING; + flight_pres = MISSING; + } else { + flight_accel = int16(5); + flight_vel = uint32(9); + flight_pres = int16(13); + acceleration = MISSING; + speed = MISSING; + height = MISSING; + } + + gps = null; + + int gps_flags = uint8(41); + + if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { + gps = new AltosGPS(); + + gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); + gps.locked = (gps_flags & AO_GPS_VALID) != 0; + gps.connected = true; + gps.lat = uint32(42) / 1.0e7; + gps.lon = uint32(46) / 1.0e7; + gps.alt = int16(50); + gps.ground_speed = uint16(52) / 100.0; + gps.course = uint8(54) * 2; + gps.hdop = uint8(55) / 5.0; + gps.h_error = uint16(58); + gps.v_error = uint16(60); + + int n_tracking_reported = uint8(70); + if (n_tracking_reported > 12) + n_tracking_reported = 12; + int n_tracking_actual = 0; + for (int i = 0; i < n_tracking_reported; i++) { + if (uint8(71 + i*2) != 0) + n_tracking_actual++; + } + if (n_tracking_actual > 0) { + gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; + + n_tracking_actual = 0; + for (int i = 0; i < n_tracking_reported; i++) { + int svid = uint8(71 + i*2); + int c_n0 = uint8(72 + i*2); + if (svid != 0) + gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); + } + } + } + + time = 0.0; + } + + public AltosRecord update_state(AltosRecord previous) { + return this; + } +} diff --git a/altosui/AltosTelemetryRecordRaw.java b/altosui/AltosTelemetryRecordRaw.java new file mode 100644 index 00000000..35796a22 --- /dev/null +++ b/altosui/AltosTelemetryRecordRaw.java @@ -0,0 +1,135 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { + int[] bytes; + int serial; + int tick; + int type; + + final static int packet_type_TM_sensor = 0x01; + final static int packet_type_Tm_sensor = 0x02; + final static int packet_type_Tn_sensor = 0x03; + final static int packet_type_config = 0x04; + final static int packet_type_GPS_location = 0x05; + final static int packet_type_GPS_satellites = 0x06; + + final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); + final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); + final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; + + static boolean cksum(int[] bytes) { + int sum = 0x5a; + for (int i = 1; i < bytes.length - 1; i++) + sum += bytes[i]; + sum &= 0xff; + System.out.printf("%d bytes sum 0x%x last byte 0x%x\n", + bytes.length, sum, bytes[bytes.length - 1]); + return sum == bytes[bytes.length - 1]; + } + + public static AltosTelemetryRecord parse (String hex) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + int[] bytes; + try { + bytes = Altos.hexbytes(hex); + } catch (NumberFormatException ne) { + throw new ParseException(ne.getMessage(), 0); + } + + /* one for length, one for checksum */ + if (bytes[0] != bytes.length - 2) + throw new ParseException(String.format("invalid length %d != %d\n", + bytes[0], + bytes.length - 2), 0); + if (!cksum(bytes)) + throw new ParseException(String.format("invalid line \"%s\"", hex), 0); + + int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; + int status = Altos.uint8(bytes, bytes.length - 2); + + System.out.printf ("rssi 0x%x = %d status 0x%x\n", + Altos.uint8(bytes, bytes.length - 3), + rssi, status); + + if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) + throw new AltosCRCException(rssi); + + /* length, data ..., rssi, status, checksum -- 4 bytes extra */ + switch (bytes.length) { + case Altos.ao_telemetry_split_len + 4: + int type = Altos.uint8(bytes, 4 + 1); + switch (type) { + case packet_type_TM_sensor: + case packet_type_Tm_sensor: + case packet_type_Tn_sensor: + r = new AltosTelemetryRecordSensor(bytes); + break; + default: + r = new AltosTelemetryRecordRaw(bytes); + break; + } + case Altos.ao_telemetry_legacy_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + default: + throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); + } + return r; + } + + public int int8(int off) { + return Altos.int8(bytes, off + 1); + } + + public int uint8(int off) { + return Altos.uint8(bytes, off + 1); + } + + public int int16(int off) { + return Altos.int16(bytes, off + 1); + } + + public int uint16(int off) { + return Altos.uint16(bytes, off + 1); + } + + public int uint32(int off) { + return Altos.uint32(bytes, off + 1); + } + + public AltosTelemetryRecordRaw(int[] in_bytes) { + bytes = in_bytes; + serial = uint16(0); + tick = uint16(2); + type = uint8(4); + } + + public AltosRecord update_state(AltosRecord previous) { + if (previous != null) + return new AltosRecord(previous); + else + return new AltosRecord(); + } +} diff --git a/altosui/AltosTelemetryRecordSensor.java b/altosui/AltosTelemetryRecordSensor.java new file mode 100644 index 00000000..5ae9f891 --- /dev/null +++ b/altosui/AltosTelemetryRecordSensor.java @@ -0,0 +1,64 @@ +/* + * 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 altosui; + + +public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { + int state; + int accel; + int pres; + int temp; + int v_batt; + int sense_d; + int sense_m; + + int acceleration; + int speed; + int height; + + int ground_accel; + int ground_pres; + int accel_plus_g; + int accel_minus_g; + + public AltosTelemetryRecordSensor(int[] in_bytes) { + super(in_bytes); + state = uint8(5); + + accel = int16(6); + pres = int16(8); + temp = int16(10); + v_batt = int16(12); + sense_d = int16(14); + sense_m = int16(16); + + acceleration = int16(18); + speed = int16(20); + height = int16(22); + + ground_accel = int16(24); + ground_pres = int16(26); + accel_plus_g = int16(28); + accel_minus_g = int16(30); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + return next; + } +} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index f4d84ad2..6a4d9d17 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -51,6 +51,7 @@ altosui_JAVA = \ AltosFlightStatus.java \ AltosFlightUI.java \ AltosGPS.java \ + AltosGPSSat.java \ AltosGreatCircle.java \ AltosHexfile.java \ Altos.java \ @@ -70,6 +71,11 @@ altosui_JAVA = \ AltosRecord.java \ AltosRecordIterable.java \ AltosTelemetryReader.java \ + AltosTelemetryRecord.java \ + AltosTelemetryRecordGeneral.java \ + AltosTelemetryRecordRaw.java \ + AltosTelemetryRecordSensor.java \ + AltosTelemetryRecordLegacy.java \ AltosTelemetryMap.java \ AltosReplayReader.java \ AltosRomconfig.java \ diff --git a/configure.ac b/configure.ac index 32ef7d74..07d30717 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ dnl dnl Process this file with autoconf to create configure. AC_PREREQ(2.57) -AC_INIT([altos], 0.9.4) +AC_INIT([altos], 0.9.4.99) AC_CONFIG_SRCDIR([src/ao.h]) AM_INIT_AUTOMAKE([foreign dist-bzip2]) AM_MAINTAINER_MODE -- cgit v1.2.3 From 4132ac5896114e5f3d8fb3f219422e8933078cf4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Jul 2011 21:41:44 -0700 Subject: altosui: Parse remaining standard telemetry packets Signed-off-by: Keith Packard --- altosui/Altos.java | 15 ++++- altosui/AltosLog.java | 4 +- altosui/AltosRecord.java | 7 ++ altosui/AltosTelemetryRecordConfiguration.java | 64 ++++++++++++++++++ altosui/AltosTelemetryRecordGeneral.java | 1 - altosui/AltosTelemetryRecordLocation.java | 92 ++++++++++++++++++++++++++ altosui/AltosTelemetryRecordRaw.java | 36 ++++++---- altosui/AltosTelemetryRecordSatellite.java | 52 +++++++++++++++ altosui/AltosTelemetryRecordSensor.java | 47 ++++++++++++- altosui/Makefile.am | 3 + 10 files changed, 302 insertions(+), 19 deletions(-) create mode 100644 altosui/AltosTelemetryRecordConfiguration.java create mode 100644 altosui/AltosTelemetryRecordLocation.java create mode 100644 altosui/AltosTelemetryRecordSatellite.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 25d97bcf..37a4f67b 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -231,10 +231,21 @@ public class Altos { static final Charset unicode_set = Charset.forName("UTF-8"); static String string(int[] bytes, int s, int l) { - byte[] b = new byte[bytes.length]; + if (s + l > bytes.length) { + if (s > bytes.length) { + s = bytes.length; + l = 0; + } else { + l = bytes.length - s; + } + } + + byte[] b = new byte[l]; + for (int i = 0; i < l; i++) b[i] = (byte) bytes[s+i]; - return new String(b, unicode_set); + String n = new String(b, unicode_set); + return n; } static int hexbyte(String s, int i) { diff --git a/altosui/AltosLog.java b/altosui/AltosLog.java index 64275f32..855ee2b4 100644 --- a/altosui/AltosLog.java +++ b/altosui/AltosLog.java @@ -82,7 +82,9 @@ class AltosLog implements Runnable { continue; try { AltosRecord telem = AltosTelemetry.parse(line.line, previous); - if (telem.serial != serial || telem.flight != flight || log_file == null) { + if (telem.serial != 0 && telem.flight != 0 && + (telem.serial != serial || telem.flight != flight || log_file == null)) + { close_log_file(); serial = telem.serial; flight = telem.flight; diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index 8976edf0..144b1c3c 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -67,6 +67,13 @@ public class AltosRecord { double time; /* seconds since boost */ + int device_type; + int config_major; + int config_minor; + int apogee_delay; + int main_deploy; + int flight_log_max; + String firmware_version; /* * Values for our MP3H6115A pressure sensor * diff --git a/altosui/AltosTelemetryRecordConfiguration.java b/altosui/AltosTelemetryRecordConfiguration.java new file mode 100644 index 00000000..98dc6ab9 --- /dev/null +++ b/altosui/AltosTelemetryRecordConfiguration.java @@ -0,0 +1,64 @@ +/* + * 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 altosui; + + +public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { + int device_type; + int flight; + int config_major; + int config_minor; + int apogee_delay; + int main_deploy; + int flight_log_max; + String callsign; + String version; + + public AltosTelemetryRecordConfiguration(int[] in_bytes) { + super(in_bytes); + + device_type = uint8(5); + flight = uint16(6); + config_major = uint8(8); + config_minor = uint8(9); + apogee_delay = uint16(10); + main_deploy = uint16(12); + flight_log_max = uint16(14); + callsign = string(16, 8); + version = string(24, 8); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + next.device_type = device_type; + next.flight = flight; + next.config_major = config_major; + next.config_minor = config_minor; + next.apogee_delay = apogee_delay; + next.main_deploy = main_deploy; + next.flight_log_max = flight_log_max; + + next.callsign = callsign; + next.firmware_version = version; + + next.seen |= AltosRecord.seen_deploy; + + return next; + } +} diff --git a/altosui/AltosTelemetryRecordGeneral.java b/altosui/AltosTelemetryRecordGeneral.java index 55f6c495..722baba3 100644 --- a/altosui/AltosTelemetryRecordGeneral.java +++ b/altosui/AltosTelemetryRecordGeneral.java @@ -34,7 +34,6 @@ public class AltosTelemetryRecordGeneral { throw new AltosCRCException(AltosParse.parse_int(word[i++])); } - System.out.printf("First word \"%s\"\n", word[i]); if (word[i].equals("TELEM")) r = AltosTelemetryRecordRaw.parse(word[i+1]); else diff --git a/altosui/AltosTelemetryRecordLocation.java b/altosui/AltosTelemetryRecordLocation.java new file mode 100644 index 00000000..76bd106e --- /dev/null +++ b/altosui/AltosTelemetryRecordLocation.java @@ -0,0 +1,92 @@ +/* + * 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 altosui; + + +public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { + int flags; + int altitude; + int latitude; + int longitude; + int year; + int month; + int day; + int hour; + int minute; + int second; + int pdop; + int hdop; + int vdop; + int mode; + int ground_speed; + int climb_rate; + int course; + + public AltosTelemetryRecordLocation(int[] in_bytes) { + super(in_bytes); + + flags = uint8(5); + altitude = int16(6); + latitude = uint32(8); + longitude = uint32(12); + year = uint8(16); + month = uint8(17); + day = uint8(18); + hour = uint8(19); + minute = uint8(20); + second = uint8(21); + pdop = uint8(22); + hdop = uint8(23); + vdop = uint8(24); + mode = uint8(25); + ground_speed = uint16(26); + climb_rate = int16(28); + course = uint8(30); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + next.gps.nsat = flags & 0xf; + next.gps.locked = (flags & (1 << 4)) != 0; + next.gps.connected = (flags & (1 << 5)) != 0; + + if (next.gps.locked) { + next.gps.lat = latitude * 1.0e-7; + next.gps.lon = longitude * 1.0e-7; + next.gps.alt = altitude; + next.gps.year = 2000 + year; + next.gps.month = month; + next.gps.day = day; + next.gps.hour = hour; + next.gps.minute = minute; + next.gps.second = second; + next.gps.ground_speed = ground_speed * 1.0e-2; + next.gps.course = course * 2; + next.gps.climb_rate = climb_rate * 1.0e-2; + next.gps.hdop = hdop; + next.gps.vdop = vdop; + next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon; + } + + return next; + } +} diff --git a/altosui/AltosTelemetryRecordRaw.java b/altosui/AltosTelemetryRecordRaw.java index 35796a22..e6c4cfc8 100644 --- a/altosui/AltosTelemetryRecordRaw.java +++ b/altosui/AltosTelemetryRecordRaw.java @@ -30,9 +30,9 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { final static int packet_type_TM_sensor = 0x01; final static int packet_type_Tm_sensor = 0x02; final static int packet_type_Tn_sensor = 0x03; - final static int packet_type_config = 0x04; - final static int packet_type_GPS_location = 0x05; - final static int packet_type_GPS_satellites = 0x06; + final static int packet_type_configuration = 0x04; + final static int packet_type_location = 0x05; + final static int packet_type_satellite = 0x06; final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); @@ -43,8 +43,6 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { for (int i = 1; i < bytes.length - 1; i++) sum += bytes[i]; sum &= 0xff; - System.out.printf("%d bytes sum 0x%x last byte 0x%x\n", - bytes.length, sum, bytes[bytes.length - 1]); return sum == bytes[bytes.length - 1]; } @@ -69,10 +67,6 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; int status = Altos.uint8(bytes, bytes.length - 2); - System.out.printf ("rssi 0x%x = %d status 0x%x\n", - Altos.uint8(bytes, bytes.length - 3), - rssi, status); - if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) throw new AltosCRCException(rssi); @@ -84,12 +78,22 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { case packet_type_TM_sensor: case packet_type_Tm_sensor: case packet_type_Tn_sensor: - r = new AltosTelemetryRecordSensor(bytes); + r = new AltosTelemetryRecordSensor(bytes, rssi); + break; + case packet_type_configuration: + r = new AltosTelemetryRecordConfiguration(bytes); + break; + case packet_type_location: + r = new AltosTelemetryRecordLocation(bytes); + break; + case packet_type_satellite: + r = new AltosTelemetryRecordSatellite(bytes); break; default: r = new AltosTelemetryRecordRaw(bytes); break; } + break; case Altos.ao_telemetry_legacy_len + 4: r = new AltosTelemetryRecordLegacy(bytes, rssi, status); break; @@ -119,6 +123,10 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { return Altos.uint32(bytes, off + 1); } + public String string(int off, int l) { + return Altos.string(bytes, off + 1, l); + } + public AltosTelemetryRecordRaw(int[] in_bytes) { bytes = in_bytes; serial = uint16(0); @@ -127,9 +135,13 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { } public AltosRecord update_state(AltosRecord previous) { + AltosRecord next; if (previous != null) - return new AltosRecord(previous); + next = new AltosRecord(previous); else - return new AltosRecord(); + next = new AltosRecord(); + next.serial = serial; + next.tick = tick; + return next; } } diff --git a/altosui/AltosTelemetryRecordSatellite.java b/altosui/AltosTelemetryRecordSatellite.java new file mode 100644 index 00000000..2dd782ad --- /dev/null +++ b/altosui/AltosTelemetryRecordSatellite.java @@ -0,0 +1,52 @@ +/* + * 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 altosui; + +public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { + int channels; + AltosGPSSat[] sats; + + public AltosTelemetryRecordSatellite(int[] in_bytes) { + super(in_bytes); + + channels = uint8(5); + if (channels > 12) + channels = 12; + if (channels == 0) + sats = null; + else { + sats = new AltosGPSSat[channels]; + for (int i = 0; i < channels; i++) { + int svid = uint8(6 + i * 2 + 0); + int c_n_1 = uint8(6 + i * 2 + 1); + sats[i] = new AltosGPSSat(svid, c_n_1); + } + } + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + next.gps.cc_gps_sat = sats; + + return next; + } +} diff --git a/altosui/AltosTelemetryRecordSensor.java b/altosui/AltosTelemetryRecordSensor.java index 5ae9f891..3998437b 100644 --- a/altosui/AltosTelemetryRecordSensor.java +++ b/altosui/AltosTelemetryRecordSensor.java @@ -36,7 +36,9 @@ public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { int accel_plus_g; int accel_minus_g; - public AltosTelemetryRecordSensor(int[] in_bytes) { + int rssi; + + public AltosTelemetryRecordSensor(int[] in_bytes, int in_rssi) { super(in_bytes); state = uint8(5); @@ -51,14 +53,53 @@ public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { speed = int16(20); height = int16(22); - ground_accel = int16(24); - ground_pres = int16(26); + ground_pres = int16(24); + ground_accel = int16(26); accel_plus_g = int16(28); accel_minus_g = int16(30); + + rssi = in_rssi; } public AltosRecord update_state(AltosRecord previous) { AltosRecord next = super.update_state(previous); + + next.state = state; + if (type == packet_type_TM_sensor) + next.accel = accel; + else + next.accel = AltosRecord.MISSING; + next.pres = pres; + next.temp = temp; + next.batt = v_batt; + if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) { + next.drogue = sense_d; + next.main = sense_m; + } else { + next.drogue = AltosRecord.MISSING; + next.main = AltosRecord.MISSING; + } + + next.acceleration = acceleration / 16.0; + next.speed = speed / 16.0; + next.height = height; + + next.ground_pres = ground_pres; + if (type == packet_type_TM_sensor) { + next.ground_accel = ground_accel; + next.accel_plus_g = accel_plus_g; + next.accel_minus_g = accel_minus_g; + } else { + next.ground_accel = AltosRecord.MISSING; + next.accel_plus_g = AltosRecord.MISSING; + next.accel_minus_g = AltosRecord.MISSING; + } + + next.rssi = rssi; + + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + + System.out.printf("Sensor record update - rssi %d\n", rssi); return next; } } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 6a4d9d17..6e64acab 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -75,6 +75,9 @@ altosui_JAVA = \ AltosTelemetryRecordGeneral.java \ AltosTelemetryRecordRaw.java \ AltosTelemetryRecordSensor.java \ + AltosTelemetryRecordConfiguration.java \ + AltosTelemetryRecordLocation.java \ + AltosTelemetryRecordSatellite.java \ AltosTelemetryRecordLegacy.java \ AltosTelemetryMap.java \ AltosReplayReader.java \ -- cgit v1.2.3 From 72575dcb9cfbb5c1ccdb3510b9962a6f60ca3fa3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Jul 2011 23:35:50 -0700 Subject: altosui: Elide nul bytes at end of telemetry string values All telemetry fields are fixed length, so any embedded strings are padded with nul bytes. Signed-off-by: Keith Packard --- altosui/Altos.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 37a4f67b..36490844 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -240,9 +240,15 @@ public class Altos { } } + int i; + for (i = l - 1; i >= 0; i--) + if (bytes[s+i] != 0) + break; + + l = i + 1; byte[] b = new byte[l]; - for (int i = 0; i < l; i++) + for (i = 0; i < l; i++) b[i] = (byte) bytes[s+i]; String n = new String(b, unicode_set); return n; -- cgit v1.2.3 From c1f859170b37864b816eb561318dbfb1cafaeed6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Jul 2011 23:37:00 -0700 Subject: altosui: Elide missing values from graphs Signed-off-by: Keith Packard --- altosui/AltosGraphUI.java | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 4b994b47..942688d2 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -28,18 +28,23 @@ public class AltosGraphUI extends JFrame AltosGraphTime.Element height = new AltosGraphTime.TimeSeries("Height (m)", "Height (AGL)", red) { public void gotTimeData(double time, AltosDataPoint d) { - series.add(time, d.height()); + double height = d.height(); + if (height != AltosRecord.MISSING) + series.add(time, d.height()); } }; AltosGraphTime.Element speed = new AltosGraphTime.TimeSeries("Speed (m/s)", "Vertical Speed", green) { public void gotTimeData(double time, AltosDataPoint d) { + double speed; if (d.state() < Altos.ao_flight_drogue && d.has_accel()) { - series.add(time, d.accel_speed()); + speed = d.accel_speed(); } else { - series.add(time, d.baro_speed()); + speed = d.baro_speed(); } + if (speed != AltosRecord.MISSING) + series.add(time, speed); } }; @@ -48,7 +53,9 @@ public class AltosGraphUI extends JFrame "Axial Acceleration", blue) { public void gotTimeData(double time, AltosDataPoint d) { - series.add(time, d.acceleration()); + double acceleration = d.acceleration(); + if (acceleration != AltosRecord.MISSING) + series.add(time, acceleration); } }; @@ -57,7 +64,9 @@ public class AltosGraphUI extends JFrame "Board temperature", red) { public void gotTimeData(double time, AltosDataPoint d) { - series.add(time, d.temperature()); + double temp = d.temperature(); + if (temp != AltosRecord.MISSING) + series.add(time, d.temperature()); } }; @@ -65,7 +74,9 @@ public class AltosGraphUI extends JFrame new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", blue) { public void gotTimeData(double time, AltosDataPoint d) { - series.add(time, d.drogue_voltage()); + double v = d.drogue_voltage(); + if (v != AltosRecord.MISSING) + series.add(time, v); } }; @@ -73,7 +84,9 @@ public class AltosGraphUI extends JFrame new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", green) { public void gotTimeData(double time, AltosDataPoint d) { - series.add(time, d.main_voltage()); + double v = d.main_voltage(); + if (v != AltosRecord.MISSING) + series.add(time, v); } }; -- cgit v1.2.3 From d0335f83c54df0b23c28d04d34c212a1bdffadd0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Jul 2011 23:37:51 -0700 Subject: altosui: Add main/drogue voltages to default graph Until we get a UI for changing the graph elements, lets add a few more potentially useful values. Signed-off-by: Keith Packard --- altosui/AltosGraphUI.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 942688d2..03aae652 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -112,7 +112,9 @@ public class AltosGraphUI extends JFrame graphs.add( myAltosGraphTime("Summary") .addElement(height) .addElement(speed) - .addElement(acceleration) ); + .addElement(acceleration) + .addElement(drogue_voltage) + .addElement(main_voltage) ); graphs.add( myAltosGraphTime("Summary") .addElement(height) -- cgit v1.2.3 From 7cfd43663cde5ebdf04e4face076d79ff6329ac3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Jul 2011 23:38:28 -0700 Subject: altosui: Remove debug printf. Signed-off-by: Keith Packard --- altosui/AltosTelemetryRecordSensor.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosTelemetryRecordSensor.java b/altosui/AltosTelemetryRecordSensor.java index 3998437b..96fee81f 100644 --- a/altosui/AltosTelemetryRecordSensor.java +++ b/altosui/AltosTelemetryRecordSensor.java @@ -99,7 +99,6 @@ public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; - System.out.printf("Sensor record update - rssi %d\n", rssi); return next; } } -- cgit v1.2.3 From 481577a29380afe6750ef7c4e928daff837cbc49 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Jul 2011 23:38:42 -0700 Subject: altosui: Compress telemetry records marked with the same time Split telemetry transmits multiple packets with the same timestamp. Merge those into a single record when read from a file. Signed-off-by: Keith Packard --- altosui/AltosTelemetryIterable.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java index 90a08485..1a31b365 100644 --- a/altosui/AltosTelemetryIterable.java +++ b/altosui/AltosTelemetryIterable.java @@ -53,7 +53,6 @@ public class AltosTelemetryIterable extends AltosRecordIterable { AltosRecord record = AltosTelemetry.parse(line, previous); if (record == null) break; - previous = record; if (records.isEmpty()) { current_tick = record.tick; } else { @@ -74,7 +73,9 @@ public class AltosTelemetryIterable extends AltosRecordIterable { has_gps = true; if (record.main != AltosRecord.MISSING) has_ignite = true; - records.add(record); + if (previous != null && previous.tick != record.tick) + records.add(previous); + previous = record; } catch (ParseException pe) { System.out.printf("parse exception %s\n", pe.getMessage()); } catch (AltosCRCException ce) { @@ -84,6 +85,9 @@ public class AltosTelemetryIterable extends AltosRecordIterable { System.out.printf("io exception\n"); } + if (previous != null) + records.add(previous); + /* adjust all tick counts to be relative to boost time */ for (AltosRecord r : this) r.time = (r.tick - boost_tick) / 100.0; -- cgit v1.2.3 From 80ca066a825646f833ca609190c76c5252118d9a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 6 Jul 2011 21:36:38 -0700 Subject: altosui: Build device constants into .java code This eliminates a depedency on updates to the system helper library, which means we don't have to provide a new library on all platforms just to support a new USB id. Signed-off-by: Keith Packard --- altosui/Altos.java | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 36490844..96263797 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -324,50 +324,42 @@ public class Altos { } static int usb_vendor_altusmetrum() { - if (load_library()) - return libaltosConstants.USB_VENDOR_ALTUSMETRUM; - return 0x000a; + load_library(); + return 0xfffe; } static int usb_product_altusmetrum() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_ALTUSMETRUM; + load_library(); return 0x000a; } static int usb_product_altusmetrum_min() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MIN; + load_library(); return 0x000a; } static int usb_product_altusmetrum_max() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MAX; - return 0x000d; + load_library(); + return 0x0013; } static int usb_product_telemetrum() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_TELEMETRUM; + load_library(); return 0x000b; } static int usb_product_teledongle() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_TELEDONGLE; + load_library(); return 0x000c; } static int usb_product_teleterra() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_TELETERRA; + load_library(); return 0x000d; } static int usb_product_telebt() { - if (load_library()) - return libaltosConstants.USB_PRODUCT_TELEBT; + load_library(); return 0x000e; } @@ -384,8 +376,7 @@ public class Altos { public final static int product_basestation = 0x10000 + 1; static String bt_product_telebt() { - if (load_library()) - return libaltosConstants.BLUETOOTH_PRODUCT_TELEBT; + load_library(); return "TeleBT"; } -- cgit v1.2.3 From 8f80f5705d64469bcfb00ff11aee68364edb271b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 6 Jul 2011 21:38:57 -0700 Subject: altosui: Don't show missing igniter and gps values The new telemetry stuff leaves state.gps always set (but empty), which seems fine, we just need to look at state.gps.connected to see if there's a GPS receiver on board. For TeleNano, we also want to hide the igniter status fields as they won't have any data present. Signed-off-by: Keith Packard --- altosui/AltosAscent.java | 41 +++++++++++++++++++++++++++++++++-------- altosui/AltosDescent.java | 17 ++++++++++++----- altosui/AltosFlightUI.java | 4 ++-- altosui/AltosInfoTable.java | 8 +++++--- altosui/AltosLanded.java | 6 +++--- altosui/AltosPad.java | 14 +++++++++++--- 6 files changed, 66 insertions(+), 24 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index 8a4aa58b..d607b0c5 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -36,6 +36,18 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { JTextField value; AltosLights lights; + void show() { + value.setVisible(true); + lights.setVisible(true); + label.setVisible(true); + } + + void hide() { + value.setVisible(false); + lights.setVisible(false); + label.setVisible(false); + } + void show(AltosState state, int crc_errors) {} void reset() { value.setText(""); @@ -136,14 +148,19 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { void reset() { value.setText(""); max_value.setText(""); - max = 0; + max = AltosRecord.MISSING; } void show(String format, double v) { - value.setText(String.format(format, v)); - if (v > max) { - max_value.setText(String.format(format, v)); - max = v; + if (v == AltosRecord.MISSING) { + value.setText("Missing"); + max_value.setText("Missing"); + } else { + value.setText(String.format(format, v)); + if (v > max || max == AltosRecord.MISSING) { + max_value.setText(String.format(format, v)); + max = v; + } } } public AscentValueHold (GridBagLayout layout, int y, String text) { @@ -233,6 +250,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { class Apogee extends AscentStatus { void show (AltosState state, int crc_errors) { + show(); value.setText(String.format("%4.2f V", state.drogue_sense)); lights.set(state.drogue_sense > 3.2); } @@ -245,6 +263,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { class Main extends AscentStatus { void show (AltosState state, int crc_errors) { + show(); value.setText(String.format("%4.2f V", state.main_sense)); lights.set(state.main_sense > 3.2); } @@ -296,7 +315,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { } public void show(AltosState state, int crc_errors) { - if (state.gps != null) { + if (state.gps != null && state.gps.connected) { lat.show(state, crc_errors); lon.show(state, crc_errors); } else { @@ -304,8 +323,14 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { lon.hide(); } height.show(state, crc_errors); - main.show(state, crc_errors); - apogee.show(state, crc_errors); + if (state.main_sense != AltosRecord.MISSING) + main.show(state, crc_errors); + else + main.hide(); + if (state.drogue_sense != AltosRecord.MISSING) + apogee.show(state, crc_errors); + else + apogee.hide(); speed.show(state, crc_errors); accel.show(state, crc_errors); } diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index addd6878..2a9e7eef 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -258,7 +258,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { class Lat extends DescentValue { void show (AltosState state, int crc_errors) { - if (state.gps != null) + if (state.gps != null && state.gps.connected) show(pos(state.gps.lat,"N", "S")); else show("???"); @@ -272,7 +272,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { class Lon extends DescentValue { void show (AltosState state, int crc_errors) { - if (state.gps != null) + if (state.gps != null && state.gps.connected) show(pos(state.gps.lon,"W", "E")); else show("???"); @@ -286,6 +286,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { class Apogee extends DescentStatus { void show (AltosState state, int crc_errors) { + show(); value.setText(String.format("%4.2f V", state.drogue_sense)); lights.set(state.drogue_sense > 3.2); } @@ -363,7 +364,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { public void show(AltosState state, int crc_errors) { height.show(state, crc_errors); speed.show(state, crc_errors); - if (state.gps != null) { + if (state.gps != null && state.gps.connected) { bearing.show(state, crc_errors); range.show(state, crc_errors); elevation.show(state, crc_errors); @@ -376,8 +377,14 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { lat.hide(); lon.hide(); } - main.show(state, crc_errors); - apogee.show(state, crc_errors); + if (state.main_sense != AltosRecord.MISSING) + main.show(state, crc_errors); + else + main.hide(); + if (state.drogue_sense != AltosRecord.MISSING) + apogee.show(state, crc_errors); + else + apogee.hide(); } public AltosDescent() { diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 5f1fc678..9536c4bb 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -156,8 +156,8 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { // Telemetry format menu telemetries = new JComboBox(); - telemetries.addItem("Legacy TeleMetrum"); - telemetries.addItem("Split Telemetry"); + telemetries.addItem("Original TeleMetrum Telemetry"); + telemetries.addItem("Standard AltOS Telemetry"); int telemetry = 1; telemetry = AltosPreferences.telemetry(serial); if (telemetry > Altos.ao_telemetry_split) diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java index 723f8301..8ebeaba1 100644 --- a/altosui/AltosInfoTable.java +++ b/altosui/AltosInfoTable.java @@ -107,10 +107,12 @@ public class AltosInfoTable extends JTable { info_add_row(0, "Max Speed", "%8.1f m/s", state.max_speed); info_add_row(0, "Temperature", "%9.2f °C", state.temperature); info_add_row(0, "Battery", "%9.2f V", state.battery); - info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense); - info_add_row(0, "Main", "%9.2f V", state.main_sense); + if (state.drogue_sense != AltosRecord.MISSING) + info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense); + if (state.main_sense != AltosRecord.MISSING) + info_add_row(0, "Main", "%9.2f V", state.main_sense); info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude); - if (state.gps == null) { + if (state.gps == null || !state.gps.connected) { info_add_row(1, "GPS", "not available"); } else { if (state.gps_ready) diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 63a2daf6..d5c8e434 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -99,7 +99,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { class Lat extends LandedValue { void show (AltosState state, int crc_errors) { show(); - if (state.gps != null) + if (state.gps != null && state.gps.connected) value.setText(pos(state.gps.lat,"N", "S")); else value.setText("???"); @@ -114,7 +114,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { class Lon extends LandedValue { void show (AltosState state, int crc_errors) { show(); - if (state.gps != null) + if (state.gps != null && state.gps.connected) value.setText(pos(state.gps.lon,"E", "W")); else value.setText("???"); @@ -200,7 +200,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { } public void show(AltosState state, int crc_errors) { - if (state.gps != null) { + if (state.gps != null && state.gps.connected) { bearing.show(state, crc_errors); distance.show(state, crc_errors); lat.show(state, crc_errors); diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index 2d800e8a..d08925be 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -149,6 +149,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { class Apogee extends LaunchStatus { void show (AltosState state, int crc_errors) { + show(); value.setText(String.format("%4.2f V", state.drogue_sense)); lights.set(state.drogue_sense > 3.2); } @@ -161,6 +162,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { class Main extends LaunchStatus { void show (AltosState state, int crc_errors) { + show(); value.setText(String.format("%4.2f V", state.main_sense)); lights.set(state.main_sense > 3.2); } @@ -259,10 +261,16 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { public void show(AltosState state, int crc_errors) { battery.show(state, crc_errors); - apogee.show(state, crc_errors); - main.show(state, crc_errors); + if (state.drogue_sense == AltosRecord.MISSING) + apogee.hide(); + else + apogee.show(state, crc_errors); + if (state.main_sense == AltosRecord.MISSING) + main.hide(); + else + main.show(state, crc_errors); pad_alt.show(state, crc_errors); - if (state.gps != null) { + if (state.gps != null && state.gps.connected) { gps_locked.show(state, crc_errors); gps_ready.show(state, crc_errors); pad_lat.show(state, crc_errors); -- cgit v1.2.3 From 8c20030ea4eb8e068e1ba88e01d07dfbc27bd7db Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 9 Jul 2011 18:41:15 -0700 Subject: altosui: Start adding support for scanning radio for available devices This is untested. Signed-off-by: Keith Packard --- altosui/AltosScanUI.java | 365 +++++++++++++++++++++++++++++++++++++++++++++++ altosui/AltosUI.java | 12 ++ altosui/Makefile.am | 1 + 3 files changed, 378 insertions(+) create mode 100644 altosui/AltosScanUI.java (limited to 'altosui') diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java new file mode 100644 index 00000000..e55f317c --- /dev/null +++ b/altosui/AltosScanUI.java @@ -0,0 +1,365 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosScanResult { + String callsign; + int serial; + int flight; + int channel; + int telemetry; + boolean interrupted = false; + + public String toString() { + return String.format("%-9.9s %4d %4d %2d %2d", + callsign, serial, flight, channel, telemetry); + } + + public String toShortString() { + return String.format("%s %d %d %d %d", + callsign, serial, flight, channel, telemetry); + } + + public AltosScanResult(String in_callsign, int in_serial, + int in_flight, int in_channel, int in_telemetry) { + callsign = in_callsign; + serial = in_serial; + flight = in_flight; + channel = in_channel; + telemetry = in_telemetry; + } + + public boolean equals(AltosScanResult other) { + return (callsign.equals(other.callsign) && + serial == other.serial && + flight == other.flight && + channel == other.channel && + telemetry == other.telemetry); + } +} + +class AltosScanResults extends LinkedList implements ListModel { + + LinkedList listeners = new LinkedList(); + + public boolean add(AltosScanResult r) { + for (AltosScanResult old : this) + if (old.equals(r)) + return true; + + super.add(r); + ListDataEvent de = new ListDataEvent(this, + ListDataEvent.INTERVAL_ADDED, + this.size() - 2, this.size() - 1); + for (ListDataListener l : listeners) + l.contentsChanged(de); + return true; + } + + public void addListDataListener(ListDataListener l) { + listeners.add(l); + } + + public void removeListDataListener(ListDataListener l) { + listeners.remove(l); + } + + public AltosScanResult getElementAt(int i) { + return this.get(i); + } + + public int getSize() { + return this.size(); + } +} + +public class AltosScanUI + extends JDialog + implements ActionListener +{ + JFrame owner; + AltosDevice device; + AltosTelemetryReader reader; + private JList list; + private JLabel channel_label; + private JLabel monitor_label; + private JButton ok_button; + javax.swing.Timer timer; + AltosScanResults results = new AltosScanResults(); + + static final int[] monitors = { Altos.ao_telemetry_split_len, + Altos.ao_telemetry_legacy_len }; + int monitor; + int channel; + + final static int timeout = 5 * 1000; + TelemetryHandler handler; + Thread thread; + + void scan_exception(Exception e) { + if (e instanceof FileNotFoundException) { + JOptionPane.showMessageDialog(owner, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } else if (e instanceof AltosSerialInUseException) { + JOptionPane.showMessageDialog(owner, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } else if (e instanceof IOException) { + IOException ee = (IOException) e; + JOptionPane.showMessageDialog(owner, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } else { + JOptionPane.showMessageDialog(owner, + String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); + } + close(); + } + + class TelemetryHandler implements Runnable { + + public void run() { + + boolean interrupted = false; + + try { + for (;;) { + try { + AltosRecord record = reader.read(); + if (record == null) + break; + if ((record.seen & AltosRecord.seen_flight) != 0) { + AltosScanResult result = new AltosScanResult(record.callsign, + record.serial, + record.flight, + channel, + monitor); + results.add(result); + } + } catch (ParseException pp) { + System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); + } catch (AltosCRCException ce) { + } + } + } catch (InterruptedException ee) { + interrupted = true; + } catch (IOException ie) { + } finally { + reader.close(interrupted); + } + } + } + + void set_channel() { + reader.serial.set_channel(channel); + } + + void set_monitor() { + reader.serial.set_telemetry(monitors[monitor]); + } + + void next() { + ++channel; + if (channel == 10) { + channel = 0; + ++monitor; + if (monitor == monitors.length) + monitor = 0; + set_monitor(); + } + set_channel(); + } + + + void close() { + if (thread != null && thread.isAlive()) { + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException ie) {} + } + thread = null; + if (timer != null) + timer.stop(); + setVisible(false); + dispose(); + } + + void tick_timer() { + next(); + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if (cmd.equals("close")) { + close(); + } + } + + /* A window listener to catch closing events and tell the config code */ + class ConfigListener extends WindowAdapter { + AltosScanUI ui; + + public ConfigListener(AltosScanUI this_ui) { + ui = this_ui; + } + + public void windowClosing(WindowEvent e) { + ui.actionPerformed(new ActionEvent(e.getSource(), + ActionEvent.ACTION_PERFORMED, + "close")); + } + } + + private boolean open() { + device = AltosDeviceDialog.show(owner, Altos.product_any); + if (device != null) { + try { + reader = new AltosTelemetryReader(device); + set_channel(); + set_monitor(); + handler = new TelemetryHandler(); + thread = new Thread(handler); + thread.start(); + return true; + } catch (Exception e) { + scan_exception(e); + } + } + return false; + } + + public AltosScanUI(JFrame in_owner) { + + owner = in_owner; + + if (!open()) + return; + + Container pane = getContentPane(); + GridBagConstraints c = new GridBagConstraints(); + Insets i = new Insets(4,4,4,4); + + timer = new javax.swing.Timer(timeout, this); + timer.setActionCommand("tick"); + timer.restart(); + + owner = in_owner; + + pane.setLayout(new GridBagLayout()); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + + list = new JList(results) { + //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)); + + pane.add(listPane, c); + + pack(); + setLocationRelativeTo(owner); + + addWindowListener(new ConfigListener(this)); + } +} \ No newline at end of file diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 7bb4ba12..6a24d8a9 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -172,6 +172,14 @@ public class AltosUI extends JFrame { } }); + + b = addButton(0, 2, "Scan Channels"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ScanChannels(); + } + }); + setTitle("AltOS"); pane.doLayout(); @@ -226,6 +234,10 @@ public class AltosUI extends JFrame { new AltosIgniteUI(AltosUI.this); } + void ScanChannels() { + new AltosScanUI(AltosUI.this); + } + /* * Replay a flight from telemetry data */ diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 6e64acab..0a3ed0b1 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -83,6 +83,7 @@ altosui_JAVA = \ AltosReplayReader.java \ AltosRomconfig.java \ AltosRomconfigUI.java \ + AltosScanUI.java \ AltosSerial.java \ AltosSerialInUseException.java \ AltosSerialMonitor.java \ -- cgit v1.2.3 From f32a55ac9a3ebbde2b41782f22491e72258fe05a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 9 Jul 2011 19:00:12 -0700 Subject: altosui: Pop up monitor window from scan dialog Signed-off-by: Keith Packard --- altosui/AltosScanUI.java | 120 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 23 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index e55f317c..01b01720 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -35,6 +35,7 @@ class AltosScanResult { int flight; int channel; int telemetry; + boolean interrupted = false; public String toString() { @@ -104,12 +105,14 @@ public class AltosScanUI extends JDialog implements ActionListener { - JFrame owner; + AltosUI owner; AltosDevice device; AltosTelemetryReader reader; private JList list; private JLabel channel_label; private JLabel monitor_label; + private JButton fake_button; + private JButton cancel_button; private JButton ok_button; javax.swing.Timer timer; AltosScanResults results = new AltosScanResults(); @@ -228,8 +231,26 @@ public class AltosScanUI public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); - if (cmd.equals("close")) { + if (cmd.equals("fake")) { + results.add(new AltosScanResult("N0CALL", 300, 1, 0, 1)); + } + + if (cmd.equals("cancel")) { + close(); + } + + if (cmd.equals("ok")) { close(); + AltosScanResult r = (AltosScanResult) (list.getSelectedValue()); + System.out.printf("Selected channel %d telemetry %d\n", + r.channel, r.telemetry); + if (device != null) { + if (reader != null) { + reader.set_telemetry(r.telemetry); + reader.set_channel(r.channel); + owner.telemetry_window(device); + } + } } } @@ -266,12 +287,12 @@ public class AltosScanUI return false; } - public AltosScanUI(JFrame in_owner) { + public AltosScanUI(AltosUI in_owner) { owner = in_owner; - if (!open()) - return; +// if (!open()) +// return; Container pane = getContentPane(); GridBagConstraints c = new GridBagConstraints(); @@ -285,17 +306,6 @@ public class AltosScanUI pane.setLayout(new GridBagLayout()); - c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.CENTER; - c.insets = i; - c.weightx = 1; - c.weighty = 1; - - c.gridx = 0; - c.gridy = 0; - c.gridwidth = 3; - c.anchor = GridBagConstraints.CENTER; - list = new JList(results) { //Subclass JList to workaround bug 4832765, which can cause the //scroll pane to not let the user easily scroll up to the beginning @@ -330,13 +340,13 @@ public class AltosScanUI 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 -// } -// } -// }); + list.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + ok_button.doClick(); //emulate button click + } + } + }); JScrollPane listScroller = new JScrollPane(list); listScroller.setPreferredSize(new Dimension(400, 80)); listScroller.setAlignmentX(LEFT_ALIGNMENT); @@ -355,11 +365,75 @@ public class AltosScanUI listPane.add(listScroller); listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 3; + c.anchor = GridBagConstraints.CENTER; + pane.add(listPane, c); + fake_button = new JButton("fake"); + fake_button.addActionListener(this); + fake_button.setActionCommand("fake"); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + + pane.add(fake_button, c); + + cancel_button = new JButton("Cancel"); + cancel_button.addActionListener(this); + cancel_button.setActionCommand("cancel"); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + + pane.add(cancel_button, c); + + ok_button = new JButton("OK"); + ok_button.addActionListener(this); + ok_button.setActionCommand("ok"); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 2; + c.gridy = 1; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + + pane.add(ok_button, c); + pack(); setLocationRelativeTo(owner); addWindowListener(new ConfigListener(this)); + + setVisible(true); } } \ No newline at end of file -- cgit v1.2.3 From d4375bc737655546c2d40f49acdfc2e60ebfea5a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 14:19:14 -0700 Subject: altosui: Remove debugging printf from AltosLog Signed-off-by: Keith Packard --- altosui/AltosLog.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosLog.java b/altosui/AltosLog.java index 855ee2b4..6157a656 100644 --- a/altosui/AltosLog.java +++ b/altosui/AltosLog.java @@ -88,7 +88,6 @@ class AltosLog implements Runnable { close_log_file(); serial = telem.serial; flight = telem.flight; - System.out.printf("Opening telem %d %d\n", serial, flight); open(telem); } previous = telem; -- cgit v1.2.3 From ebcba28b3c09925869b617880d2919e5d0e059f0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 14:19:41 -0700 Subject: altosui: Configuration telemetry record includes flight number Mark the reported altos record as including flight information. Signed-off-by: Keith Packard --- altosui/AltosTelemetryRecordConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosTelemetryRecordConfiguration.java b/altosui/AltosTelemetryRecordConfiguration.java index 98dc6ab9..b029d120 100644 --- a/altosui/AltosTelemetryRecordConfiguration.java +++ b/altosui/AltosTelemetryRecordConfiguration.java @@ -57,7 +57,7 @@ public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { next.callsign = callsign; next.firmware_version = version; - next.seen |= AltosRecord.seen_deploy; + next.seen |= AltosRecord.seen_deploy | AltosRecord.seen_flight; return next; } -- cgit v1.2.3 From 7ef786276b5d5c7d17c3fe4f36aa41db61a9742f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 14:23:08 -0700 Subject: altosui: Finish radio scanning UI Scans all channels and telemetry formats, presenting visible devices in a list. Entries from the list may be selected, in which case a monitor window pops up with the appropriate configuration. Signed-off-by: Keith Packard --- altosui/AltosScanUI.java | 183 ++++++++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 80 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 01b01720..d94ac3ae 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -35,12 +35,13 @@ class AltosScanResult { int flight; int channel; int telemetry; + static final String[] short_monitor_names = { "Standard", "Original" }; boolean interrupted = false; public String toString() { - return String.format("%-9.9s %4d %4d %2d %2d", - callsign, serial, flight, channel, telemetry); + return String.format("%-9.9s serial %-4d flight %-4d (channel %-2d telemetry %s)", + callsign, serial, flight, channel, short_monitor_names[telemetry]); } public String toShortString() { @@ -109,20 +110,18 @@ public class AltosScanUI AltosDevice device; AltosTelemetryReader reader; private JList list; - private JLabel channel_label; - private JLabel monitor_label; - private JButton fake_button; + private JLabel scanning_label; private JButton cancel_button; - private JButton ok_button; + private JButton monitor_button; javax.swing.Timer timer; AltosScanResults results = new AltosScanResults(); - static final int[] monitors = { Altos.ao_telemetry_split_len, - Altos.ao_telemetry_legacy_len }; + static final String[] monitor_names = { "Standard AltOS Telemetry", "Original TeleMetrum Telemetry" }; + static final int[] monitors = { 2, 1 }; int monitor; int channel; - final static int timeout = 5 * 1000; + final static int timeout = 1200; TelemetryHandler handler; Thread thread; @@ -166,17 +165,21 @@ public class AltosScanUI try { AltosRecord record = reader.read(); if (record == null) - break; + continue; if ((record.seen & AltosRecord.seen_flight) != 0) { - AltosScanResult result = new AltosScanResult(record.callsign, + final AltosScanResult result = new AltosScanResult(record.callsign, record.serial, record.flight, channel, monitor); - results.add(result); + Runnable r = new Runnable() { + public void run() { + results.add(result); + } + }; + SwingUtilities.invokeLater(r); } } catch (ParseException pp) { - System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); } catch (AltosCRCException ce) { } } @@ -189,24 +192,29 @@ public class AltosScanUI } } - void set_channel() { - reader.serial.set_channel(channel); - } - - void set_monitor() { - reader.serial.set_telemetry(monitors[monitor]); + void set_label() { + scanning_label.setText(String.format("Scanning: channel %d %s", + channel, + monitor_names[monitor])); } void next() { + reader.serial.set_monitor(false); + try { + Thread.sleep(100); + } catch (InterruptedException ie){ + } ++channel; - if (channel == 10) { + if (channel > 9) { channel = 0; ++monitor; if (monitor == monitors.length) monitor = 0; - set_monitor(); + reader.serial.set_telemetry(monitors[monitor]); } - set_channel(); + reader.serial.set_channel(channel); + set_label(); + reader.serial.set_monitor(true); } @@ -231,24 +239,22 @@ public class AltosScanUI public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); - if (cmd.equals("fake")) { - results.add(new AltosScanResult("N0CALL", 300, 1, 0, 1)); - } - - if (cmd.equals("cancel")) { + if (cmd.equals("cancel")) close(); - } - if (cmd.equals("ok")) { + if (cmd.equals("tick")) + tick_timer(); + + if (cmd.equals("monitor")) { close(); AltosScanResult r = (AltosScanResult) (list.getSelectedValue()); - System.out.printf("Selected channel %d telemetry %d\n", - r.channel, r.telemetry); - if (device != null) { - if (reader != null) { - reader.set_telemetry(r.telemetry); - reader.set_channel(r.channel); - owner.telemetry_window(device); + if (r != null) { + if (device != null) { + if (reader != null) { + reader.set_telemetry(monitors[r.telemetry]); + reader.set_channel(r.channel); + owner.telemetry_window(device); + } } } } @@ -270,20 +276,37 @@ public class AltosScanUI } private boolean open() { - device = AltosDeviceDialog.show(owner, Altos.product_any); - if (device != null) { - try { - reader = new AltosTelemetryReader(device); - set_channel(); - set_monitor(); - handler = new TelemetryHandler(); - thread = new Thread(handler); - thread.start(); - return true; - } catch (Exception e) { - scan_exception(e); - } + device = AltosDeviceDialog.show(owner, Altos.product_basestation); + if (device == null) + return false; + try { + reader = new AltosTelemetryReader(device); + reader.serial.set_channel(channel); + reader.serial.set_telemetry(monitors[monitor]); + handler = new TelemetryHandler(); + thread = new Thread(handler); + thread.start(); + return true; + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(owner, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(owner, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException ee) { + JOptionPane.showMessageDialog(owner, + device.toShortString(), + "Unkonwn I/O error", + JOptionPane.ERROR_MESSAGE); } + if (reader != null) + reader.close(false); return false; } @@ -291,8 +314,8 @@ public class AltosScanUI owner = in_owner; -// if (!open()) -// return; + if (!open()) + return; Container pane = getContentPane(); GridBagConstraints c = new GridBagConstraints(); @@ -306,6 +329,23 @@ public class AltosScanUI pane.setLayout(new GridBagLayout()); + scanning_label = new JLabel("Scanning:"); + + set_label(); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + + pane.add(scanning_label, c); + list = new JList(results) { //Subclass JList to workaround bug 4832765, which can cause the //scroll pane to not let the user easily scroll up to the beginning @@ -343,7 +383,7 @@ public class AltosScanUI list.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { - ok_button.doClick(); //emulate button click + monitor_button.doClick(); //emulate button click } } }); @@ -365,24 +405,7 @@ public class AltosScanUI listPane.add(listScroller); listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); - c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.CENTER; - c.insets = i; - c.weightx = 1; - c.weighty = 1; - - c.gridx = 0; - c.gridy = 0; - c.gridwidth = 3; - c.anchor = GridBagConstraints.CENTER; - - pane.add(listPane, c); - - fake_button = new JButton("fake"); - fake_button.addActionListener(this); - fake_button.setActionCommand("fake"); - - c.fill = GridBagConstraints.NONE; + c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; c.insets = i; c.weightx = 1; @@ -390,10 +413,10 @@ public class AltosScanUI c.gridx = 0; c.gridy = 1; - c.gridwidth = 1; + c.gridwidth = 2; c.anchor = GridBagConstraints.CENTER; - pane.add(fake_button, c); + pane.add(listPane, c); cancel_button = new JButton("Cancel"); cancel_button.addActionListener(this); @@ -405,16 +428,16 @@ public class AltosScanUI c.weightx = 1; c.weighty = 1; - c.gridx = 1; - c.gridy = 1; + c.gridx = 0; + c.gridy = 2; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; pane.add(cancel_button, c); - ok_button = new JButton("OK"); - ok_button.addActionListener(this); - ok_button.setActionCommand("ok"); + monitor_button = new JButton("Monitor"); + monitor_button.addActionListener(this); + monitor_button.setActionCommand("monitor"); c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -422,12 +445,12 @@ public class AltosScanUI c.weightx = 1; c.weighty = 1; - c.gridx = 2; - c.gridy = 1; + c.gridx = 1; + c.gridy = 2; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; - pane.add(ok_button, c); + pane.add(monitor_button, c); pack(); setLocationRelativeTo(owner); -- cgit v1.2.3 From 941b90a4905e34936d24a25ca90ac04eb6f5a792 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 17:38:00 -0700 Subject: altosui: Generalize and centralize telemetry constants, parse v0.8 telemetry Move telemetry constants to Altos class, adding functions to compute names and lengths. Generalize users of these values to use all of the known values. Add support for v0.8 TeleMetrum telemetry Signed-off-by: Keith Packard --- altosui/Altos.java | 34 +++++++++++++++++++++++++++++---- altosui/AltosFlightUI.java | 14 +++++++------- altosui/AltosPreferences.java | 2 +- altosui/AltosScanUI.java | 28 +++++++++++++-------------- altosui/AltosSerial.java | 10 ++-------- altosui/AltosTelemetryRecordLegacy.java | 20 ++++++++++++------- altosui/AltosTelemetryRecordRaw.java | 7 +++++-- 7 files changed, 72 insertions(+), 43 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 96263797..8d5916ad 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -70,11 +70,23 @@ public class Altos { /* Telemetry modes */ static final int ao_telemetry_off = 0; - static final int ao_telemetry_legacy = 1; - static final int ao_telemetry_split = 2; + static final int ao_telemetry_min = 1; + static final int ao_telemetry_standard = 1; + static final int ao_telemetry_0_9 = 2; + static final int ao_telemetry_0_8 = 3; + static final int ao_telemetry_max = 3; + + static final String[] ao_telemetry_name = { + "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" + }; + + static final int ao_telemetry_standard_len = 32; + static final int ao_telemetry_0_9_len = 95; + static final int ao_telemetry_0_8_len = 94; - static final int ao_telemetry_split_len = 32; - static final int ao_telemetry_legacy_len = 95; + static final int[] ao_telemetry_len = { + 0, 32, 95, 94 + }; static HashMap string_to_state = new HashMap(); @@ -103,6 +115,20 @@ public class Altos { map_initialized = true; } + static int telemetry_len(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_len[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + static String telemetry_name(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_name[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + static String[] state_to_string = { "startup", "idle", diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 9536c4bb..04bfc90d 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -156,14 +156,14 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { // Telemetry format menu telemetries = new JComboBox(); - telemetries.addItem("Original TeleMetrum Telemetry"); - telemetries.addItem("Standard AltOS Telemetry"); - int telemetry = 1; - telemetry = AltosPreferences.telemetry(serial); - if (telemetry > Altos.ao_telemetry_split) - telemetry = Altos.ao_telemetry_split; + for (int i = 1; i <= Altos.ao_telemetry_max; i++) + telemetries.addItem(Altos.telemetry_name(i)); + int telemetry = AltosPreferences.telemetry(serial); + if (telemetry <= Altos.ao_telemetry_off || + telemetry > Altos.ao_telemetry_max) + telemetry = Altos.ao_telemetry_standard; telemetries.setSelectedIndex(telemetry - 1); - telemetries.setMaximumRowCount(2); + telemetries.setMaximumRowCount(Altos.ao_telemetry_max); telemetries.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int telemetry = telemetries.getSelectedIndex() + 1; diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index 5029aff6..c8dee743 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -216,7 +216,7 @@ class AltosPreferences { if (telemetries.containsKey(serial)) return telemetries.get(serial); int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), - Altos.ao_telemetry_split); + Altos.ao_telemetry_standard); telemetries.put(serial, telemetry); return telemetry; } diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index d94ac3ae..54be4f52 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -35,13 +35,12 @@ class AltosScanResult { int flight; int channel; int telemetry; - static final String[] short_monitor_names = { "Standard", "Original" }; boolean interrupted = false; public String toString() { - return String.format("%-9.9s serial %-4d flight %-4d (channel %-2d telemetry %s)", - callsign, serial, flight, channel, short_monitor_names[telemetry]); + return String.format("%-9.9s serial %-4d flight %-4d (channel %-2d %s)", + callsign, serial, flight, channel, Altos.telemetry_name(telemetry)); } public String toShortString() { @@ -116,9 +115,7 @@ public class AltosScanUI javax.swing.Timer timer; AltosScanResults results = new AltosScanResults(); - static final String[] monitor_names = { "Standard AltOS Telemetry", "Original TeleMetrum Telemetry" }; - static final int[] monitors = { 2, 1 }; - int monitor; + int telemetry; int channel; final static int timeout = 1200; @@ -171,7 +168,7 @@ public class AltosScanUI record.serial, record.flight, channel, - monitor); + telemetry); Runnable r = new Runnable() { public void run() { results.add(result); @@ -195,7 +192,7 @@ public class AltosScanUI void set_label() { scanning_label.setText(String.format("Scanning: channel %d %s", channel, - monitor_names[monitor])); + Altos.telemetry_name(telemetry))); } void next() { @@ -207,10 +204,10 @@ public class AltosScanUI ++channel; if (channel > 9) { channel = 0; - ++monitor; - if (monitor == monitors.length) - monitor = 0; - reader.serial.set_telemetry(monitors[monitor]); + ++telemetry; + if (telemetry > Altos.ao_telemetry_max) + telemetry = Altos.ao_telemetry_min; + reader.serial.set_telemetry(telemetry); } reader.serial.set_channel(channel); set_label(); @@ -251,7 +248,7 @@ public class AltosScanUI if (r != null) { if (device != null) { if (reader != null) { - reader.set_telemetry(monitors[r.telemetry]); + reader.set_telemetry(r.telemetry); reader.set_channel(r.channel); owner.telemetry_window(device); } @@ -282,7 +279,7 @@ public class AltosScanUI try { reader = new AltosTelemetryReader(device); reader.serial.set_channel(channel); - reader.serial.set_telemetry(monitors[monitor]); + reader.serial.set_telemetry(telemetry); handler = new TelemetryHandler(); thread = new Thread(handler); thread.start(); @@ -329,6 +326,9 @@ public class AltosScanUI pane.setLayout(new GridBagLayout()); + channel = 0; + telemetry = Altos.ao_telemetry_min; + scanning_label = new JLabel("Scanning:"); set_label(); diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 3666cb41..2e8ce870 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -326,13 +326,7 @@ public class AltosSerial implements Runnable { } private int telemetry_len() { - switch (telemetry) { - case 1: - default: - return Altos.ao_telemetry_legacy_len; - case 2: - return Altos.ao_telemetry_split_len; - } + return Altos.telemetry_len(telemetry); } public void set_channel(int in_channel) { @@ -404,7 +398,7 @@ public class AltosSerial implements Runnable { line = ""; monitor_mode = false; frame = null; - telemetry = Altos.ao_telemetry_split; + telemetry = Altos.ao_telemetry_standard; monitors = new LinkedList> (); reply_queue = new LinkedBlockingQueue (); open(); diff --git a/altosui/AltosTelemetryRecordLegacy.java b/altosui/AltosTelemetryRecordLegacy.java index e3751ee7..756f3ec9 100644 --- a/altosui/AltosTelemetryRecordLegacy.java +++ b/altosui/AltosTelemetryRecordLegacy.java @@ -385,24 +385,25 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele */ int[] bytes; + int adjust; private int int8(int i) { - return Altos.int8(bytes, i + 1); + return Altos.int8(bytes, i + 1 + adjust); } private int uint8(int i) { - return Altos.uint8(bytes, i + 1); + return Altos.uint8(bytes, i + 1 + adjust); } private int int16(int i) { - return Altos.int16(bytes, i + 1); + return Altos.int16(bytes, i + 1 + adjust); } private int uint16(int i) { - return Altos.uint16(bytes, i + 1); + return Altos.uint16(bytes, i + 1 + adjust); } private int uint32(int i) { - return Altos.uint32(bytes, i + 1); + return Altos.uint32(bytes, i + 1 + adjust); } private String string(int i, int l) { - return Altos.string(bytes, i + 1, l); + return Altos.string(bytes, i + 1 + adjust, l); } static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); @@ -428,8 +429,13 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele } } version = 4; - callsign = string(62, 8); + adjust = 0; serial = uint16(0); + + if (bytes.length == Altos.ao_telemetry_0_8_len + 4) + adjust = -1; + + callsign = string(62, 8); flight = uint16(2); rssi = in_rssi; status = in_status; diff --git a/altosui/AltosTelemetryRecordRaw.java b/altosui/AltosTelemetryRecordRaw.java index e6c4cfc8..4b34f017 100644 --- a/altosui/AltosTelemetryRecordRaw.java +++ b/altosui/AltosTelemetryRecordRaw.java @@ -72,7 +72,7 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { /* length, data ..., rssi, status, checksum -- 4 bytes extra */ switch (bytes.length) { - case Altos.ao_telemetry_split_len + 4: + case Altos.ao_telemetry_standard_len + 4: int type = Altos.uint8(bytes, 4 + 1); switch (type) { case packet_type_TM_sensor: @@ -94,7 +94,10 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { break; } break; - case Altos.ao_telemetry_legacy_len + 4: + case Altos.ao_telemetry_0_9_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + case Altos.ao_telemetry_0_8_len + 4: r = new AltosTelemetryRecordLegacy(bytes, rssi, status); break; default: -- cgit v1.2.3 From e905042879147dd86241bf2dcc7437e5a6eb7578 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 20:43:57 -0700 Subject: altosui: Initialize channel and telemetry before use in ScanUI Otherwise we try to use telemetry format 0, which means 'no telemetry'. Signed-off-by: Keith Packard --- altosui/AltosScanUI.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 54be4f52..bc1638ed 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -311,6 +311,9 @@ public class AltosScanUI owner = in_owner; + channel = 0; + telemetry = Altos.ao_telemetry_min; + if (!open()) return; @@ -326,9 +329,6 @@ public class AltosScanUI pane.setLayout(new GridBagLayout()); - channel = 0; - telemetry = Altos.ao_telemetry_min; - scanning_label = new JLabel("Scanning:"); set_label(); -- cgit v1.2.3 From cbd14ba103ee5e3c5eec18e3a4ff13c320b98634 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 20:44:51 -0700 Subject: altosui: Set 'seen' bits in legacy telemetry packet reader Otherwise, the 'scan' code won't show detected flight computers. Signed-off-by: Keith Packard --- altosui/AltosTelemetryRecordLegacy.java | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosTelemetryRecordLegacy.java b/altosui/AltosTelemetryRecordLegacy.java index 756f3ec9..f59027ab 100644 --- a/altosui/AltosTelemetryRecordLegacy.java +++ b/altosui/AltosTelemetryRecordLegacy.java @@ -414,27 +414,19 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele static final int AO_GPS_DATE_VALID = (1 << 6); static final int AO_GPS_COURSE_VALID = (1 << 7); - static class theLock extends Object { - } - static public theLock lockObject = new theLock(); public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { bytes = in_bytes; - synchronized(lockObject) { - for (int i = 0; i < in_bytes.length - 2; i++) { - if ((i % 10) == 0) - System.out.printf("%3d:", i); - System.out.printf(" %02x", uint8(i)); - if ((i % 10) == 9 || i == in_bytes.length - 3) - System.out.printf("\n"); - } - } version = 4; adjust = 0; - serial = uint16(0); - if (bytes.length == Altos.ao_telemetry_0_8_len + 4) + if (bytes.length == Altos.ao_telemetry_0_8_len + 4) { + serial = uint8(0); adjust = -1; - + } else + serial = uint16(0); + + seen = seen_flight | seen_sensor | seen_temp_volt | seen_deploy; + callsign = string(62, 8); flight = uint16(2); rssi = in_rssi; @@ -476,6 +468,7 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { gps = new AltosGPS(); + seen |= seen_gps_time | seen_gps_lat | seen_gps_lon; gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); gps.locked = (gps_flags & AO_GPS_VALID) != 0; gps.connected = true; -- cgit v1.2.3 From 225073fd822f9861a83d65386c29fda9b37bf273 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 16:37:40 -0700 Subject: altosui: Add map preloading GUI Provide a way to manually enter latitude and longitude, preview the map area while downloading a 9x9 grid of map tiles to be used when monitoring flights without network access. Signed-off-by: Keith Packard --- altosui/AltosSiteMap.java | 59 +++++--- altosui/AltosSiteMapPreload.java | 285 +++++++++++++++++++++++++++++++++++++++ altosui/AltosUI.java | 11 ++ altosui/Makefile.am | 1 + 4 files changed, 340 insertions(+), 16 deletions(-) create mode 100644 altosui/AltosSiteMapPreload.java (limited to 'altosui') diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index 7575c10e..73068138 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -150,10 +150,13 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { //System.out.printf("Loading/fetching map %s\n", pngfile); Thread thread = new Thread() { public void run() { - ImageIcon res; - res = AltosSiteMapCache.fetchAndLoadMap(pngfile, pngurl); + final ImageIcon res = AltosSiteMapCache.fetchAndLoadMap(pngfile, pngurl); if (res != null) { - tile.loadMap(res); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + tile.loadMap(res); + } + }); } else { System.out.printf("# Failed to fetch file %s\n", pngfile); System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl); @@ -163,6 +166,24 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { thread.start(); } + File pngfile; + String pngurl; + + public int prefetchMap(int x, int y) { + LatLng map_latlng = latlng( + -centre.x + x*px_size + px_size/2, + -centre.y + y*px_size + px_size/2); + pngfile = MapFile(map_latlng.lat, map_latlng.lng); + pngurl = MapURL(map_latlng.lat, map_latlng.lng); + if (pngfile.exists()) { + return 1; + } else if (AltosSiteMapCache.fetchMap(pngfile, pngurl)) { + return 0; + } else { + return -1; + } + } + public static void prefetchMaps(double lat, double lng, int w, int h) { AltosSiteMap asm = new AltosSiteMap(true); asm.centre = asm.getBaseLocation(lat, lng); @@ -172,18 +193,18 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { int dx = -w/2, dy = -h/2; for (int y = dy; y < h+dy; y++) { for (int x = dx; x < w+dx; x++) { - LatLng map_latlng = asm.latlng( - -asm.centre.x + x*px_size + px_size/2, - -asm.centre.y + y*px_size + px_size/2); - File pngfile = asm.MapFile(map_latlng.lat, map_latlng.lng); - String pngurl = asm.MapURL(map_latlng.lat, map_latlng.lng); - if (pngfile.exists()) { - System.out.printf("Already have %s\n", pngfile); - } else if (AltosSiteMapCache.fetchMap(pngfile, pngurl)) { - System.out.printf("Fetched map %s\n", pngfile); - } else { - System.out.printf("# Failed to fetch file %s\n", pngfile); - System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl); + int r = asm.prefetchMap(x, y); + switch (r) { + case 1: + System.out.printf("Already have %s\n", asm.pngfile); + break; + case 0: + System.out.printf("Fetched map %s\n", asm.pngfile); + break; + case -1: + System.out.printf("# Failed to fetch file %s\n", asm.pngfile); + System.out.printf(" wget -O '%s' ''\n", asm.pngfile, asm.pngurl); + break; } } } @@ -224,6 +245,12 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { boolean initialised = false; Point2D.Double last_pt = null; int last_state = -1; + + public void show(double lat, double lon) { + initMaps(lat, lon); + initialised = true; + scrollRocketToVisible(pt(lat, lon)); + } public void show(final AltosState state, final int crc_errors) { // if insufficient gps data, nothing to update if (!state.gps.locked && state.gps.nsat < 4) @@ -382,6 +409,6 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { } } setViewportView(comp); - setPreferredSize(new Dimension(500,200)); + setPreferredSize(new Dimension(500,500)); } } diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java new file mode 100644 index 00000000..2d9468b9 --- /dev/null +++ b/altosui/AltosSiteMapPreload.java @@ -0,0 +1,285 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.MouseInputAdapter; +import javax.imageio.ImageIO; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.lang.Math; +import java.awt.geom.Point2D; +import java.awt.geom.Line2D; + +class AltosMapPos extends Box { + JLabel label; + JComboBox hemi; + JTextField deg; + JLabel deg_label; + JTextField min; + JLabel min_label; + + public void set_value(double new_value) { + double d, m; + int h; + + h = 0; + if (new_value < 0) { + h = 1; + new_value = -new_value; + } + d = Math.floor(new_value); + deg.setText(String.format("%3.0f", d)); + m = (new_value - d) * 60.0; + min.setText(String.format("%7.4f", m)); + hemi.setSelectedIndex(h); + } + + public double get_value() throws NumberFormatException { + int h = hemi.getSelectedIndex(); + double d = Double.parseDouble(deg.getText()); + double m = Double.parseDouble(min.getText()); + double v = d + m/60.0; + if (h == 1) + v = -v; + return v; + } + + public AltosMapPos(String label_value, + String[] hemi_names, + double default_value) { + super(BoxLayout.X_AXIS); + label = new JLabel(label_value); + hemi = new JComboBox(hemi_names); + hemi.setEditable(false); + deg = new JTextField("000"); + deg_label = new JLabel("degrees"); + min = new JTextField("00.0000"); + min_label = new JLabel("minutes"); + set_value(default_value); + add(label); + add(Box.createRigidArea(new Dimension(5, 0))); + add(hemi); + add(Box.createRigidArea(new Dimension(5, 0))); + add(deg); + add(Box.createRigidArea(new Dimension(5, 0))); + add(deg_label); + add(Box.createRigidArea(new Dimension(5, 0))); + add(min); + add(Box.createRigidArea(new Dimension(5, 0))); + add(min_label); + } +} + +public class AltosSiteMapPreload extends JDialog implements ActionListener { + AltosUI owner; + AltosSiteMap map; + + AltosMapPos lat; + AltosMapPos lon; + + JProgressBar pbar; + + final static int width = 9; + final static int height = 9; + final static int tiles = width * height; + + JToggleButton load_button; + boolean loading; + JButton close_button; + + static final String[] lat_hemi_names = { "N", "S" }; + static final String[] lon_hemi_names = { "E", "W" }; + + class updatePbar implements Runnable { + int n; + String s; + + public updatePbar(int in_n, String in_s) { + n = in_n; + s = in_s; + } + + public void run() { + pbar.setValue(n); + pbar.setString(s); + if (n == width * height) { + load_button.setSelected(false); + loading = false; + } + } + } + + class bgLoad extends Thread { + + AltosSiteMap map; + + public bgLoad(AltosSiteMap in_map) { + map = in_map; + } + + public void run() { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + map.prefetchMap(y - height/2, x - width/2); + SwingUtilities.invokeLater(new updatePbar(y * height + x + 1, + map.pngfile.toString())); + } + } + } + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if (cmd.equals("close")) + setVisible(false); + + if (cmd.equals("load")) { + if (!loading) { + loading = true; + final double latitude = lat.get_value(); + final double longitude = lon.get_value(); + map.show(latitude,longitude); + bgLoad thread = new bgLoad(map); + thread.start(); + } + } + } + + public AltosSiteMapPreload(AltosUI in_owner) { + owner = in_owner; + + Container pane = getContentPane(); + GridBagConstraints c = new GridBagConstraints(); + Insets i = new Insets(4,4,4,4); + + pane.setLayout(new GridBagLayout()); + + map = new AltosSiteMap(); + + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + + pane.add(map, c); + + pbar = new JProgressBar(); + pbar.setMinimum(0); + pbar.setMaximum(width * height); + pbar.setValue(0); + pbar.setString(""); + pbar.setStringPainted(true); + + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 0; + + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 2; + + pane.add(pbar, c); + + lat = new AltosMapPos("Latitude:", + lat_hemi_names, + 37.167833333); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 0; + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + + pane.add(lat, c); + + lon = new AltosMapPos("Longitude:", + lon_hemi_names, + -97.73975); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 0; + + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + + pane.add(lon, c); + + load_button = new JToggleButton("Load Map"); + load_button.addActionListener(this); + load_button.setActionCommand("load"); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 0; + + c.gridx = 0; + c.gridy = 3; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + + pane.add(load_button, c); + + close_button = new JButton("Close"); + close_button.addActionListener(this); + close_button.setActionCommand("close"); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 0; + + c.gridx = 1; + c.gridy = 3; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + + pane.add(close_button, c); + + pack(); + setLocationRelativeTo(owner); + setVisible(true); + } +} \ No newline at end of file diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 6a24d8a9..d8c8d61c 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -180,6 +180,13 @@ public class AltosUI extends JFrame { } }); + b = addButton(1, 2, "Load Maps"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + LoadMaps(); + } + }); + setTitle("AltOS"); pane.doLayout(); @@ -238,6 +245,10 @@ public class AltosUI extends JFrame { new AltosScanUI(AltosUI.this); } + void LoadMaps() { + new AltosSiteMapPreload(AltosUI.this); + } + /* * Replay a flight from telemetry data */ diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 0a3ed0b1..18862d98 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -88,6 +88,7 @@ altosui_JAVA = \ AltosSerialInUseException.java \ AltosSerialMonitor.java \ AltosSiteMap.java \ + AltosSiteMapPreload.java \ AltosSiteMapCache.java \ AltosSiteMapTile.java \ AltosState.java \ -- cgit v1.2.3 From 0929ee32f753255cbe1474988cb41a5a86d29a0e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 17:37:20 -0700 Subject: altosui: Try to avoid resize weirdness with map preloading grid bag + box does some strange stuff, this appears to avoid the worst of the interactions. Signed-off-by: Keith Packard --- altosui/AltosSiteMapPreload.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 2d9468b9..f939e9d6 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -217,7 +217,7 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; c.insets = i; - c.weightx = 1; + c.weightx = 0; c.weighty = 0; c.gridx = 0; @@ -234,7 +234,7 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; c.insets = i; - c.weightx = 1; + c.weightx = 0; c.weighty = 0; c.gridx = 1; -- cgit v1.2.3 From 00e6981c2e0a668864fcf391932855cd8942140c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 21:05:06 -0700 Subject: altosui: Flush telemetry lines before starting to watch for scan results This prevents pending telemetry lines from being incorrectly attributed to the wrong channel/telemetry. Signed-off-by: Keith Packard --- altosui/AltosScanUI.java | 5 +++++ altosui/AltosTelemetryReader.java | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index bc1638ed..96cab73b 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -280,6 +280,11 @@ public class AltosScanUI reader = new AltosTelemetryReader(device); reader.serial.set_channel(channel); reader.serial.set_telemetry(telemetry); + try { + Thread.sleep(100); + } catch (InterruptedException ie) { + } + reader.flush(); handler = new TelemetryHandler(); thread = new Thread(handler); thread.start(); diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 18f17841..23524b2c 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -39,6 +39,10 @@ class AltosTelemetryReader extends AltosFlightReader { return next; } + void flush() { + telem.clear(); + } + void close(boolean interrupted) { serial.remove_monitor(telem); log.close(); -- cgit v1.2.3 From 0a4d934f6e2914bfe2d965630543f029a1576c11 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 22:34:44 -0700 Subject: altosui: Display full map preload area in view. This involved fixing the map view to support arbitrary sizes, and then exposing a synchronous tile loading API so that the progress bar could be used to show tile loading progress. Signed-off-by: Keith Packard --- altosui/AltosSiteMap.java | 99 +++++++++++++++++++++++----------------- altosui/AltosSiteMapCache.java | 6 +++ altosui/AltosSiteMapPreload.java | 91 +++++++++++++++++++++++++----------- altosui/AltosSiteMapTile.java | 8 +++- 4 files changed, 136 insertions(+), 68 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index 73068138..188902e9 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -97,6 +97,8 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { int zoom; double scale_x, scale_y; + int radius; /* half width/height of tiles to load */ + private Point2D.Double pt(double lat, double lng) { return pt(new LatLng(lat, lng), scale_x, scale_y); } @@ -144,37 +146,31 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { // nothing } - private void bgLoadMap(final AltosSiteMapTile tile, - final File pngfile, final String pngurl) + private void loadMap(final AltosSiteMapTile tile, + File pngfile, String pngurl) { - //System.out.printf("Loading/fetching map %s\n", pngfile); - Thread thread = new Thread() { - public void run() { - final ImageIcon res = AltosSiteMapCache.fetchAndLoadMap(pngfile, pngurl); - if (res != null) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - tile.loadMap(res); - } - }); - } else { - System.out.printf("# Failed to fetch file %s\n", pngfile); - System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl); - } - } - }; - thread.start(); + final ImageIcon res = AltosSiteMapCache.fetchAndLoadMap(pngfile, pngurl); + if (res != null) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + tile.loadMap(res); + } + }); + } else { + System.out.printf("# Failed to fetch file %s\n", pngfile); + System.out.printf(" wget -O '%s' '%s'\n", pngfile, pngurl); + } } - File pngfile; - String pngurl; + File pngfile; + String pngurl; public int prefetchMap(int x, int y) { LatLng map_latlng = latlng( -centre.x + x*px_size + px_size/2, -centre.y + y*px_size + px_size/2); - pngfile = MapFile(map_latlng.lat, map_latlng.lng); - pngurl = MapURL(map_latlng.lat, map_latlng.lng); + pngfile = MapFile(map_latlng.lat, map_latlng.lng, zoom); + pngurl = MapURL(map_latlng.lat, map_latlng.lng, zoom); if (pngfile.exists()) { return 1; } else if (AltosSiteMapCache.fetchMap(pngfile, pngurl)) { @@ -210,25 +206,41 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { } } - private void initMap(AltosSiteMapTile tile, Point offset) { + public String initMap(Point offset) { + AltosSiteMapTile tile = mapTiles.get(offset); Point2D.Double coord = tileCoordOffset(offset); LatLng map_latlng = latlng(px_size/2-coord.x, px_size/2-coord.y); - File pngfile = MapFile(map_latlng.lat, map_latlng.lng); - String pngurl = MapURL(map_latlng.lat, map_latlng.lng); - bgLoadMap(tile, pngfile, pngurl); + File pngfile = MapFile(map_latlng.lat, map_latlng.lng, zoom); + String pngurl = MapURL(map_latlng.lat, map_latlng.lng, zoom); + loadMap(tile, pngfile, pngurl); + return pngfile.toString(); } - private void initMaps(double lat, double lng) { - centre = getBaseLocation(lat, lng); - + public void setBaseLocation(double lat, double lng) { for (Point k : mapTiles.keySet()) { - initMap(mapTiles.get(k), k); + AltosSiteMapTile tile = mapTiles.get(k); + tile.clearMap(); } + + centre = getBaseLocation(lat, lng); + scrollRocketToVisible(pt(lat,lng)); } - private File MapFile(double lat, double lng) { + private void initMaps(double lat, double lng) { + setBaseLocation(lat, lng); + + Thread thread = new Thread() { + public void run() { + for (Point k : mapTiles.keySet()) + initMap(k); + } + }; + thread.start(); + } + + private static File MapFile(double lat, double lng, int zoom) { char chlat = lat < 0 ? 'S' : 'N'; char chlng = lng < 0 ? 'W' : 'E'; if (lat < 0) lat = -lat; @@ -238,7 +250,7 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { chlat, lat, chlng, lng, zoom)); } - private String MapURL(double lat, double lng) { + private static String MapURL(double lat, double lng, int zoom) { return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=hybrid&format=png32", lat, lng, zoom, px_size, px_size); } @@ -248,7 +260,6 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { public void show(double lat, double lon) { initMaps(lat, lon); - initialised = true; scrollRocketToVisible(pt(lat, lon)); } public void show(final AltosState state, final int crc_errors) { @@ -295,7 +306,7 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { AltosSiteMapTile tile = createTile(offset); tile.show(state, crc_errors, lref, ref); - initMap(tile, offset); + initMap(offset); finishTileLater(tile, offset); } @@ -325,13 +336,13 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { } private void ensureTilesAround(Point base_offset) { - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { + for (int x = -radius; x <= radius; x++) { + for (int y = -radius; y <= radius; y++) { Point offset = new Point(base_offset.x + x, base_offset.y + y); if (mapTiles.containsKey(offset)) continue; AltosSiteMapTile tile = createTile(offset); - initMap(tile, offset); + initMap(offset); finishTileLater(tile, offset); } } @@ -396,13 +407,15 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { JComponent comp = new JComponent() { }; private GridBagLayout layout = new GridBagLayout(); - public AltosSiteMap() { + public AltosSiteMap(int in_radius) { + radius = in_radius; + GrabNDrag scroller = new GrabNDrag(comp); comp.setLayout(layout); - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { + for (int x = -radius; x <= radius; x++) { + for (int y = -radius; y <= radius; y++) { Point offset = new Point(x, y); AltosSiteMapTile t = createTile(offset); addTileAt(t, offset); @@ -411,4 +424,8 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { setViewportView(comp); setPreferredSize(new Dimension(500,500)); } + + public AltosSiteMap() { + this(1); + } } diff --git a/altosui/AltosSiteMapCache.java b/altosui/AltosSiteMapCache.java index 2e62cc45..cfad52a9 100644 --- a/altosui/AltosSiteMapCache.java +++ b/altosui/AltosSiteMapCache.java @@ -37,6 +37,7 @@ public class AltosSiteMapCache extends JLabel { try { u = new URL(url); } catch (java.net.MalformedURLException e) { + System.out.printf("Malformed URL '%s'\n", url); return false; } @@ -57,9 +58,12 @@ public class AltosSiteMapCache extends JLabel { in.close(); if (offset != contentLength) { + System.out.printf("Bad length %d != %d\n", + offset, contentLength); return false; } } catch (IOException e) { + System.out.printf("IO exception reading URL\n"); return false; } @@ -69,11 +73,13 @@ public class AltosSiteMapCache extends JLabel { out.flush(); out.close(); } catch (FileNotFoundException e) { + System.out.printf("Can't create file\n"); return false; } catch (IOException e) { if (file.exists()) { file.delete(); } + System.out.printf("IO exception writing file\n"); return false; } return true; diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index f939e9d6..25133435 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -33,6 +33,7 @@ import java.awt.geom.Point2D; import java.awt.geom.Line2D; class AltosMapPos extends Box { + AltosUI owner; JLabel label; JComboBox hemi; JTextField deg; @@ -58,25 +59,51 @@ class AltosMapPos extends Box { public double get_value() throws NumberFormatException { int h = hemi.getSelectedIndex(); - double d = Double.parseDouble(deg.getText()); - double m = Double.parseDouble(min.getText()); - double v = d + m/60.0; + String d_t = deg.getText(); + String m_t = min.getText(); + double d, m, v; + try { + d = Double.parseDouble(d_t); + } catch (NumberFormatException ne) { + JOptionPane.showMessageDialog(owner, + String.format("Invalid degrees \"%s\"", + d_t), + "Invalid number", + JOptionPane.ERROR_MESSAGE); + throw ne; + } + try { + if (m_t.equals("")) + m = 0; + else + m = Double.parseDouble(m_t); + } catch (NumberFormatException ne) { + JOptionPane.showMessageDialog(owner, + String.format("Invalid minutes \"%s\"", + m_t), + "Invalid number", + JOptionPane.ERROR_MESSAGE); + throw ne; + } + v = d + m/60.0; if (h == 1) v = -v; return v; } - public AltosMapPos(String label_value, + public AltosMapPos(AltosUI in_owner, + String label_value, String[] hemi_names, double default_value) { super(BoxLayout.X_AXIS); + owner = in_owner; label = new JLabel(label_value); hemi = new JComboBox(hemi_names); hemi.setEditable(false); deg = new JTextField("000"); - deg_label = new JLabel("degrees"); + deg_label = new JLabel("°"); min = new JTextField("00.0000"); - min_label = new JLabel("minutes"); + min_label = new JLabel("'"); set_value(default_value); add(label); add(Box.createRigidArea(new Dimension(5, 0))); @@ -101,9 +128,9 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { JProgressBar pbar; - final static int width = 9; - final static int height = 9; - final static int tiles = width * height; + final static int radius = 4; + final static int width = (radius * 2 + 1); + final static int height = (radius * 2 + 1); JToggleButton load_button; boolean loading; @@ -116,15 +143,21 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { int n; String s; - public updatePbar(int in_n, String in_s) { - n = in_n; + public updatePbar(int x, int y, String in_s) { + n = (x + radius) + (y + radius) * width + 1; + System.out.printf("update pbar %d\n", n); s = in_s; } public void run() { pbar.setValue(n); pbar.setString(s); - if (n == width * height) { + if (n < width * height) { + pbar.setValue(n); + pbar.setString(s); + } else { + pbar.setValue(0); + pbar.setString(""); load_button.setSelected(false); loading = false; } @@ -140,11 +173,11 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { } public void run() { - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - map.prefetchMap(y - height/2, x - width/2); - SwingUtilities.invokeLater(new updatePbar(y * height + x + 1, - map.pngfile.toString())); + for (int y = -map.radius; y <= map.radius; y++) { + for (int x = -map.radius; x <= map.radius; x++) { + String pngfile; + pngfile = map.initMap(new Point(x,y)); + SwingUtilities.invokeLater(new updatePbar(x, y, pngfile)); } } } @@ -158,12 +191,16 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { if (cmd.equals("load")) { if (!loading) { - loading = true; - final double latitude = lat.get_value(); - final double longitude = lon.get_value(); - map.show(latitude,longitude); - bgLoad thread = new bgLoad(map); - thread.start(); + try { + final double latitude = lat.get_value(); + final double longitude = lon.get_value(); + map.setBaseLocation(latitude,longitude); + loading = true; + bgLoad thread = new bgLoad(map); + thread.start(); + } catch (NumberFormatException ne) { + load_button.setSelected(false); + } } } } @@ -177,7 +214,7 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { pane.setLayout(new GridBagLayout()); - map = new AltosSiteMap(); + map = new AltosSiteMap(4); c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; @@ -211,7 +248,8 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { pane.add(pbar, c); - lat = new AltosMapPos("Latitude:", + lat = new AltosMapPos(owner, + "Latitude:", lat_hemi_names, 37.167833333); c.fill = GridBagConstraints.NONE; @@ -227,7 +265,8 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { pane.add(lat, c); - lon = new AltosMapPos("Longitude:", + lon = new AltosMapPos(owner, + "Longitude:", lon_hemi_names, -97.73975); diff --git a/altosui/AltosSiteMapTile.java b/altosui/AltosSiteMapTile.java index 8301f42b..66da7c54 100644 --- a/altosui/AltosSiteMapTile.java +++ b/altosui/AltosSiteMapTile.java @@ -35,11 +35,16 @@ public class AltosSiteMapTile extends JLayeredPane { JLabel mapLabel; JLabel draw; Graphics2D g2d; + int px_size; public void loadMap(ImageIcon icn) { mapLabel.setIcon(icn); } + public void clearMap() { + fillLabel(mapLabel, Color.GRAY, px_size); + } + static Color stateColors[] = { Color.WHITE, // startup Color.WHITE, // idle @@ -90,7 +95,8 @@ public class AltosSiteMapTile extends JLayeredPane { return g; } - public AltosSiteMapTile(int px_size) { + public AltosSiteMapTile(int in_px_size) { + px_size = in_px_size; setPreferredSize(new Dimension(px_size, px_size)); mapLabel = new JLabel(); -- cgit v1.2.3 From 1681c57cbbfc5214dbc2a519e54ce9f29ffe3921 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Jul 2011 22:43:34 -0700 Subject: altosui: Remove a bunch of sitemap debugging printfs Seems to work, let's get less chatty Signed-off-by: Keith Packard --- altosui/AltosSiteMapCache.java | 6 ------ altosui/AltosSiteMapPreload.java | 1 - 2 files changed, 7 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSiteMapCache.java b/altosui/AltosSiteMapCache.java index cfad52a9..2e62cc45 100644 --- a/altosui/AltosSiteMapCache.java +++ b/altosui/AltosSiteMapCache.java @@ -37,7 +37,6 @@ public class AltosSiteMapCache extends JLabel { try { u = new URL(url); } catch (java.net.MalformedURLException e) { - System.out.printf("Malformed URL '%s'\n", url); return false; } @@ -58,12 +57,9 @@ public class AltosSiteMapCache extends JLabel { in.close(); if (offset != contentLength) { - System.out.printf("Bad length %d != %d\n", - offset, contentLength); return false; } } catch (IOException e) { - System.out.printf("IO exception reading URL\n"); return false; } @@ -73,13 +69,11 @@ public class AltosSiteMapCache extends JLabel { out.flush(); out.close(); } catch (FileNotFoundException e) { - System.out.printf("Can't create file\n"); return false; } catch (IOException e) { if (file.exists()) { file.delete(); } - System.out.printf("IO exception writing file\n"); return false; } return true; diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 25133435..c97f081c 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -145,7 +145,6 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { public updatePbar(int x, int y, String in_s) { n = (x + radius) + (y + radius) * width + 1; - System.out.printf("update pbar %d\n", n); s = in_s; } -- cgit v1.2.3 From a482d904a3f391c3a24df3660acb3f3696aa6766 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Sat, 16 Jul 2011 23:08:49 -0700 Subject: altosui: Make sure degree and minute values are visible (map preload) Set min size to preferred size so that the value remains visible instead of snapping to 0 pixels wide. Signed-off-by: Keith Packard --- altosui/AltosSiteMapPreload.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index c97f081c..876c14ac 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -105,6 +105,8 @@ class AltosMapPos extends Box { min = new JTextField("00.0000"); min_label = new JLabel("'"); set_value(default_value); + deg.setMinimumSize(deg.getPreferredSize()); + min.setMinimumSize(min.getPreferredSize()); add(label); add(Box.createRigidArea(new Dimension(5, 0))); add(hemi); -- cgit v1.2.3 From 51796e2f1ebce3ee8dc1ac90648381410c1379ee Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 May 2011 11:32:29 -0700 Subject: altos, altosui: Add igniter mode (dual, apogee, main) This provides for redundant charges for either apogee or main. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 7 ++++++ altosui/AltosConfigData.java | 2 ++ altosui/AltosConfigUI.java | 54 ++++++++++++++++++++++++++++++++++++++++---- src/ao.h | 7 +++++- src/ao_config.c | 31 +++++++++++++++++++++++++ src/ao_ignite.c | 50 ++++++++++++++++++++++++++++++++-------- 6 files changed, 136 insertions(+), 15 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index c5de83f2..e3c30d4d 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -70,6 +70,7 @@ public class AltosConfig implements ActionListener { int_ref radio_channel; int_ref radio_calibration; int_ref flight_log_max; + int_ref ignite_mode; string_ref version; string_ref product; string_ref callsign; @@ -130,6 +131,7 @@ public class AltosConfig implements ActionListener { config_ui.set_radio_channel(radio_channel.get()); config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_flight_log_max(flight_log_max.get()); + config_ui.set_ignite_mode(ignite_mode.get()); config_ui.set_callsign(callsign.get()); config_ui.set_clean(); config_ui.make_visible(); @@ -153,6 +155,7 @@ public class AltosConfig implements ActionListener { get_int(line, "Radio channel:", radio_channel); get_int(line, "Radio cal:", radio_calibration); get_int(line, "Max flight log:", flight_log_max); + get_int(line, "Ignite mode:", ignite_mode); get_string(line, "Callsign:", callsign); get_string(line,"software-version", version); get_string(line,"product", product); @@ -224,6 +227,8 @@ public class AltosConfig implements ActionListener { serial_line.printf("c c %s\n", callsign.get()); if (flight_log_max.get() != 0) serial_line.printf("c l %d\n", flight_log_max.get()); + if (ignite_mode.get() >= 0) + serial_line.printf("c i %d\n", ignite_mode.get()); serial_line.printf("c w\n"); } catch (InterruptedException ie) { } finally { @@ -306,6 +311,7 @@ public class AltosConfig implements ActionListener { radio_channel.set(config_ui.radio_channel()); radio_calibration.set(config_ui.radio_calibration()); flight_log_max.set(config_ui.flight_log_max()); + ignite_mode.set(config_ui.ignite_mode()); callsign.set(config_ui.callsign()); run_serial_thread(serial_mode_save); } @@ -340,6 +346,7 @@ public class AltosConfig implements ActionListener { radio_channel = new int_ref(0); radio_calibration = new int_ref(1186611); flight_log_max = new int_ref(0); + ignite_mode = new int_ref(-1); callsign = new string_ref("N0CALL"); version = new string_ref("unknown"); product = new string_ref("unknown"); diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 8c32ed86..3f0e9af3 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -51,6 +51,7 @@ public class AltosConfigData implements Iterable { int accel_cal_plus, accel_cal_minus; int radio_calibration; int flight_log_max; + int ignite_mode; static String get_string(String line, String label) throws ParseException { @@ -96,6 +97,7 @@ public class AltosConfigData implements Iterable { try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} + try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} try { version = get_string(line,"software-version"); } catch (Exception e) {} try { product = get_string(line,"product"); } catch (Exception e) {} diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index f835ee2e..6f635b9d 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -46,6 +46,7 @@ public class AltosConfigUI JLabel radio_channel_label; JLabel radio_calibration_label; JLabel flight_log_max_label; + JLabel ignite_mode_label; JLabel callsign_label; public boolean dirty; @@ -59,6 +60,7 @@ public class AltosConfigUI JComboBox radio_channel_value; JTextField radio_calibration_value; JComboBox flight_log_max_value; + JComboBox ignite_mode_value; JTextField callsign_value; JButton save; @@ -83,6 +85,12 @@ public class AltosConfigUI "704", "768", "832", "896", "960", }; + static String[] ignite_mode_values = { + "Dual Deploy", + "Redundant Apogee", + "Redundant Main", + }; + static String[] radio_channel_values = new String[10]; { for (int i = 0; i <= 9; i++) @@ -326,9 +334,33 @@ public class AltosConfigUI flight_log_max_value.addItemListener(this); pane.add(flight_log_max_value, c); - /* Buttons */ + /* Ignite mode */ c = new GridBagConstraints(); c.gridx = 0; c.gridy = 9; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + ignite_mode_label = new JLabel("Igniter Firing Mode:"); + pane.add(ignite_mode_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 9; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + ignite_mode_value = new JComboBox(ignite_mode_values); + ignite_mode_value.setEditable(false); + ignite_mode_value.addItemListener(this); + pane.add(ignite_mode_value, c); + + /* Buttons */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 10; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -339,7 +371,7 @@ public class AltosConfigUI save.setActionCommand("Save"); c = new GridBagConstraints(); - c.gridx = 2; c.gridy = 9; + c.gridx = 2; c.gridy = 10; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -350,7 +382,7 @@ public class AltosConfigUI reset.setActionCommand("Reset"); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 9; + c.gridx = 4; c.gridy = 10; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -361,7 +393,7 @@ public class AltosConfigUI reboot.setActionCommand("Reboot"); c = new GridBagConstraints(); - c.gridx = 6; c.gridy = 9; + c.gridx = 6; c.gridy = 10; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_END; @@ -499,6 +531,20 @@ public class AltosConfigUI return Integer.parseInt(flight_log_max_value.getSelectedItem().toString()); } + public void set_ignite_mode(int new_ignite_mode) { + if (new_ignite_mode < 0) { + ignite_mode_value.setEnabled(false); + new_ignite_mode = 0; + } else { + ignite_mode_value.setEnabled(true); + } + ignite_mode_value.setSelectedItem(Integer.toString(new_ignite_mode)); + } + + public int ignite_mode() { + return ignite_mode_value.getSelectedIndex(); + } + public void set_clean() { dirty = false; } diff --git a/src/ao.h b/src/ao.h index e52a2198..d3e588b6 100644 --- a/src/ao.h +++ b/src/ao.h @@ -1357,7 +1357,7 @@ ao_igniter_init(void); */ #define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 4 +#define AO_CONFIG_MINOR 5 struct ao_config { uint8_t major; @@ -1370,8 +1370,13 @@ struct ao_config { int16_t accel_minus_g; /* minor version 2 */ uint32_t radio_cal; /* minor version 3 */ uint32_t flight_log_max; /* minor version 4 */ + uint8_t ignite_mode; /* minor version 5 */ }; +#define AO_IGNITE_MODE_DUAL 0 +#define AO_IGNITE_MODE_APOGEE 1 +#define AO_IGNITE_MODE_MAIN 2 + extern __xdata struct ao_config ao_config; #define AO_CONFIG_MAX_SIZE 128 diff --git a/src/ao_config.c b/src/ao_config.c index 813164ea..48349886 100644 --- a/src/ao_config.c +++ b/src/ao_config.c @@ -27,6 +27,7 @@ __xdata uint8_t ao_config_mutex; #define AO_CONFIG_DEFAULT_CALLSIGN "N0CALL" #define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000 #define AO_CONFIG_DEFAULT_APOGEE_DELAY 0 +#define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL #if USE_INTERNAL_EEPROM #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ao_storage_config #else @@ -75,6 +76,7 @@ _ao_config_get(void) ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY; ao_config.radio_cal = ao_radio_cal; ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX; + ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; ao_config_dirty = 1; } if (ao_config.minor < AO_CONFIG_MINOR) { @@ -92,6 +94,9 @@ _ao_config_get(void) /* Fixups for minor version 4 */ if (ao_config.minor < 4) ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX; + /* Fixupes for minor version 5 */ + if (ao_config.minor < 5) + ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; } @@ -334,6 +339,28 @@ ao_config_log_set(void) __reentrant } #endif /* HAS_EEPROM */ +#if HAS_IGNITE +void +ao_config_ignite_mode_show(void) __reentrant +{ + printf("Ignite mode: %d\n", ao_config.ignite_mode); +} + +void +ao_config_ignite_mode_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + ao_mutex_get(&ao_config_mutex); + _ao_config_get(); + ao_config.ignite_mode = ao_cmd_lex_i; + ao_config_dirty = 1; + ao_mutex_put(&ao_config_mutex); + ao_config_log_show(); +} +#endif + struct ao_config_var { __code char *str; void (*set)(void) __reentrant; @@ -369,6 +396,10 @@ __code struct ao_config_var ao_config_vars[] = { #if HAS_EEPROM { "l \0Flight log size in kB", ao_config_log_set, ao_config_log_show }, +#endif +#if HAS_IGNITE + { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode", + ao_config_ignite_mode_set, ao_config_ignite_mode_show }, #endif { "s\0Show", ao_config_show, ao_config_show }, diff --git a/src/ao_ignite.c b/src/ao_ignite.c index e1b91bea..512ec622 100644 --- a/src/ao_ignite.c +++ b/src/ao_ignite.c @@ -51,7 +51,7 @@ void ao_ignite(enum ao_igniter igniter) __critical { ao_ignition[igniter].request = 1; - ao_wakeup(&ao_ignition[0]); + ao_wakeup(&ao_ignition); } enum ao_igniter_status @@ -91,16 +91,46 @@ void ao_igniter_fire(enum ao_igniter igniter) __critical { ao_ignition[igniter].firing = 1; - switch (igniter) { - case ao_igniter_drogue: - AO_IGNITER_DROGUE = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_DROGUE = 0; + switch(ao_config.ignite_mode) { + case AO_IGNITE_MODE_DUAL: + switch (igniter) { + case ao_igniter_drogue: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + break; + case ao_igniter_main: + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } break; - case ao_igniter_main: - AO_IGNITER_MAIN = 1; - ao_delay(AO_IGNITER_FIRE_TIME); - AO_IGNITER_MAIN = 0; + case AO_IGNITE_MODE_APOGEE: + switch (igniter) { + case ao_igniter_drogue: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + ao_delay(AO_IGNITER_CHARGE_TIME); + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } + break; + case AO_IGNITE_MODE_MAIN: + switch (igniter) { + case ao_igniter_main: + AO_IGNITER_DROGUE = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_DROGUE = 0; + ao_delay(AO_IGNITER_CHARGE_TIME); + AO_IGNITER_MAIN = 1; + ao_delay(AO_IGNITER_FIRE_TIME); + AO_IGNITER_MAIN = 0; + break; + } break; } ao_ignition[igniter].firing = 0; -- cgit v1.2.3 From 81cac174c80ee42d9e94c6500da7c4c760c3ce67 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jul 2011 11:25:47 -0700 Subject: altosui: Download list of site locations for map preloading The current URL for this is: http://gag.com/~keithp/launch-sites.txt The format is: :: lat and lon are both in signed decimal degrees. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 1 + altosui/AltosSiteMapPreload.java | 169 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 159 insertions(+), 11 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 2e8ce870..8f8f99d7 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -25,6 +25,7 @@ import java.lang.*; import java.io.*; import java.util.concurrent.*; import java.util.*; +import java.text.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 876c14ac..972765ae 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -31,6 +31,8 @@ import java.util.prefs.*; import java.lang.Math; import java.awt.geom.Point2D; import java.awt.geom.Line2D; +import java.net.URL; +import java.net.URLConnection; class AltosMapPos extends Box { AltosUI owner; @@ -100,13 +102,14 @@ class AltosMapPos extends Box { label = new JLabel(label_value); hemi = new JComboBox(hemi_names); hemi.setEditable(false); - deg = new JTextField("000"); + deg = new JTextField(5); + deg.setMinimumSize(deg.getPreferredSize()); + deg.setHorizontalAlignment(JTextField.RIGHT); deg_label = new JLabel("°"); - min = new JTextField("00.0000"); + min = new JTextField(9); + min.setMinimumSize(min.getPreferredSize()); min_label = new JLabel("'"); set_value(default_value); - deg.setMinimumSize(deg.getPreferredSize()); - min.setMinimumSize(min.getPreferredSize()); add(label); add(Box.createRigidArea(new Dimension(5, 0))); add(hemi); @@ -121,19 +124,111 @@ class AltosMapPos extends Box { } } -public class AltosSiteMapPreload extends JDialog implements ActionListener { +class AltosSite { + String name; + double latitude; + double longitude; + + public String toString() { + return name; + } + + public AltosSite(String in_name, double in_latitude, double in_longitude) { + name = in_name; + latitude = in_latitude; + longitude = in_longitude; + } + + public AltosSite(String line) throws ParseException { + String[] elements = line.split(":"); + + if (elements.length < 3) + throw new ParseException(String.format("Invalid site line %s", line), 0); + + name = elements[0]; + + try { + latitude = Double.parseDouble(elements[1]); + longitude = Double.parseDouble(elements[2]); + } catch (NumberFormatException ne) { + throw new ParseException(String.format("Invalid site line %s", line), 0); + } + } +} + +class AltosSites extends Thread { + AltosSiteMapPreload preload; + URL url; + LinkedList sites; + + void notify_complete() { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + preload.set_sites(); + } + }); + } + + void add(AltosSite site) { + sites.add(site); + } + + void add(String line) { + try { + add(new AltosSite(line)); + } catch (ParseException pe) { + } + } + + public void run() { + try { + URLConnection uc = url.openConnection(); + int length = uc.getContentLength(); + + InputStreamReader in_stream = new InputStreamReader(uc.getInputStream(), Altos.unicode_set); + BufferedReader in = new BufferedReader(in_stream); + + for (;;) { + String line = in.readLine(); + if (line == null) + break; + add(line); + } + } catch (IOException e) { + } finally { + notify_complete(); + } + } + + public AltosSites(AltosSiteMapPreload in_preload) { + sites = new LinkedList(); + preload = in_preload; + try { + url = new URL("http://gag.com/~keithp/launch-sites.txt"); + } catch (java.net.MalformedURLException e) { + notify_complete(); + } + start(); + } +} + +public class AltosSiteMapPreload extends JDialog implements ActionListener, ItemListener { AltosUI owner; AltosSiteMap map; AltosMapPos lat; AltosMapPos lon; - JProgressBar pbar; - final static int radius = 4; final static int width = (radius * 2 + 1); final static int height = (radius * 2 + 1); + JProgressBar pbar; + + AltosSites sites; + JLabel site_list_label; + JComboBox site_list; + JToggleButton load_button; boolean loading; JButton close_button; @@ -184,6 +279,27 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { } } + public void set_sites() { + int i = 1; + for (AltosSite site : sites.sites) { + site_list.insertItemAt(site, i); + i++; + } + } + + public void itemStateChanged(ItemEvent e) { + int state = e.getStateChange(); + + if (state == ItemEvent.SELECTED) { + Object o = e.getItem(); + if (o instanceof AltosSite) { + AltosSite site = (AltosSite) o; + lat.set_value(site.latitude); + lon.set_value(site.longitude); + } + } + } + public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); @@ -249,6 +365,37 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { pane.add(pbar, c); + site_list_label = new JLabel ("Known Launch Sites:"); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 0; + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + + pane.add(site_list_label, c); + + site_list = new JComboBox(new String[] { "Site List" }); + site_list.addItemListener(this); + + sites = new AltosSites(this); + + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 0; + + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 1; + + pane.add(site_list, c); + lat = new AltosMapPos(owner, "Latitude:", lat_hemi_names, @@ -260,7 +407,7 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { c.weighty = 0; c.gridx = 0; - c.gridy = 2; + c.gridy = 3; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; @@ -278,7 +425,7 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { c.weighty = 0; c.gridx = 1; - c.gridy = 2; + c.gridy = 3; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; @@ -295,7 +442,7 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { c.weighty = 0; c.gridx = 0; - c.gridy = 3; + c.gridy = 4; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; @@ -312,7 +459,7 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener { c.weighty = 0; c.gridx = 1; - c.gridy = 3; + c.gridy = 4; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; -- cgit v1.2.3 From fef42e0d9e0a20bdbd32e052749fc63575515e1c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jul 2011 11:29:13 -0700 Subject: altosui: Add launch-sites.txt Contains a few of our favorites. Signed-off-by: Keith Packard --- altosui/launch-sites.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 altosui/launch-sites.txt (limited to 'altosui') diff --git a/altosui/launch-sites.txt b/altosui/launch-sites.txt new file mode 100644 index 00000000..05619d57 --- /dev/null +++ b/altosui/launch-sites.txt @@ -0,0 +1,7 @@ +KLOUDBusters Rocket Pasture:37.167833333:-97.73975 +NCR Pawnee:40.8875500:-104.6484750 +OPROC Discovery Bay:47.97808,-122.896383 +OROC Brothers:43.79949786336483:-120.6485810681392 +OROC Sheridan:45.044176:-123.314323 +Tripoli Colorado Hartsel:39.009247:-105.702338 +WAC Sportsman Club:47.815327777777778:-119.427186111111111 -- cgit v1.2.3 From 1f3f3d575572eff33a2bc7a53d4691e59a428450 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jul 2011 15:09:55 -0700 Subject: altosui: Add a bunch more site locations BALLS, Rio Rancho, METRA, QRS Cedar Grove and Hudson Ranch Signed-off-by: Keith Packard --- altosui/Makefile.am | 3 +++ altosui/launch-sites.txt | 5 +++++ 2 files changed, 8 insertions(+) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 18862d98..e3075d41 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -307,3 +307,6 @@ $(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) $(WINDOWS_DIST): $(WINDOWS_FILES) altos-windows.nsi -rm -f $@ makensis -Oaltos-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" altos-windows.nsi + +publish: + scp launch-sites.txt gag.com:public_html \ No newline at end of file diff --git a/altosui/launch-sites.txt b/altosui/launch-sites.txt index 05619d57..baa0dfe9 100644 --- a/altosui/launch-sites.txt +++ b/altosui/launch-sites.txt @@ -1,7 +1,12 @@ +AHPRA BALLS:40.808333333333333:-119.15 +ARS Rio Rancho:35.33475:-106.75361 KLOUDBusters Rocket Pasture:37.167833333:-97.73975 +METRA Pine Island:41.31939:-74.47077 NCR Pawnee:40.8875500:-104.6484750 OPROC Discovery Bay:47.97808,-122.896383 OROC Brothers:43.79949786336483:-120.6485810681392 OROC Sheridan:45.044176:-123.314323 +QRS Cedar Grove:-27.8512283:152.9624000 +SCORE Hudson Ranch:38.155602777777778:-104.809119444444444 Tripoli Colorado Hartsel:39.009247:-105.702338 WAC Sportsman Club:47.815327777777778:-119.427186111111111 -- cgit v1.2.3 From ddef3e4ec1b3ff86b164f83807c34c2a78f73eb8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jul 2011 15:45:07 -0700 Subject: altosui: Mark preload site location with red circles (like launch) Just to show where on the map the official launch location is. Signed-off-by: Keith Packard --- altosui/AltosSiteMap.java | 10 ++++++++++ altosui/AltosSiteMapPreload.java | 1 + altosui/AltosSiteMapTile.java | 11 +++++++++++ 3 files changed, 22 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index 188902e9..b3fb3c54 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -320,6 +320,16 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { last_state = state.state; } + public void draw_circle(double lat, double lon) { + final Point2D.Double pt = pt(lat, lon); + + for (Point offset : mapTiles.keySet()) { + AltosSiteMapTile tile = mapTiles.get(offset); + Point2D.Double ref = translatePoint(pt, tileCoordOffset(offset)); + tile.draw_circle(ref); + } + } + private AltosSiteMapTile createTile(Point offset) { AltosSiteMapTile tile = new AltosSiteMapTile(px_size); mapTiles.put(offset, tile); diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 972765ae..5d437e17 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -312,6 +312,7 @@ public class AltosSiteMapPreload extends JDialog implements ActionListener, Item final double latitude = lat.get_value(); final double longitude = lon.get_value(); map.setBaseLocation(latitude,longitude); + map.draw_circle(latitude,longitude); loading = true; bgLoad thread = new bgLoad(map); thread.start(); diff --git a/altosui/AltosSiteMapTile.java b/altosui/AltosSiteMapTile.java index 66da7c54..9e62bb47 100644 --- a/altosui/AltosSiteMapTile.java +++ b/altosui/AltosSiteMapTile.java @@ -43,6 +43,10 @@ public class AltosSiteMapTile extends JLayeredPane { public void clearMap() { fillLabel(mapLabel, Color.GRAY, px_size); + g2d = fillLabel(draw, new Color(127,127,127,0), px_size); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); } static Color stateColors[] = { @@ -85,6 +89,13 @@ public class AltosSiteMapTile extends JLayeredPane { repaint(); } + public void draw_circle(Point2D.Double pt) { + g2d.setColor(Color.RED); + g2d.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10); + g2d.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40); + g2d.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70); + } + public static Graphics2D fillLabel(JLabel l, Color c, int px_size) { BufferedImage img = new BufferedImage(px_size, px_size, BufferedImage.TYPE_INT_ARGB); -- cgit v1.2.3 From 6796d9e253a808824ba32cdb008da8bf302780fc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jul 2011 15:53:13 -0700 Subject: Fix NCR Pawnee location Signed-off-by: Keith Packard --- altosui/launch-sites.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/launch-sites.txt b/altosui/launch-sites.txt index baa0dfe9..bd5d1795 100644 --- a/altosui/launch-sites.txt +++ b/altosui/launch-sites.txt @@ -2,7 +2,7 @@ AHPRA BALLS:40.808333333333333:-119.15 ARS Rio Rancho:35.33475:-106.75361 KLOUDBusters Rocket Pasture:37.167833333:-97.73975 METRA Pine Island:41.31939:-74.47077 -NCR Pawnee:40.8875500:-104.6484750 +NCR Pawnee:40.885955:-104.63793 OPROC Discovery Bay:47.97808,-122.896383 OROC Brothers:43.79949786336483:-120.6485810681392 OROC Sheridan:45.044176:-123.314323 -- cgit v1.2.3 From 7f6cce5749724dbb836aaa27bbeedf977106f6f3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jul 2011 16:43:41 -0700 Subject: Add HARA Bragg Farms site Signed-off-by: Keith Packard --- altosui/launch-sites.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/launch-sites.txt b/altosui/launch-sites.txt index bd5d1795..de7955e0 100644 --- a/altosui/launch-sites.txt +++ b/altosui/launch-sites.txt @@ -1,5 +1,6 @@ AHPRA BALLS:40.808333333333333:-119.15 ARS Rio Rancho:35.33475:-106.75361 +HARA Bragg Farms:34.895875:-86.616211 KLOUDBusters Rocket Pasture:37.167833333:-97.73975 METRA Pine Island:41.31939:-74.47077 NCR Pawnee:40.885955:-104.63793 -- cgit v1.2.3 From 6795d353be91df96a571cebc237e6a54a065a380 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jul 2011 16:44:10 -0700 Subject: altosui: Change continutity colors to yellow/magenta Makes them stand apart from the accel/speed lines Signed-off-by: Keith Packard --- altosui/AltosGraphUI.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 03aae652..a27aa37f 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -23,6 +23,9 @@ public class AltosGraphUI extends JFrame static final private Color green = new Color(31,194,31); static final private Color blue = new Color(31,31,194); static final private Color black = new Color(31,31,31); + static final private Color yellow = new Color(194,194,31); + static final private Color cyan = new Color(31,194,194); + static final private Color magenta = new Color(194,31,194); static private class OverallGraphs { AltosGraphTime.Element height = @@ -71,7 +74,7 @@ public class AltosGraphUI extends JFrame }; AltosGraphTime.Element drogue_voltage = - new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", blue) + new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", yellow) { public void gotTimeData(double time, AltosDataPoint d) { double v = d.drogue_voltage(); @@ -81,7 +84,7 @@ public class AltosGraphUI extends JFrame }; AltosGraphTime.Element main_voltage = - new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", green) + new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", magenta) { public void gotTimeData(double time, AltosDataPoint d) { double v = d.main_voltage(); -- cgit v1.2.3 From 95201e7fe4a6a7ec42321e8dbad3aea3bbf4c840 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 2 Aug 2011 17:40:02 -0700 Subject: altosui: Standard text field in flight UI needs more width (now 20) Latitude and longitude take more than 16 characters. Signed-off-by: Keith Packard --- altosui/Altos.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 8d5916ad..1acce949 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -98,7 +98,7 @@ public class Altos { static final Font value_font = new Font("Monospaced", Font.PLAIN, 22); static final Font status_font = new Font("SansSerif", Font.BOLD, 24); - static final int text_width = 16; + static final int text_width = 20; static void initialize_map() { -- cgit v1.2.3 From 37c41c962ea4631e62307a57d2ce6572b87fd743 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 2 Aug 2011 17:41:02 -0700 Subject: altosui: Parse accel cal from 'c s' command These fields weren't used before, so the code to parse them hadn't been written. Signed-off-by: Keith Packard --- altosui/AltosConfigData.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 3f0e9af3..6b80171a 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -95,6 +95,15 @@ public class AltosConfigData implements Iterable { try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} + try { + if (line.startsWith("Accel cal")) { + String[] bits = line.split("\\s+"); + if (bits.length >= 6) { + accel_cal_plus = Integer.parseInt(bits[3]); + accel_cal_minus = Integer.parseInt(bits[5]); + } + } + } catch (Exception e) {} try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} -- cgit v1.2.3 From 3cc2eed6cdafe788a8617ab45c6664077e76411e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 2 Aug 2011 18:01:52 -0700 Subject: altosui: Simple timeouts don't work with query data To get the query to come back, it's best to abort and retry the command, other wise the command may have been lost to the previous connection. Signed-off-by: Keith Packard --- altosui/AltosConfigData.java | 2 +- altosui/AltosSerial.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 6b80171a..1d50ade9 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -85,7 +85,7 @@ public class AltosConfigData implements Iterable { serial_line.printf("c s\nv\n"); lines = new LinkedList(); for (;;) { - String line = serial_line.get_reply(5000); + String line = serial_line.get_reply_no_dialog(5000); if (line == null) throw new TimeoutException(); if (line.contains("Syntax error")) diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 8f8f99d7..cb82a574 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -233,12 +233,14 @@ public class AltosSerial implements Runnable { abort = false; timeout_started = false; for (;;) { + System.out.printf("timeout %d\n", timeout); AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); if (line != null) { stop_timeout_dialog(); --in_reply; return line.line; } + System.out.printf("no line remote %b can_cancel %b\n", remote, can_cancel); if (!remote || !can_cancel || check_timeout()) { --in_reply; return null; @@ -246,6 +248,14 @@ public class AltosSerial implements Runnable { } } + public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { + flush_output(); + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) + return line.line; + return null; + } + public void add_monitor(LinkedBlockingQueue q) { set_monitor(true); monitors.add(q); -- cgit v1.2.3 From 11a2bb8e28df7ed87542f2ee726f877971f5d52a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 2 Aug 2011 17:41:53 -0700 Subject: altosui: Add idle monitor dialog This monitors a telemetrum device in idle mode, either directly or through a teledongle, allowing the GPS status and batteries to be monitored without resorting to placing the device in pad mode. Signed-off-by: Keith Packard --- altosui/AltosIdleMonitorUI.java | 388 ++++++++++++++++++++++++++++++++++++++++ altosui/AltosState.java | 2 +- altosui/AltosUI.java | 14 ++ altosui/Makefile.am | 1 + 4 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 altosui/AltosIdleMonitorUI.java (limited to 'altosui') diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java new file mode 100644 index 00000000..a4262cae --- /dev/null +++ b/altosui/AltosIdleMonitorUI.java @@ -0,0 +1,388 @@ +/* + * Copyright © 2010 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosADC { + int tick; + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + + public AltosADC(AltosSerial serial) throws InterruptedException, TimeoutException { + serial.printf("a\n"); + for (;;) { + String line = serial.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + for (int i = 0; i < items.length;) { + if (items[i].equals("tick:")) { + tick = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("accel:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pres:")) { + pres = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + drogue = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + } + break; + } + } +} + +class AltosGPSQuery extends AltosGPS { + public AltosGPSQuery (AltosSerial serial) throws TimeoutException, InterruptedException { + serial.printf("g\n"); + for (;;) { + String line = serial.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] bits = line.split("\\s+"); + if (bits.length == 0) + continue; + if (line.startsWith("Date:")) { + if (bits.length < 2) + continue; + String[] d = bits[1].split(":"); + if (d.length < 3) + continue; + year = Integer.parseInt(d[0]) + 2000; + month = Integer.parseInt(d[1]); + day = Integer.parseInt(d[2]); + continue; + } + if (line.startsWith("Time:")) { + if (bits.length < 2) + continue; + String[] d = bits[1].split("/"); + if (d.length < 3) + continue; + hour = Integer.parseInt(d[0]); + minute = Integer.parseInt(d[1]); + second = Integer.parseInt(d[2]); + continue; + } + if (line.startsWith("Lat/Lon:")) { + if (bits.length < 3) + continue; + lat = Integer.parseInt(bits[1]) * 1.0e-7; + lon = Integer.parseInt(bits[2]) * 1.0e-7; + continue; + } + if (line.startsWith("Alt:")) { + if (bits.length < 2) + continue; + alt = Integer.parseInt(bits[1]); + continue; + } + if (line.startsWith("Flags:")) { + if (bits.length < 2) + continue; + int status = Integer.decode(bits[1]); + connected = (status & Altos.AO_GPS_RUNNING) != 0; + locked = (status & Altos.AO_GPS_VALID) != 0; + continue; + } + if (line.startsWith("Sats:")) { + if (bits.length < 2) + continue; + nsat = Integer.parseInt(bits[1]); + cc_gps_sat = new AltosGPSSat[nsat]; + for (int i = 0; i < nsat; i++) { + int svid = Integer.parseInt(bits[2+i*2]); + int cc_n0 = Integer.parseInt(bits[3+i*2]); + cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0); + } + } + if (line.startsWith("done")) + break; + if (line.startsWith("Syntax error")) + break; + } + } +} + +class AltosIdleMonitor extends Thread { + AltosDevice device; + AltosSerial serial; + AltosIdleMonitorUI ui; + AltosState state; + boolean remote; + int channel; + AltosState previous_state; + AltosConfigData config_data; + AltosADC adc; + AltosGPS gps; + + void update_state() throws InterruptedException, TimeoutException { + AltosRecord record = new AltosRecord(); + + try { + if (remote) { + set_channel(channel); + serial.start_remote(); + } else + serial.flush_input(); + config_data = new AltosConfigData(serial); + adc = new AltosADC(serial); + gps = new AltosGPSQuery(serial); + } finally { + if (remote) + serial.stop_remote(); + } + + record.version = 0; + record.callsign = config_data.callsign; + record.serial = config_data.serial; + record.flight = 0; + record.rssi = 0; + record.status = 0; + record.state = Altos.ao_flight_idle; + + record.tick = adc.tick; + record.accel = adc.accel; + record.pres = adc.pres; + record.batt = adc.batt; + record.temp = adc.temp; + record.drogue = adc.drogue; + record.main = adc.main; + + record.ground_accel = record.accel; + record.ground_pres = record.pres; + record.accel_plus_g = config_data.accel_cal_plus; + record.accel_minus_g = config_data.accel_cal_minus; + record.acceleration = 0; + record.speed = 0; + record.height = 0; + record.gps = gps; + state = new AltosState (record, state); + } + + void set_channel(int in_channel) { + channel = in_channel; + } + + public void post_state() { + Runnable r = new Runnable() { + public void run() { + ui.update(state); + } + }; + SwingUtilities.invokeLater(r); + } + + public void run() { + try { + for (;;) { + try { + update_state(); + post_state(); + } catch (TimeoutException te) { + } + Thread.sleep(1000); + } + } catch (InterruptedException ie) { + serial.close(); + } + } + + public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote) + throws FileNotFoundException, AltosSerialInUseException { + device = in_device; + ui = in_ui; + serial = new AltosSerial(device); + remote = in_remote; + state = null; + } +} + +public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { + AltosDevice device; + JTabbedPane pane; + AltosPad pad; + AltosInfoTable flightInfo; + AltosFlightStatus flightStatus; + AltosIdleMonitor thread; + int serial; + boolean remote; + + void stop_display() { + if (thread != null && thread.isAlive()) { + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException ie) {} + } + thread = null; + } + + void disconnect() { + stop_display(); + } + + public void reset() { + pad.reset(); + flightInfo.clear(); + } + + public void show(AltosState state, int crc_errors) { + try { + pad.show(state, crc_errors); + flightStatus.show(state, crc_errors); + flightInfo.show(state, crc_errors); + } catch (Exception e) { + System.out.print("Show exception" + e); + } + } + + public void update(AltosState state) { + show (state, 0); + } + + Container bag; + JComboBox channels; + + public AltosIdleMonitorUI(JFrame in_owner) throws FileNotFoundException, AltosSerialInUseException { + + device = AltosDeviceDialog.show(in_owner, Altos.product_any); + remote = false; + if (!device.matchProduct(Altos.product_telemetrum)) + remote = true; + + serial = device.getSerial(); + bag = getContentPane(); + bag.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + + java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg"); + if (imgURL != null) + setIconImage(new ImageIcon(imgURL).getImage()); + + setTitle(String.format("AltOS %s", device.toShortString())); + + /* Stick channel selector at top of table for telemetry monitoring */ + if (remote && serial >= 0) { + // Channel menu + channels = new AltosChannelMenu(AltosPreferences.channel(serial)); + channels.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int channel = channels.getSelectedIndex(); + thread.set_channel(channel); + } + }); + c.gridx = 0; + c.gridy = 0; + c.insets = new Insets(3, 3, 3, 3); + c.anchor = GridBagConstraints.WEST; + bag.add (channels, c); + } + + + /* Flight status is always visible */ + flightStatus = new AltosFlightStatus(); + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.gridwidth = 2; + bag.add(flightStatus, c); + c.gridwidth = 1; + + /* The rest of the window uses a tabbed pane to + * show one of the alternate data views + */ + pane = new JTabbedPane(); + + pad = new AltosPad(); + pane.add("Launch Pad", pad); + + flightInfo = new AltosInfoTable(); + pane.add("Table", new JScrollPane(flightInfo)); + + /* Make the tabbed pane use the rest of the window space */ + c.gridx = 0; + c.gridy = 2; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + c.gridwidth = 2; + bag.add(pane, c); + + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + disconnect(); + setVisible(false); + dispose(); + } + }); + + pack(); + setVisible(true); + + thread = new AltosIdleMonitor(this, device, remote); + + thread.start(); + } +} diff --git a/altosui/AltosState.java b/altosui/AltosState.java index 0ff2479e..d374aed8 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -130,7 +130,7 @@ public class AltosState { time_change = 0; } - if (state == Altos.ao_flight_pad) { + if (state == Altos.ao_flight_pad || state == Altos.ao_flight_idle) { /* Track consecutive 'good' gps reports, waiting for 10 of them */ if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index d8c8d61c..9b724fd7 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -187,6 +187,13 @@ public class AltosUI extends JFrame { } }); + b = addButton(2, 2, "Monitor Idle"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + IdleMonitor(); + } + }); + setTitle("AltOS"); pane.doLayout(); @@ -300,6 +307,13 @@ public class AltosUI extends JFrame { new AltosConfigureUI(AltosUI.this, voice); } + private void IdleMonitor() { + try { + new AltosIdleMonitorUI(this); + } catch (Exception e) { + } + } + static AltosRecordIterable open_logfile(String filename) { File file = new File (filename); try { diff --git a/altosui/Makefile.am b/altosui/Makefile.am index e3075d41..008bd097 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -55,6 +55,7 @@ altosui_JAVA = \ AltosGreatCircle.java \ AltosHexfile.java \ Altos.java \ + AltosIdleMonitorUI.java \ AltosIgnite.java \ AltosIgniteUI.java \ AltosInfoTable.java \ -- cgit v1.2.3 From 6492218fc316f8cf6214a577807a8dd0a80a9b6a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 2 Aug 2011 19:07:56 -0700 Subject: altos/altosui: Add pad orientation configure option Allow TeleMetrum to be operated with the antenna pointing downwards on the pad. This provides some additional flexibility when designing an ebay. The accelerometer calibration levels are flipped around to match, so no re-calibration should be required. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 9 ++++++-- altosui/AltosConfigUI.java | 56 +++++++++++++++++++++++++++++++++++++++++----- altosui/AltosSerial.java | 1 - src/ao.h | 6 ++++- src/ao_config.c | 39 +++++++++++++++++++++++++++++++- src/ao_flight_test.c | 4 ++++ src/ao_sample.c | 2 ++ 7 files changed, 107 insertions(+), 10 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index e3c30d4d..04d75528 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -71,6 +71,7 @@ public class AltosConfig implements ActionListener { int_ref radio_calibration; int_ref flight_log_max; int_ref ignite_mode; + int_ref pad_orientation; string_ref version; string_ref product; string_ref callsign; @@ -132,6 +133,7 @@ public class AltosConfig implements ActionListener { config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_flight_log_max(flight_log_max.get()); config_ui.set_ignite_mode(ignite_mode.get()); + config_ui.set_pad_orientation(pad_orientation.get()); config_ui.set_callsign(callsign.get()); config_ui.set_clean(); config_ui.make_visible(); @@ -139,12 +141,10 @@ public class AltosConfig implements ActionListener { void process_line(String line) { if (line == null) { - System.out.printf("timeout\n"); abort(); return; } if (line.equals("done")) { - System.out.printf("done\n"); if (serial_line != null) update_ui(); return; @@ -156,6 +156,7 @@ public class AltosConfig implements ActionListener { get_int(line, "Radio cal:", radio_calibration); get_int(line, "Max flight log:", flight_log_max); get_int(line, "Ignite mode:", ignite_mode); + get_int(line, "Pad orientation:", pad_orientation); get_string(line, "Callsign:", callsign); get_string(line,"software-version", version); get_string(line,"product", product); @@ -229,6 +230,8 @@ public class AltosConfig implements ActionListener { serial_line.printf("c l %d\n", flight_log_max.get()); if (ignite_mode.get() >= 0) serial_line.printf("c i %d\n", ignite_mode.get()); + if (pad_orientation.get() >= 0) + serial_line.printf("c o %d\n", pad_orientation.get()); serial_line.printf("c w\n"); } catch (InterruptedException ie) { } finally { @@ -312,6 +315,7 @@ public class AltosConfig implements ActionListener { radio_calibration.set(config_ui.radio_calibration()); flight_log_max.set(config_ui.flight_log_max()); ignite_mode.set(config_ui.ignite_mode()); + pad_orientation.set(config_ui.pad_orientation()); callsign.set(config_ui.callsign()); run_serial_thread(serial_mode_save); } @@ -347,6 +351,7 @@ public class AltosConfig implements ActionListener { radio_calibration = new int_ref(1186611); flight_log_max = new int_ref(0); ignite_mode = new int_ref(-1); + pad_orientation = new int_ref(-1); callsign = new string_ref("N0CALL"); version = new string_ref("unknown"); product = new string_ref("unknown"); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 6f635b9d..1a48c1d3 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -47,6 +47,7 @@ public class AltosConfigUI JLabel radio_calibration_label; JLabel flight_log_max_label; JLabel ignite_mode_label; + JLabel pad_orientation_label; JLabel callsign_label; public boolean dirty; @@ -61,6 +62,7 @@ public class AltosConfigUI JTextField radio_calibration_value; JComboBox flight_log_max_value; JComboBox ignite_mode_value; + JComboBox pad_orientation_value; JTextField callsign_value; JButton save; @@ -91,6 +93,11 @@ public class AltosConfigUI "Redundant Main", }; + static String[] pad_orientation_values = { + "Antenna Up", + "Antenna Down", + }; + static String[] radio_channel_values = new String[10]; { for (int i = 0; i <= 9; i++) @@ -358,9 +365,33 @@ public class AltosConfigUI ignite_mode_value.addItemListener(this); pane.add(ignite_mode_value, c); - /* Buttons */ + /* Pad orientation */ c = new GridBagConstraints(); c.gridx = 0; c.gridy = 10; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + pad_orientation_label = new JLabel("Pad Orientation:"); + pane.add(pad_orientation_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 10; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + pad_orientation_value = new JComboBox(pad_orientation_values); + pad_orientation_value.setEditable(false); + pad_orientation_value.addItemListener(this); + pane.add(pad_orientation_value, c); + + /* Buttons */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 11; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -371,7 +402,7 @@ public class AltosConfigUI save.setActionCommand("Save"); c = new GridBagConstraints(); - c.gridx = 2; c.gridy = 10; + c.gridx = 2; c.gridy = 11; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -382,7 +413,7 @@ public class AltosConfigUI reset.setActionCommand("Reset"); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 10; + c.gridx = 4; c.gridy = 11; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -393,7 +424,7 @@ public class AltosConfigUI reboot.setActionCommand("Reboot"); c = new GridBagConstraints(); - c.gridx = 6; c.gridy = 10; + c.gridx = 6; c.gridy = 11; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_END; @@ -538,13 +569,28 @@ public class AltosConfigUI } else { ignite_mode_value.setEnabled(true); } - ignite_mode_value.setSelectedItem(Integer.toString(new_ignite_mode)); + ignite_mode_value.setSelectedIndex(new_ignite_mode); } public int ignite_mode() { return ignite_mode_value.getSelectedIndex(); } + + public void set_pad_orientation(int new_pad_orientation) { + if (new_pad_orientation < 0) { + pad_orientation_value.setEnabled(false); + new_pad_orientation = 0; + } else { + pad_orientation_value.setEnabled(true); + } + pad_orientation_value.setSelectedIndex(new_pad_orientation); + } + + public int pad_orientation() { + return pad_orientation_value.getSelectedIndex(); + } + public void set_clean() { dirty = false; } diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index cb82a574..f45aa18b 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -233,7 +233,6 @@ public class AltosSerial implements Runnable { abort = false; timeout_started = false; for (;;) { - System.out.printf("timeout %d\n", timeout); AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); if (line != null) { stop_timeout_dialog(); diff --git a/src/ao.h b/src/ao.h index 9cde9cba..b315af7a 100644 --- a/src/ao.h +++ b/src/ao.h @@ -1358,7 +1358,7 @@ ao_igniter_init(void); */ #define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 5 +#define AO_CONFIG_MINOR 6 struct ao_config { uint8_t major; @@ -1372,12 +1372,16 @@ struct ao_config { uint32_t radio_cal; /* minor version 3 */ uint32_t flight_log_max; /* minor version 4 */ uint8_t ignite_mode; /* minor version 5 */ + uint8_t pad_orientation; /* minor version 6 */ }; #define AO_IGNITE_MODE_DUAL 0 #define AO_IGNITE_MODE_APOGEE 1 #define AO_IGNITE_MODE_MAIN 2 +#define AO_PAD_ORIENTATION_ANTENNA_UP 0 +#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 + extern __xdata struct ao_config ao_config; #define AO_CONFIG_MAX_SIZE 128 diff --git a/src/ao_config.c b/src/ao_config.c index 48349886..215dda92 100644 --- a/src/ao_config.c +++ b/src/ao_config.c @@ -28,6 +28,7 @@ __xdata uint8_t ao_config_mutex; #define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000 #define AO_CONFIG_DEFAULT_APOGEE_DELAY 0 #define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL +#define AO_CONFIG_DEFAULT_PAD_ORIENTATION AO_PAD_ORIENTATION_ANTENNA_UP #if USE_INTERNAL_EEPROM #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ao_storage_config #else @@ -77,6 +78,7 @@ _ao_config_get(void) ao_config.radio_cal = ao_radio_cal; ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX; ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; + ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION; ao_config_dirty = 1; } if (ao_config.minor < AO_CONFIG_MINOR) { @@ -97,6 +99,8 @@ _ao_config_get(void) /* Fixupes for minor version 5 */ if (ao_config.minor < 5) ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE; + if (ao_config.minor < 6) + ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION; ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; } @@ -357,7 +361,36 @@ ao_config_ignite_mode_set(void) __reentrant ao_config.ignite_mode = ao_cmd_lex_i; ao_config_dirty = 1; ao_mutex_put(&ao_config_mutex); - ao_config_log_show(); + ao_config_ignite_mode_show(); +} +#endif + +#if HAS_IGNITE +void +ao_config_pad_orientation_show(void) __reentrant +{ + printf("Pad orientation: %d\n", ao_config.pad_orientation); +} + +void +ao_config_pad_orientation_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + ao_mutex_get(&ao_config_mutex); + _ao_config_get(); + ao_cmd_lex_i &= 1; + if (ao_config.pad_orientation != ao_cmd_lex_i) { + uint16_t t; + t = ao_config.accel_plus_g; + ao_config.accel_plus_g = 0x7fff - ao_config.accel_minus_g; + ao_config.accel_minus_g = 0x7fff - t; + } + ao_config.pad_orientation = ao_cmd_lex_i; + ao_config_dirty = 1; + ao_mutex_put(&ao_config_mutex); + ao_config_pad_orientation_show(); } #endif @@ -400,6 +433,10 @@ __code struct ao_config_var ao_config_vars[] = { #if HAS_IGNITE { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode", ao_config_ignite_mode_set, ao_config_ignite_mode_show }, +#endif +#if HAS_ACCEL + { "o <0 antenna up, 1 antenna down>\0Set pad orientation", + ao_config_pad_orientation_set,ao_config_pad_orientation_show }, #endif { "s\0Show", ao_config_show, ao_config_show }, diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index e55d5ade..56733c89 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -179,8 +179,12 @@ struct ao_config { uint16_t main_deploy; int16_t accel_plus_g; int16_t accel_minus_g; + uint8_t pad_orientation; }; +#define AO_PAD_ORIENTATION_ANTENNA_UP 0 +#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1 + #define ao_config_get() struct ao_config ao_config; diff --git a/src/ao_sample.c b/src/ao_sample.c index ac156646..88ba58c5 100644 --- a/src/ao_sample.c +++ b/src/ao_sample.c @@ -179,6 +179,8 @@ ao_sample(void) * just dropped a bit of noise off the low end. */ ao_sample_accel = (uint16_t) ((((uint32_t) ao_sample_accel << 16) / (ao_accel_ref[ao_sample_adc] << 1))) >> 1; + if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) + ao_sample_accel = 0x7fff - ao_sample_accel; ao_adc->accel = ao_sample_accel; #endif #endif -- cgit v1.2.3 From 7207a95823dc2a27906759528dd88256cb20679f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 12:04:00 -0700 Subject: altosui: Change button to 'Configure Altimeter' Now that we've got more than one model. Signed-off-by: Keith Packard --- altosui/AltosUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 9b724fd7..033f233c 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -137,7 +137,7 @@ public class AltosUI extends JFrame { ExportData(); } }); - b = addButton(0, 1, "Configure TeleMetrum"); + b = addButton(0, 1, "Configure Altimter"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ConfigureTeleMetrum(); -- cgit v1.2.3 From f03ca0ab8799bfa5100eaa2577cfd7b9c37d05bf Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 7 Aug 2011 14:52:29 -0700 Subject: altosui: Add dialogs to configure 'common' frequencies These are stored in preferences, but not yet hooked up to the TM/TD configure dialogs Signed-off-by: Keith Packard --- altosui/AltosConfigFreqUI.java | 418 +++++++++++++++++++++++++++++++++++++++++ altosui/AltosConfigureUI.java | 18 +- altosui/AltosFrequency.java | 51 +++++ altosui/AltosPreferences.java | 66 +++++++ altosui/Makefile.am | 2 + 5 files changed, 553 insertions(+), 2 deletions(-) create mode 100644 altosui/AltosConfigFreqUI.java create mode 100644 altosui/AltosFrequency.java (limited to 'altosui') diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java new file mode 100644 index 00000000..d68151ec --- /dev/null +++ b/altosui/AltosConfigFreqUI.java @@ -0,0 +1,418 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import javax.swing.plaf.basic.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosEditFreqUI extends JDialog implements ActionListener { + Frame frame; + JTextField frequency; + JTextField description; + JButton ok_button, cancel_button; + boolean got_ok; + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if ("ok".equals(cmd)) { + got_ok = true; + setVisible(false); + } + if ("cancel".equals(cmd)) { + got_ok = false; + setVisible(false); + } + } + + public AltosFrequency get() { + if (!got_ok) + return null; + + String f_s = frequency.getText(); + String d_s = description.getText(); + + try { + double f_d = Double.parseDouble(f_s); + + return new AltosFrequency(f_d, d_s); + } catch (NumberFormatException ne) { + } + return null; + } + + public AltosEditFreqUI(Frame in_frame, AltosFrequency existing) { + super(in_frame, true); + + got_ok = false; + frame = in_frame; + + Container pane = getContentPane(); + pane.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets (4,4,4,4); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(new JLabel("Frequency"), c); + + frequency = new JTextField(12); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 1; + c.gridy = 0; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(frequency, c); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(new JLabel("Description"), c); + + description = new JTextField(12); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(description, c); + + ok_button = new JButton("OK"); + ok_button.setActionCommand("ok"); + ok_button.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(ok_button, c); + + cancel_button = new JButton("Cancel"); + cancel_button.setActionCommand("cancel"); + cancel_button.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(cancel_button, c); + + if (existing == null) + setTitle("Add New Frequency"); + else { + setTitle("Edit Existing Frequency"); + frequency.setText(String.format("%7.3f", existing.frequency)); + description.setText(existing.description); + } + getRootPane().setDefaultButton(ok_button); + + pack(); + setLocationRelativeTo(frame); + + } + + public AltosEditFreqUI(Frame in_frame) { + this(in_frame, (AltosFrequency) null); + } +} + +public class AltosConfigFreqUI extends JDialog implements ActionListener { + + Frame frame; + LinkedList listeners; + + class FrequencyList extends JList { + DefaultListModel list_model; + + public void add(AltosFrequency frequency) { + int i; + for (i = 0; i < list_model.size(); i++) { + AltosFrequency f = (AltosFrequency) list_model.get(i); + if (f.frequency == frequency.frequency) + return; + if (f.frequency > frequency.frequency) + break; + } + list_model.insertElementAt(frequency, i); + } + + public void remove(AltosFrequency frequency) { + list_model.removeElement(frequency); + } + + //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); + } + + public AltosFrequency selected() { + AltosFrequency f = (AltosFrequency) getSelectedValue(); + return f; + } + + public AltosFrequency[] frequencies() { + AltosFrequency[] ret; + + ret = new AltosFrequency[list_model.size()]; + for (int i = 0; i < list_model.size(); i++) + ret[i] = (AltosFrequency) list_model.get(i); + return ret; + } + + public FrequencyList(AltosFrequency[] in_frequencies) { + list_model = new DefaultListModel(); + setModel(list_model); + setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + setLayoutOrientation(JList.HORIZONTAL_WRAP); + for (int i = 0; i < in_frequencies.length; i++) { + add(in_frequencies[i]); + } + setVisibleRowCount(in_frequencies.length); + } + } + + FrequencyList frequencies; + + void save_frequencies() { + AltosPreferences.set_common_frequencies(frequencies.frequencies()); + } + + JButton add, edit, remove; + + JButton cancel, ok; + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if ("ok".equals(cmd)) { + save_frequencies(); + setVisible(false); + } else if ("cancel".equals(cmd)) { + setVisible(false); + } else if ("add".equals(cmd)) { + AltosEditFreqUI ui = new AltosEditFreqUI(frame); + ui.setVisible(true); + AltosFrequency f = ui.get(); + if (f != null) + frequencies.add(f); + } else if ("edit".equals(cmd)) { + AltosFrequency old_f = frequencies.selected(); + if (old_f == null) + return; + AltosEditFreqUI ui = new AltosEditFreqUI(frame, old_f); + ui.setVisible(true); + AltosFrequency new_f = ui.get(); + if (new_f != null) { + if (old_f != null) + frequencies.remove(old_f); + frequencies.add(new_f); + } + } else if ("remove".equals(cmd)) { + AltosFrequency old_f = frequencies.selected(); + if (old_f == null) + return; + int ret = JOptionPane.showConfirmDialog(this, + String.format("Remove frequency \"%s\"?", + old_f.toShortString()), + "Remove Frequency", + JOptionPane.YES_NO_OPTION); + if (ret == JOptionPane.YES_OPTION) + frequencies.remove(old_f); + } + } + + public AltosFrequency[] frequencies() { + return frequencies.frequencies(); + } + + public AltosConfigFreqUI(Frame in_frame, + AltosFrequency[] in_frequencies) { + super(in_frame, "Manage Frequencies", true); + + frame = in_frame; + + listeners = new LinkedList(); + + frequencies = new FrequencyList(in_frequencies); + + Container pane = getContentPane(); + pane.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(4,4,4,4); + + /* + * Frequencies label and list + */ + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 1; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(new JLabel("Frequencies"), c); + + JScrollPane list_scroller = new JScrollPane(frequencies); + list_scroller.setAlignmentX(LEFT_ALIGNMENT); + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.WEST; + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 6; + c.gridheight = 2; + c.weightx = 1; + c.weighty = 1; + pane.add(list_scroller, c); + + add = new JButton("Add"); + add.setActionCommand("add"); + add.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 0; + c.gridy = 3; + c.gridwidth = 2; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(add, c); + + edit = new JButton("Edit"); + edit.setActionCommand("edit"); + edit.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 2; + c.gridy = 3; + c.gridwidth = 2; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(edit, c); + + remove = new JButton("Remove"); + remove.setActionCommand("remove"); + remove.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 4; + c.gridy = 3; + c.gridwidth = 2; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(remove, c); + + ok = new JButton("OK"); + ok.setActionCommand("ok"); + ok.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 0; + c.gridy = 4; + c.gridwidth = 3; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(ok, c); + + cancel = new JButton("Cancel"); + cancel.setActionCommand("cancel"); + cancel.addActionListener(this); + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.gridx = 3; + c.gridy = 4; + c.gridwidth = 3; + c.gridheight = 1; + c.weightx = 0; + c.weighty = 0; + pane.add(cancel, c); + + pack(); + setLocationRelativeTo(frame); + } + + public static void show(Component frameComp) { + Frame frame = JOptionPane.getFrameForComponent(frameComp); + AltosConfigFreqUI dialog; + + dialog = new AltosConfigFreqUI(frame, AltosPreferences.common_frequencies()); + dialog.setVisible(true); + } + +} diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index 0f5e4a3b..a8a70ffd 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -50,6 +50,7 @@ public class AltosConfigureUI JRadioButton serial_debug; JButton manage_bluetooth; + JButton manage_frequencies; /* DocumentListener interface methods */ public void changedUpdate(DocumentEvent e) { @@ -207,13 +208,26 @@ public class AltosConfigureUI AltosBTManage.show(owner, Altos.bt_known); } }); - c.gridx = 1; + c.gridx = 0; c.gridy = 6; - c.gridwidth = 3; + c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; pane.add(manage_bluetooth, c); + manage_frequencies = new JButton("Manage Frequencies"); + manage_frequencies.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + AltosConfigFreqUI.show(owner); + } + }); + c.gridx = 2; + c.gridy = 6; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(manage_frequencies, c); + /* And a close button at the bottom */ close = new JButton("Close"); close.addActionListener(new ActionListener() { diff --git a/altosui/AltosFrequency.java b/altosui/AltosFrequency.java new file mode 100644 index 00000000..8265eafc --- /dev/null +++ b/altosui/AltosFrequency.java @@ -0,0 +1,51 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import javax.swing.plaf.basic.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosFrequency { + double frequency; + String description; + + public String toString() { + return String.format("%7.3f MHz %-20.20s", + frequency, description); + } + + public String toShortString() { + return String.format("%7.3f MHz %s", + frequency, description); + } + + public AltosFrequency(double f, String d) { + frequency = f; + description = d; + } +} \ No newline at end of file diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index c8dee743..e92b9532 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -64,6 +64,9 @@ class AltosPreferences { /* Channel (map serial to channel) */ static Hashtable channels; + /* Frequency (map serial to frequency) */ + static Hashtable frequencies; + /* Telemetry (map serial to telemetry format) */ static Hashtable telemetries; @@ -79,6 +82,55 @@ class AltosPreferences { /* Serial debug */ static boolean serial_debug; + /* List of frequencies */ + final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; + static AltosFrequency[] common_frequencies; + + final static String frequency_count = "COUNT"; + final static String frequency_format = "FREQUENCY-%d"; + final static String description_format = "DESCRIPTION-%d"; + + static AltosFrequency[] load_common_frequencies() { + AltosFrequency[] frequencies = null; + boolean existing = false; + try { + existing = preferences.nodeExists(common_frequencies_node_name); + } catch (BackingStoreException be) { + existing = false; + } + if (existing) { + Preferences node = preferences.node(common_frequencies_node_name); + int count = node.getInt(frequency_count, 0); + + frequencies = new AltosFrequency[count]; + for (int i = 0; i < count; i++) { + double frequency; + String description; + + frequency = node.getDouble(String.format(frequency_format, i), 0.0); + description = node.get(String.format(description_format, i), null); + frequencies[i] = new AltosFrequency(frequency, description); + } + } else { + frequencies = new AltosFrequency[10]; + for (int i = 0; i < 10; i++) { + frequencies[i] = new AltosFrequency(434.550 + i * .1, + String.format("Channel %d", i)); + } + } + return frequencies; + } + + static void save_common_frequencies(AltosFrequency[] frequencies) { + Preferences node = preferences.node(common_frequencies_node_name); + + node.putInt(frequency_count, frequencies.length); + for (int i = 0; i < frequencies.length; i++) { + node.putDouble(String.format(frequency_format, i), frequencies[i].frequency); + node.put(String.format(description_format, i), frequencies[i].description); + } + } + public static void init() { preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); @@ -112,6 +164,8 @@ class AltosPreferences { serial_debug = preferences.getBoolean(serialDebugPreference, false); AltosSerial.set_debug(serial_debug); + + common_frequencies = load_common_frequencies(); } static { init(); } @@ -273,4 +327,16 @@ class AltosPreferences { public static Preferences bt_devices() { return preferences.node("bt_devices"); } + + public static AltosFrequency[] common_frequencies() { + return common_frequencies; + } + + public static void set_common_frequencies(AltosFrequency[] frequencies) { + common_frequencies = frequencies; + synchronized(preferences) { + save_common_frequencies(frequencies); + flush_preferences(); + } + } } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 008bd097..d6fd0e6d 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -16,6 +16,7 @@ altosui_JAVA = \ AltosChannelMenu.java \ AltosConfig.java \ AltosConfigData.java \ + AltosConfigFreqUI.java \ AltosConfigUI.java \ AltosConfigureUI.java \ AltosConvert.java \ @@ -50,6 +51,7 @@ altosui_JAVA = \ AltosFlightReader.java \ AltosFlightStatus.java \ AltosFlightUI.java \ + AltosFrequency.java \ AltosGPS.java \ AltosGPSSat.java \ AltosGreatCircle.java \ -- cgit v1.2.3 From 0e3e4f9c1e6a6bf972514f12c9d622258aa2aec2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 01:47:29 -0700 Subject: altosui: Convert from channels to frequencies Major areas: * Preferences are stored as frequencies instead of channels * Serial configuration is done using frequencies * UI is presented with frequency lists Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 54 +++++++++++++--- altosui/AltosConfigData.java | 4 +- altosui/AltosConfigFreqUI.java | 4 +- altosui/AltosConfigUI.java | 58 ++++++++++++------ altosui/AltosConvert.java | 33 ++++++++++ altosui/AltosEepromDelete.java | 15 ++--- altosui/AltosEepromDownload.java | 13 ++-- altosui/AltosFlightReader.java | 7 ++- altosui/AltosFlightUI.java | 26 +++++--- altosui/AltosFreqList.java | 87 ++++++++++++++++++++++++++ altosui/AltosFrequency.java | 6 ++ altosui/AltosIdleMonitorUI.java | 35 ++++++----- altosui/AltosIgnite.java | 37 ++++++----- altosui/AltosPreferences.java | 47 ++++++++++---- altosui/AltosScanUI.java | 125 ++++++++++++++++++++++++-------------- altosui/AltosSerial.java | 72 +++++++++++++++------- altosui/AltosTelemetryReader.java | 27 ++++++-- altosui/AltosUI.java | 12 +++- altosui/Makefile.am | 1 + 19 files changed, 486 insertions(+), 177 deletions(-) create mode 100644 altosui/AltosFreqList.java (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 04d75528..694ef4db 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -64,6 +64,8 @@ public class AltosConfig implements ActionListener { AltosDevice device; AltosSerial serial_line; boolean remote; + AltosConfigData remote_config_data; + double remote_frequency; int_ref serial; int_ref main_deploy; int_ref apogee_delay; @@ -72,6 +74,7 @@ public class AltosConfig implements ActionListener { int_ref flight_log_max; int_ref ignite_mode; int_ref pad_orientation; + int_ref radio_setting; string_ref version; string_ref product; string_ref callsign; @@ -109,7 +112,7 @@ public class AltosConfig implements ActionListener { } } - void start_serial() throws InterruptedException { + void start_serial() throws InterruptedException, TimeoutException { serial_started = true; if (remote) serial_line.start_remote(); @@ -129,12 +132,13 @@ public class AltosConfig implements ActionListener { config_ui.set_version(version.get()); config_ui.set_main_deploy(main_deploy.get()); config_ui.set_apogee_delay(apogee_delay.get()); - config_ui.set_radio_channel(radio_channel.get()); + config_ui.set_radio_frequency(frequency()); config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_flight_log_max(flight_log_max.get()); config_ui.set_ignite_mode(ignite_mode.get()); config_ui.set_pad_orientation(pad_orientation.get()); config_ui.set_callsign(callsign.get()); + config_ui.set_radio_setting(radio_setting.get()); config_ui.set_clean(); config_ui.make_visible(); } @@ -157,6 +161,7 @@ public class AltosConfig implements ActionListener { get_int(line, "Max flight log:", flight_log_max); get_int(line, "Ignite mode:", ignite_mode); get_int(line, "Pad orientation:", pad_orientation); + get_int(line, "Radio setting:", radio_setting); get_string(line, "Callsign:", callsign); get_string(line,"software-version", version); get_string(line,"product", product); @@ -200,6 +205,7 @@ public class AltosConfig implements ActionListener { } } } catch (InterruptedException ie) { + } catch (TimeoutException te) { } finally { try { stop_serial(); @@ -211,16 +217,20 @@ public class AltosConfig implements ActionListener { void save_data() { try { - int channel; + double frequency = frequency(); + boolean has_setting = radio_setting.get() != 0; start_serial(); serial_line.printf("c m %d\n", main_deploy.get()); serial_line.printf("c d %d\n", apogee_delay.get()); - channel = radio_channel.get(); - serial_line.printf("c r %d\n", channel); + serial_line.set_radio_frequency(frequency, + has_setting, + radio_calibration.get()); if (remote) { serial_line.stop_remote(); - serial_line.set_channel(channel); - AltosPreferences.set_channel(device.getSerial(), channel); + serial_line.set_radio_frequency(frequency, + has_setting, + radio_calibration.get()); + AltosPreferences.set_frequency(device.getSerial(), frequency); serial_line.start_remote(); } if (!remote) @@ -234,6 +244,7 @@ public class AltosConfig implements ActionListener { serial_line.printf("c o %d\n", pad_orientation.get()); serial_line.printf("c w\n"); } catch (InterruptedException ie) { + } catch (TimeoutException te) { } finally { try { stop_serial(); @@ -248,6 +259,7 @@ public class AltosConfig implements ActionListener { serial_line.printf("r eboot\n"); serial_line.flush_output(); } catch (InterruptedException ie) { + } catch (TimeoutException te) { } finally { try { stop_serial(); @@ -308,11 +320,32 @@ public class AltosConfig implements ActionListener { update_ui(); } + double frequency() { + int setting = radio_setting.get(); + + if (setting != 0) + return AltosConvert.radio_setting_to_frequency(setting, radio_calibration.get()); + else + return AltosConvert.radio_channel_to_frequency(radio_channel.get()); + } + + void set_frequency(double freq) { + int setting = radio_setting.get(); + + if (setting != 0) { + radio_setting.set(AltosConvert.radio_frequency_to_setting(freq, + radio_calibration.get())); + radio_channel.set(0); + } else { + radio_channel.set(AltosConvert.radio_frequency_to_channel(freq)); + } + } + void save_data() { main_deploy.set(config_ui.main_deploy()); apogee_delay.set(config_ui.apogee_delay()); - radio_channel.set(config_ui.radio_channel()); radio_calibration.set(config_ui.radio_calibration()); + set_frequency(config_ui.radio_frequency()); flight_log_max.set(config_ui.flight_log_max()); ignite_mode.set(config_ui.ignite_mode()); pad_orientation.set(config_ui.pad_orientation()); @@ -348,6 +381,7 @@ public class AltosConfig implements ActionListener { main_deploy = new int_ref(250); apogee_delay = new int_ref(0); radio_channel = new int_ref(0); + radio_setting = new int_ref(0); radio_calibration = new int_ref(1186611); flight_log_max = new int_ref(0); ignite_mode = new int_ref(-1); @@ -360,9 +394,9 @@ public class AltosConfig implements ActionListener { if (device != null) { try { serial_line = new AltosSerial(device); - if (!device.matchProduct(Altos.product_telemetrum)) - remote = true; try { + if (!device.matchProduct(Altos.product_telemetrum)) + remote = true; init_ui(); } catch (InterruptedException ie) { abort(); diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 1d50ade9..aa7a90de 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -47,6 +47,7 @@ public class AltosConfigData implements Iterable { int main_deploy; int apogee_delay; int radio_channel; + int radio_setting; String callsign; int accel_cal_plus, accel_cal_minus; int radio_calibration; @@ -85,7 +86,7 @@ public class AltosConfigData implements Iterable { serial_line.printf("c s\nv\n"); lines = new LinkedList(); for (;;) { - String line = serial_line.get_reply_no_dialog(5000); + String line = serial_line.get_reply(); if (line == null) throw new TimeoutException(); if (line.contains("Syntax error")) @@ -95,6 +96,7 @@ public class AltosConfigData implements Iterable { try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} + try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} try { if (line.startsWith("Accel cal")) { String[] bits = line.split("\\s+"); diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java index d68151ec..063d21b4 100644 --- a/altosui/AltosConfigFreqUI.java +++ b/altosui/AltosConfigFreqUI.java @@ -177,9 +177,9 @@ public class AltosConfigFreqUI extends JDialog implements ActionListener { int i; for (i = 0; i < list_model.size(); i++) { AltosFrequency f = (AltosFrequency) list_model.get(i); - if (f.frequency == frequency.frequency) + if (frequency.frequency == f.frequency) return; - if (f.frequency > frequency.frequency) + if (frequency.frequency < f.frequency) break; } list_model.insertElementAt(frequency, i); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 1a48c1d3..c109924e 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -43,8 +43,9 @@ public class AltosConfigUI JLabel serial_label; JLabel main_deploy_label; JLabel apogee_delay_label; - JLabel radio_channel_label; + JLabel frequency_label; JLabel radio_calibration_label; + JLabel radio_frequency_label; JLabel flight_log_max_label; JLabel ignite_mode_label; JLabel pad_orientation_label; @@ -58,7 +59,7 @@ public class AltosConfigUI JLabel serial_value; JComboBox main_deploy_value; JComboBox apogee_delay_value; - JComboBox radio_channel_value; + AltosFreqList radio_frequency_value; JTextField radio_calibration_value; JComboBox flight_log_max_value; JComboBox ignite_mode_value; @@ -98,13 +99,6 @@ public class AltosConfigUI "Antenna Down", }; - static String[] radio_channel_values = new String[10]; - { - for (int i = 0; i <= 9; i++) - radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)", - i, 434.550 + i * 0.1); - } - /* A window listener to catch closing events and tell the config code */ class ConfigListener extends WindowAdapter { AltosConfigUI ui; @@ -245,7 +239,7 @@ public class AltosConfigUI apogee_delay_value.addItemListener(this); pane.add(apogee_delay_value, c); - /* Radio channel */ + /* Frequency */ c = new GridBagConstraints(); c.gridx = 0; c.gridy = 5; c.gridwidth = 4; @@ -253,8 +247,8 @@ public class AltosConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = il; c.ipady = 5; - radio_channel_label = new JLabel("Radio Channel:"); - pane.add(radio_channel_label, c); + radio_frequency_label = new JLabel("Frequency:"); + pane.add(radio_frequency_label, c); c = new GridBagConstraints(); c.gridx = 4; c.gridy = 5; @@ -264,10 +258,9 @@ public class AltosConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = ir; c.ipady = 5; - radio_channel_value = new JComboBox(radio_channel_values); - radio_channel_value.setEditable(false); - radio_channel_value.addItemListener(this); - pane.add(radio_channel_value, c); + radio_frequency_value = new AltosFreqList(); + radio_frequency_value.addItemListener(this); + pane.add(radio_frequency_value, c); /* Radio Calibration */ c = new GridBagConstraints(); @@ -501,6 +494,7 @@ public class AltosConfigUI /* set and get all of the dialog values */ public void set_product(String product) { + radio_frequency_value.set_product(product); product_value.setText(product); } @@ -509,6 +503,7 @@ public class AltosConfigUI } public void set_serial(int serial) { + radio_frequency_value.set_serial(serial); serial_value.setText(String.format("%d", serial)); } @@ -528,12 +523,32 @@ public class AltosConfigUI return Integer.parseInt(apogee_delay_value.getSelectedItem().toString()); } - public void set_radio_channel(int new_radio_channel) { - radio_channel_value.setSelectedIndex(new_radio_channel); + public void set_radio_frequency(double new_radio_frequency) { + int i; + for (i = 0; i < radio_frequency_value.getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i); + + if (f.close(new_radio_frequency)) { + radio_frequency_value.setSelectedIndex(i); + return; + } + } + for (i = 0; i < radio_frequency_value.getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i); + + if (new_radio_frequency < f.frequency) + break; + } + String description = String.format("%s serial %s", + product_value.getText(), + serial_value.getText()); + AltosFrequency new_frequency = new AltosFrequency(new_radio_frequency, description); + AltosPreferences.add_common_frequency(new_frequency); + radio_frequency_value.insertItemAt(new_frequency, i); } - public int radio_channel() { - return radio_channel_value.getSelectedIndex(); + public double radio_frequency() { + return radio_frequency_value.frequency(); } public void set_radio_calibration(int new_radio_calibration) { @@ -548,6 +563,9 @@ public class AltosConfigUI callsign_value.setText(new_callsign); } + public void set_radio_setting(int new_radio_setting) { + } + public String callsign() { return callsign_value.getText(); } diff --git a/altosui/AltosConvert.java b/altosui/AltosConvert.java index 8cc1df27..6a9b699c 100644 --- a/altosui/AltosConvert.java +++ b/altosui/AltosConvert.java @@ -189,4 +189,37 @@ public class AltosConvert { { return ignite / 32767 * 15.0; } + + static double + radio_setting_to_frequency(int setting, int cal) { + double f; + + f = 434.550 * setting / cal; + /* Round to nearest 50KHz */ + f = Math.floor (20.0 * f + 0.5) / 20.0; + return f; + } + + static int + radio_frequency_to_setting(double frequency, int cal) { + double set = frequency / 434.550 * cal; + + return (int) Math.floor (set + 0.5); + } + + static double + radio_channel_to_frequency(int channel) { + return 434.550 + channel * 0.100; + } + + static int + radio_frequency_to_channel(double frequency) { + int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); + + if (channel < 0) + channel = 0; + if (channel > 9) + channel = 9; + return channel; + } } diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index ecd82c18..94951ced 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -84,11 +84,11 @@ public class AltosEepromDelete implements Runnable { } public void run () { - if (remote) - serial_line.start_remote(); - success = false; try { + if (remote) + serial_line.start_remote(); + for (AltosEepromLog log : flights) { if (log.delete) { DeleteLog(log); @@ -103,11 +103,12 @@ public class AltosEepromDelete implements Runnable { show_error (String.format("Connection to \"%s\" failed", serial_line.device.toShortString()), "Connection Failed"); + } finally { + if (remote) + serial_line.stop_remote(); + serial_line.flush_output(); + serial_line.close(); } - if (remote) - serial_line.stop_remote(); - serial_line.flush_output(); - serial_line.close(); if (listener != null) { Runnable r = new Runnable() { public void run() { diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 82f01ef5..64dcdff7 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -264,11 +264,11 @@ public class AltosEepromDownload implements Runnable { } public void run () { - if (remote) - serial_line.start_remote(); - try { boolean failed = false; + if (remote) + serial_line.start_remote(); + for (AltosEepromLog log : flights) { parse_exception = null; if (log.download) { @@ -295,11 +295,12 @@ public class AltosEepromDownload implements Runnable { serial_line.device.toShortString()), "Connection Failed", JOptionPane.ERROR_MESSAGE); + } finally { + if (remote) + serial_line.stop_remote(); + serial_line.flush_output(); } - if (remote) - serial_line.stop_remote(); monitor.done(); - serial_line.flush_output(); if (listener != null) { Runnable r = new Runnable() { public void run() { diff --git a/altosui/AltosFlightReader.java b/altosui/AltosFlightReader.java index f665bda8..3a171444 100644 --- a/altosui/AltosFlightReader.java +++ b/altosui/AltosFlightReader.java @@ -20,6 +20,7 @@ package altosui; import java.lang.*; import java.text.*; import java.io.*; +import java.util.concurrent.*; public class AltosFlightReader { String name; @@ -32,9 +33,13 @@ public class AltosFlightReader { void close(boolean interrupted) { } - void set_channel(int channel) { } + void set_frequency(double frequency) throws InterruptedException, TimeoutException { } + + void save_frequency() { } void set_telemetry(int telemetry) { } + void save_telemetry() { } + void update(AltosState state) throws InterruptedException { } } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 04bfc90d..8c3f821e 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -26,7 +26,7 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.*; public class AltosFlightUI extends JFrame implements AltosFlightDisplay { AltosVoice voice; @@ -118,7 +118,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { } Container bag; - JComboBox channels; + AltosFreqList frequencies; JComboBox telemetries; public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) { @@ -141,18 +141,25 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { /* Stick channel selector at top of table for telemetry monitoring */ if (serial >= 0) { // Channel menu - channels = new AltosChannelMenu(AltosPreferences.channel(serial)); - channels.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int channel = channels.getSelectedIndex(); - reader.set_channel(channel); - } + frequencies = new AltosFreqList(AltosPreferences.frequency(serial)); + frequencies.set_product("Monitor"); + frequencies.set_serial(serial); + frequencies.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + double frequency = frequencies.frequency(); + reader.save_frequency(); + try { + reader.set_frequency(frequency); + } catch (TimeoutException te) { + } catch (InterruptedException ie) { + } + } }); c.gridx = 0; c.gridy = 0; c.insets = new Insets(3, 3, 3, 3); c.anchor = GridBagConstraints.WEST; - bag.add (channels, c); + bag.add (frequencies, c); // Telemetry format menu telemetries = new JComboBox(); @@ -168,6 +175,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { public void actionPerformed(ActionEvent e) { int telemetry = telemetries.getSelectedIndex() + 1; reader.set_telemetry(telemetry); + reader.save_telemetry(); } }); c.gridx = 1; diff --git a/altosui/AltosFreqList.java b/altosui/AltosFreqList.java new file mode 100644 index 00000000..59b0e127 --- /dev/null +++ b/altosui/AltosFreqList.java @@ -0,0 +1,87 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosFreqList extends JComboBox { + + String product; + int serial; + int calibrate; + + public void set_frequency(double new_frequency) { + int i; + for (i = 0; i < getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) getItemAt(i); + + if (f.close(new_frequency)) { + setSelectedIndex(i); + return; + } + } + for (i = 0; i < getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) getItemAt(i); + + if (new_frequency < f.frequency) + break; + } + String description = String.format("%s serial %d", product, serial); + AltosFrequency frequency = new AltosFrequency(new_frequency, description); + AltosPreferences.add_common_frequency(frequency); + insertItemAt(frequency, i); + setMaximumRowCount(getItemCount()); + } + + public void set_product(String new_product) { + product = new_product; + } + + public void set_serial(int new_serial) { + serial = new_serial; + } + + public double frequency() { + AltosFrequency f = (AltosFrequency) getSelectedItem(); + if (f != null) + return f.frequency; + return 434.550; + } + + public AltosFreqList () { + super(AltosPreferences.common_frequencies()); + setMaximumRowCount(getItemCount()); + setEditable(false); + product = "Unknown"; + serial = 0; + } + + public AltosFreqList(double in_frequency) { + this(); + set_frequency(in_frequency); + } +} diff --git a/altosui/AltosFrequency.java b/altosui/AltosFrequency.java index 8265eafc..0617ce74 100644 --- a/altosui/AltosFrequency.java +++ b/altosui/AltosFrequency.java @@ -44,6 +44,12 @@ public class AltosFrequency { frequency, description); } + public boolean close(double f) { + double diff = Math.abs(frequency - f); + + return diff < 0.010; + } + public AltosFrequency(double f, String d) { frequency = f; description = d; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index a4262cae..0370efa9 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -167,7 +167,7 @@ class AltosIdleMonitor extends Thread { AltosIdleMonitorUI ui; AltosState state; boolean remote; - int channel; + double frequency; AltosState previous_state; AltosConfigData config_data; AltosADC adc; @@ -178,7 +178,7 @@ class AltosIdleMonitor extends Thread { try { if (remote) { - set_channel(channel); + serial.set_radio_frequency(frequency); serial.start_remote(); } else serial.flush_input(); @@ -217,8 +217,8 @@ class AltosIdleMonitor extends Thread { state = new AltosState (record, state); } - void set_channel(int in_channel) { - channel = in_channel; + void set_frequency(double in_frequency) { + frequency = in_frequency; } public void post_state() { @@ -246,7 +246,7 @@ class AltosIdleMonitor extends Thread { } public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote) - throws FileNotFoundException, AltosSerialInUseException { + throws FileNotFoundException, AltosSerialInUseException, InterruptedException, TimeoutException { device = in_device; ui = in_ui; serial = new AltosSerial(device); @@ -299,9 +299,10 @@ public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { } Container bag; - JComboBox channels; + AltosFreqList frequencies; - public AltosIdleMonitorUI(JFrame in_owner) throws FileNotFoundException, AltosSerialInUseException { + public AltosIdleMonitorUI(JFrame in_owner) + throws FileNotFoundException, AltosSerialInUseException, TimeoutException, InterruptedException { device = AltosDeviceDialog.show(in_owner, Altos.product_any); remote = false; @@ -320,21 +321,23 @@ public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { setTitle(String.format("AltOS %s", device.toShortString())); - /* Stick channel selector at top of table for telemetry monitoring */ + /* Stick frequency selector at top of table for telemetry monitoring */ if (remote && serial >= 0) { - // Channel menu - channels = new AltosChannelMenu(AltosPreferences.channel(serial)); - channels.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int channel = channels.getSelectedIndex(); - thread.set_channel(channel); - } + // Frequency menu + frequencies = new AltosFreqList(AltosPreferences.frequency(serial)); + frequencies.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + double frequency = frequencies.frequency(); + thread.set_frequency(frequency); + AltosPreferences.set_frequency(device.getSerial(), + frequency); + } }); c.gridx = 0; c.gridy = 0; c.insets = new Insets(3, 3, 3, 3); c.anchor = GridBagConstraints.WEST; - bag.add (channels, c); + bag.add (frequencies, c); } diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index 7a06c63d..3e52ea36 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -40,7 +40,7 @@ public class AltosIgnite { final static int Active = 2; final static int Open = 3; - private void start_serial() throws InterruptedException { + private void start_serial() throws InterruptedException, TimeoutException { serial_started = true; if (remote) serial.start_remote(); @@ -102,22 +102,25 @@ public class AltosIgnite { if (serial == null) return status; string_ref status_name = new string_ref(); - start_serial(); - serial.printf("t\n"); - for (;;) { - String line = serial.get_reply(5000); - if (line == null) - throw new TimeoutException(); - if (get_string(line, "Igniter: drogue Status: ", status_name)) - if (igniter == Apogee) - status = status(status_name.get()); - if (get_string(line, "Igniter: main Status: ", status_name)) { - if (igniter == Main) - status = status(status_name.get()); - break; + try { + start_serial(); + serial.printf("t\n"); + for (;;) { + String line = serial.get_reply(5000); + if (line == null) + throw new TimeoutException(); + if (get_string(line, "Igniter: drogue Status: ", status_name)) + if (igniter == Apogee) + status = status(status_name.get()); + if (get_string(line, "Igniter: main Status: ", status_name)) { + if (igniter == Main) + status = status(status_name.get()); + break; + } } + } finally { + stop_serial(); } - stop_serial(); return status; } @@ -145,6 +148,7 @@ public class AltosIgnite { break; } } catch (InterruptedException ie) { + } catch (TimeoutException te) { } finally { try { stop_serial(); @@ -166,7 +170,8 @@ public class AltosIgnite { serial.set_frame(frame); } - public AltosIgnite(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { + public AltosIgnite(AltosDevice in_device) + throws FileNotFoundException, AltosSerialInUseException, TimeoutException, InterruptedException { device = in_device; serial = new AltosSerial(device); diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index e92b9532..8609f94e 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -34,6 +34,9 @@ class AltosPreferences { /* channel preference name */ final static String channelPreferenceFormat = "CHANNEL-%d"; + /* frequency preference name */ + final static String frequencyPreferenceFormat = "FREQUENCY-%d"; + /* telemetry format preference name */ final static String telemetryPreferenceFormat = "TELEMETRY-%d"; @@ -61,9 +64,6 @@ class AltosPreferences { /* Map directory -- hangs of logdir */ static File mapdir; - /* Channel (map serial to channel) */ - static Hashtable channels; - /* Frequency (map serial to frequency) */ static Hashtable frequencies; @@ -148,7 +148,7 @@ class AltosPreferences { if (!mapdir.exists()) mapdir.mkdirs(); - channels = new Hashtable(); + frequencies = new Hashtable(); telemetries = new Hashtable(); @@ -242,20 +242,24 @@ class AltosPreferences { return mapdir; } - public static void set_channel(int serial, int new_channel) { - channels.put(serial, new_channel); + public static void set_frequency(int serial, double new_frequency) { + frequencies.put(serial, new_frequency); synchronized (preferences) { - preferences.putInt(String.format(channelPreferenceFormat, serial), new_channel); + preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); flush_preferences(); } } - public static int channel(int serial) { - if (channels.containsKey(serial)) - return channels.get(serial); - int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); - channels.put(serial, channel); - return channel; + public static double frequency(int serial) { + if (frequencies.containsKey(serial)) + return frequencies.get(serial); + double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); + if (frequency == 0.0) { + int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); + frequency = AltosConvert.radio_channel_to_frequency(channel); + } + frequencies.put(serial, frequency); + return frequency; } public static void set_telemetry(int serial, int new_telemetry) { @@ -339,4 +343,21 @@ class AltosPreferences { flush_preferences(); } } + + public static void add_common_frequency(AltosFrequency frequency) { + AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; + int i; + + for (i = 0; i < common_frequencies.length; i++) { + if (frequency.frequency == common_frequencies[i].frequency) + return; + if (frequency.frequency < common_frequencies[i].frequency) + break; + new_frequencies[i] = common_frequencies[i]; + } + new_frequencies[i] = frequency; + for (; i < common_frequencies.length; i++) + new_frequencies[i+1] = common_frequencies[i]; + set_common_frequencies(new_frequencies); + } } diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 96cab73b..9a483138 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -33,27 +33,27 @@ class AltosScanResult { String callsign; int serial; int flight; - int channel; + double frequency; int telemetry; boolean interrupted = false; public String toString() { - return String.format("%-9.9s serial %-4d flight %-4d (channel %-2d %s)", - callsign, serial, flight, channel, Altos.telemetry_name(telemetry)); + return String.format("%-9.9s serial %-4d flight %-4d (frequency %7.3f %s)", + callsign, serial, flight, frequency, Altos.telemetry_name(telemetry)); } public String toShortString() { - return String.format("%s %d %d %d %d", - callsign, serial, flight, channel, telemetry); + return String.format("%s %d %d %7.3f %d", + callsign, serial, flight, frequency, telemetry); } public AltosScanResult(String in_callsign, int in_serial, - int in_flight, int in_channel, int in_telemetry) { + int in_flight, double in_frequency, int in_telemetry) { callsign = in_callsign; serial = in_serial; flight = in_flight; - channel = in_channel; + frequency = in_frequency; telemetry = in_telemetry; } @@ -61,7 +61,7 @@ class AltosScanResult { return (callsign.equals(other.callsign) && serial == other.serial && flight == other.flight && - channel == other.channel && + frequency == other.frequency && telemetry == other.telemetry); } } @@ -107,20 +107,25 @@ public class AltosScanUI { AltosUI owner; AltosDevice device; + AltosConfigData config_data; AltosTelemetryReader reader; private JList list; private JLabel scanning_label; + private JLabel frequency_label; + private JLabel telemetry_label; private JButton cancel_button; private JButton monitor_button; javax.swing.Timer timer; AltosScanResults results = new AltosScanResults(); int telemetry; - int channel; + double frequency; final static int timeout = 1200; TelemetryHandler handler; Thread thread; + AltosFrequency[] frequencies; + int frequency_index; void scan_exception(Exception e) { if (e instanceof FileNotFoundException) { @@ -167,7 +172,7 @@ public class AltosScanUI final AltosScanResult result = new AltosScanResult(record.callsign, record.serial, record.flight, - channel, + frequency, telemetry); Runnable r = new Runnable() { public void run() { @@ -190,26 +195,30 @@ public class AltosScanUI } void set_label() { - scanning_label.setText(String.format("Scanning: channel %d %s", - channel, - Altos.telemetry_name(telemetry))); + frequency_label.setText(String.format("Frequency: %s", frequencies[frequency_index].toString())); + telemetry_label.setText(String.format("Telemetry: %s", Altos.telemetry_name(telemetry))); } - void next() { + void set_telemetry() { + reader.set_telemetry(telemetry); + } + + void set_frequency() throws InterruptedException, TimeoutException { + reader.set_frequency(frequencies[frequency_index].frequency); + } + + void next() throws InterruptedException, TimeoutException { reader.serial.set_monitor(false); - try { - Thread.sleep(100); - } catch (InterruptedException ie){ - } - ++channel; - if (channel > 9) { - channel = 0; + Thread.sleep(100); + ++frequency_index; + if (frequency_index >= frequencies.length) { + frequency_index = 0; ++telemetry; if (telemetry > Altos.ao_telemetry_max) telemetry = Altos.ao_telemetry_min; - reader.serial.set_telemetry(telemetry); + set_telemetry(); } - reader.serial.set_channel(channel); + set_frequency(); set_label(); reader.serial.set_monitor(true); } @@ -229,31 +238,37 @@ public class AltosScanUI dispose(); } - void tick_timer() { + void tick_timer() throws InterruptedException, TimeoutException { next(); } public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); - if (cmd.equals("cancel")) - close(); - - if (cmd.equals("tick")) - tick_timer(); - - if (cmd.equals("monitor")) { - close(); - AltosScanResult r = (AltosScanResult) (list.getSelectedValue()); - if (r != null) { - if (device != null) { - if (reader != null) { - reader.set_telemetry(r.telemetry); - reader.set_channel(r.channel); - owner.telemetry_window(device); + try { + if (cmd.equals("cancel")) + close(); + + if (cmd.equals("tick")) + tick_timer(); + + if (cmd.equals("monitor")) { + close(); + AltosScanResult r = (AltosScanResult) (list.getSelectedValue()); + if (r != null) { + if (device != null) { + if (reader != null) { + reader.set_telemetry(r.telemetry); + reader.set_frequency(r.frequency); + owner.telemetry_window(device); + } } } } + } catch (TimeoutException te) { + close(); + } catch (InterruptedException ie) { + close(); } } @@ -278,8 +293,8 @@ public class AltosScanUI return false; try { reader = new AltosTelemetryReader(device); - reader.serial.set_channel(channel); - reader.serial.set_telemetry(telemetry); + set_frequency(); + set_telemetry(); try { Thread.sleep(100); } catch (InterruptedException ie) { @@ -306,6 +321,16 @@ public class AltosScanUI device.toShortString(), "Unkonwn I/O error", JOptionPane.ERROR_MESSAGE); + } catch (TimeoutException te) { + JOptionPane.showMessageDialog(owner, + device.toShortString(), + "Timeout error", + JOptionPane.ERROR_MESSAGE); + } catch (InterruptedException ie) { + JOptionPane.showMessageDialog(owner, + device.toShortString(), + "Interrupted exception", + JOptionPane.ERROR_MESSAGE); } if (reader != null) reader.close(false); @@ -316,7 +341,8 @@ public class AltosScanUI owner = in_owner; - channel = 0; + frequencies = AltosPreferences.common_frequencies(); + frequency_index = 0; telemetry = Altos.ao_telemetry_min; if (!open()) @@ -335,11 +361,13 @@ public class AltosScanUI pane.setLayout(new GridBagLayout()); scanning_label = new JLabel("Scanning:"); + frequency_label = new JLabel(""); + telemetry_label = new JLabel(""); set_label(); c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.CENTER; + c.anchor = GridBagConstraints.WEST; c.insets = i; c.weightx = 1; c.weighty = 1; @@ -347,9 +375,12 @@ public class AltosScanUI c.gridx = 0; c.gridy = 0; c.gridwidth = 2; - c.anchor = GridBagConstraints.CENTER; pane.add(scanning_label, c); + c.gridy = 1; + pane.add(frequency_label, c); + c.gridy = 2; + pane.add(telemetry_label, c); list = new JList(results) { //Subclass JList to workaround bug 4832765, which can cause the @@ -417,7 +448,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 0; - c.gridy = 1; + c.gridy = 3; c.gridwidth = 2; c.anchor = GridBagConstraints.CENTER; @@ -434,7 +465,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 0; - c.gridy = 2; + c.gridy = 4; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; @@ -451,7 +482,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 1; - c.gridy = 2; + c.gridy = 4; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index f45aa18b..6c687f5f 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -54,11 +54,12 @@ public class AltosSerial implements Runnable { int line_count; boolean monitor_mode; int telemetry; - int channel; + double frequency; static boolean debug; boolean remote; LinkedList pending_output = new LinkedList(); Frame frame; + AltosConfigData config_data; static void set_debug(boolean new_debug) { debug = new_debug; @@ -154,7 +155,7 @@ public class AltosSerial implements Runnable { Object[] options = { "Cancel" }; JOptionPane pane = new JOptionPane(); - pane.setMessage(String.format("Connecting to %s", device.getPath())); + pane.setMessage(String.format("Connecting to %s, %7.3f MHz", device.toShortString(), frequency)); pane.setOptions(options); pane.setInitialValue(null); @@ -208,20 +209,13 @@ public class AltosSerial implements Runnable { } while (got_some); } - public String get_reply() throws InterruptedException { - if (SwingUtilities.isEventDispatchThread()) - System.out.printf("Uh-oh, reading serial device from swing thread\n"); - flush_output(); - AltosLine line = reply_queue.take(); - return line.line; - } - int in_reply; public String get_reply(int timeout) throws InterruptedException { boolean can_cancel = true; ++in_reply; + System.out.printf("get_reply %d\n", timeout); if (SwingUtilities.isEventDispatchThread()) { can_cancel = false; System.out.printf("Uh-oh, reading serial device from swing thread\n"); @@ -239,7 +233,6 @@ public class AltosSerial implements Runnable { --in_reply; return line.line; } - System.out.printf("no line remote %b can_cancel %b\n", remote, can_cancel); if (!remote || !can_cancel || check_timeout()) { --in_reply; return null; @@ -247,8 +240,13 @@ public class AltosSerial implements Runnable { } } + public String get_reply() throws InterruptedException { + return get_reply(5000); + } + public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { flush_output(); + System.out.printf("get_reply_no_dialog\n"); AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); if (line != null) return line.line; @@ -267,6 +265,8 @@ public class AltosSerial implements Runnable { } public void close() { + if (remote) + stop_remote(); if (in_reply != 0) System.out.printf("Uh-oh. Closing active serial device\n"); @@ -328,19 +328,11 @@ public class AltosSerial implements Runnable { flush_output(); } - public void set_radio() { - telemetry = AltosPreferences.telemetry(device.getSerial()); - channel = AltosPreferences.channel(device.getSerial()); - set_channel(channel); - set_callsign(AltosPreferences.callsign()); - } - private int telemetry_len() { return Altos.telemetry_len(telemetry); } - public void set_channel(int in_channel) { - channel = in_channel; + private void set_channel(int channel) { if (altos != null) { if (monitor_mode) printf("m 0\nc r %d\nm %x\n", @@ -351,6 +343,33 @@ public class AltosSerial implements Runnable { } } + private void set_radio_setting(int setting) { + if (altos != null) { + if (monitor_mode) + printf("m 0\nc R %d\nc r 0\nm %x\n", + setting, telemetry_len()); + else + printf("c R %d\nc r 0\n", setting); + } + } + + public void set_radio_frequency(double frequency, + boolean has_setting, + int cal) { + if (has_setting) + set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); + else + set_channel(AltosConvert.radio_frequency_to_channel(frequency)); + } + + public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + config_data(); + set_radio_frequency(frequency, + config_data.radio_setting != 0, + config_data.radio_calibration); + } + public void set_telemetry(int in_telemetry) { telemetry = in_telemetry; if (altos != null) { @@ -378,10 +397,19 @@ public class AltosSerial implements Runnable { } } - public void start_remote() { + public AltosConfigData config_data() throws InterruptedException, TimeoutException { + if (config_data == null) + config_data = new AltosConfigData(this); + return config_data; + } + + public void start_remote() throws TimeoutException, InterruptedException { if (debug) System.out.printf("start remote\n"); - set_radio(); + if (frequency == 0.0) + frequency = AltosPreferences.frequency(device.getSerial()); + set_radio_frequency(frequency); + set_callsign(AltosPreferences.callsign()); printf("p\nE 0\n"); flush_input(); remote = true; diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 23524b2c..4512e761 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -27,6 +27,9 @@ class AltosTelemetryReader extends AltosFlightReader { AltosSerial serial; AltosLog log; AltosRecord previous; + AltosConfigData config_data; + double frequency; + int telemetry; LinkedBlockingQueue telem; @@ -49,18 +52,26 @@ class AltosTelemetryReader extends AltosFlightReader { serial.close(); } - void set_channel(int channel) { - serial.set_channel(channel); - AltosPreferences.set_channel(device.getSerial(), channel); + public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + serial.set_radio_frequency(frequency); } - void set_telemetry(int telemetry) { + void save_frequency() { + AltosPreferences.set_frequency(device.getSerial(), frequency); + } + + void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; serial.set_telemetry(telemetry); + } + + void save_telemetry() { AltosPreferences.set_telemetry(device.getSerial(), telemetry); } public AltosTelemetryReader (AltosDevice in_device) - throws FileNotFoundException, AltosSerialInUseException, IOException { + throws FileNotFoundException, AltosSerialInUseException, IOException, InterruptedException, TimeoutException { device = in_device; serial = new AltosSerial(device); log = new AltosLog(serial); @@ -68,7 +79,11 @@ class AltosTelemetryReader extends AltosFlightReader { previous = null; telem = new LinkedBlockingQueue(); - serial.set_radio(); + frequency = AltosPreferences.frequency(device.getSerial()); + set_frequency(frequency); + telemetry = AltosPreferences.telemetry(device.getSerial()); + set_telemetry(telemetry); + serial.set_callsign(AltosPreferences.callsign()); serial.add_monitor(telem); } } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 033f233c..885e60cd 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -26,7 +26,7 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.*; import libaltosJNI.*; @@ -67,6 +67,16 @@ public class AltosUI extends JFrame { device.toShortString(), "Unkonwn I/O error", JOptionPane.ERROR_MESSAGE); + } catch (TimeoutException te) { + JOptionPane.showMessageDialog(this, + device.toShortString(), + "Timeout error", + JOptionPane.ERROR_MESSAGE); + } catch (InterruptedException ie) { + JOptionPane.showMessageDialog(this, + device.toShortString(), + "Interrupted exception", + JOptionPane.ERROR_MESSAGE); } } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index d6fd0e6d..4bac6df1 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -52,6 +52,7 @@ altosui_JAVA = \ AltosFlightStatus.java \ AltosFlightUI.java \ AltosFrequency.java \ + AltosFreqList.java \ AltosGPS.java \ AltosGPSSat.java \ AltosGreatCircle.java \ -- cgit v1.2.3 From a65daf94e8fe3e22f770ef76d9104c3dd11d0330 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 12:25:30 -0700 Subject: altosui: altimeter is not spelled altimter Signed-off-by: Keith Packard --- altosui/AltosUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 885e60cd..fefe74e8 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -147,7 +147,7 @@ public class AltosUI extends JFrame { ExportData(); } }); - b = addButton(0, 1, "Configure Altimter"); + b = addButton(0, 1, "Configure Altimeter"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ConfigureTeleMetrum(); -- cgit v1.2.3 From a315b200cd0da1a964f5395cd59660be1b49672b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 12:31:48 -0700 Subject: altosui: Pull out BlueTooth support This leaves the code in place, but commented out so that it isn't used until we've got a bluetooth device ready for use. Signed-off-by: Keith Packard --- altosui/Altos.java | 2 +- altosui/AltosConfigureUI.java | 32 ++++++++++++++++++-------------- altosui/AltosDeviceDialog.java | 38 +++++++++++++++++++++++--------------- altosui/Makefile.am | 10 ++++++---- altosui/libaltos/cjnitest.c | 2 ++ altosui/libaltos/libaltos.c | 2 ++ altosui/libaltos/libaltos.h | 6 ++++++ 7 files changed, 58 insertions(+), 34 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 1acce949..b257ad7b 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -408,5 +408,5 @@ public class Altos { public final static String bt_product_telebt = bt_product_telebt(); - public static AltosBTKnown bt_known = new AltosBTKnown(); +// public static AltosBTKnown bt_known = new AltosBTKnown(); } diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index a8a70ffd..abb54c74 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -49,7 +49,8 @@ public class AltosConfigureUI JRadioButton serial_debug; - JButton manage_bluetooth; +// BLUETOOTH +// JButton manage_bluetooth; JButton manage_frequencies; /* DocumentListener interface methods */ @@ -202,18 +203,19 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.WEST; pane.add(serial_debug, c); - manage_bluetooth = new JButton("Manage Bluetooth"); - manage_bluetooth.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - AltosBTManage.show(owner, Altos.bt_known); - } - }); - c.gridx = 0; - c.gridy = 6; - c.gridwidth = 2; - c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.WEST; - pane.add(manage_bluetooth, c); +// BLUETOOTH +// manage_bluetooth = new JButton("Manage Bluetooth"); +// manage_bluetooth.addActionListener(new ActionListener() { +// public void actionPerformed(ActionEvent e) { +// AltosBTManage.show(owner, Altos.bt_known); +// } +// }); +// c.gridx = 0; +// c.gridy = 6; +// c.gridwidth = 2; +// c.fill = GridBagConstraints.NONE; +// c.anchor = GridBagConstraints.WEST; +// pane.add(manage_bluetooth, c); manage_frequencies = new JButton("Manage Frequencies"); manage_frequencies.addActionListener(new ActionListener() { @@ -221,7 +223,9 @@ public class AltosConfigureUI AltosConfigFreqUI.show(owner); } }); - c.gridx = 2; +// BLUETOOTH +// c.gridx = 2; + c.gridx = 1; c.gridy = 6; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index e17504e2..fa9587bc 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -30,7 +30,8 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { private JList list; private JButton cancel_button; private JButton select_button; - private JButton manage_bluetooth_button; +// BLUETOOTH +// private JButton manage_bluetooth_button; private Frame frame; private int product; @@ -40,14 +41,18 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { private AltosDevice[] devices() { java.util.List usb_devices = AltosUSBDevice.list(product); - java.util.List bt_devices = Altos.bt_known.list(product); - AltosDevice[] devices = new AltosDevice[usb_devices.size() + bt_devices.size()]; + int num_devices = usb_devices.size(); +// BLUETOOTH +// java.util.List bt_devices = Altos.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); +// BLUETOOTH +// int off = usb_devices.size(); +// for (int j = 0; j < bt_devices.size(); j++) +// devices[off + j] = bt_devices.get(j); return devices; } @@ -70,9 +75,10 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { cancel_button.setActionCommand("cancel"); cancel_button.addActionListener(this); - manage_bluetooth_button = new JButton("Manage Bluetooth"); - manage_bluetooth_button.setActionCommand("manage"); - manage_bluetooth_button.addActionListener(this); +// BLUETOOTH +// 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"); @@ -146,7 +152,8 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { buttonPane.add(Box.createHorizontalGlue()); buttonPane.add(cancel_button); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); - buttonPane.add(manage_bluetooth_button); +// BLUETOOTH +// buttonPane.add(manage_bluetooth_button); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); buttonPane.add(select_button); @@ -166,11 +173,12 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { public void actionPerformed(ActionEvent e) { if ("select".equals(e.getActionCommand())) value = (AltosDevice)(list.getSelectedValue()); - if ("manage".equals(e.getActionCommand())) { - AltosBTManage.show(frame, Altos.bt_known); - update_devices(); - return; - } +// BLUETOOTH +// if ("manage".equals(e.getActionCommand())) { +// AltosBTManage.show(frame, Altos.bt_known); +// update_devices(); +// return; +// } setVisible(false); } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 4bac6df1..713a02f4 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -10,6 +10,12 @@ CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:libaltos:$(FREETTS)/*:/ bin_SCRIPTS=altosui +altosui_BT = \ + AltosBTDevice.java \ + AltosBTDeviceIterator.java \ + AltosBTManage.java \ + AltosBTKnown.java + altosui_JAVA = \ GrabNDrag.java \ AltosAscent.java \ @@ -28,10 +34,6 @@ altosui_JAVA = \ AltosDeviceDialog.java \ AltosDevice.java \ AltosUSBDevice.java \ - AltosBTDevice.java \ - AltosBTDeviceIterator.java \ - AltosBTManage.java \ - AltosBTKnown.java \ AltosDisplayThread.java \ AltosEepromChunk.java \ AltosEepromDelete.java \ diff --git a/altosui/libaltos/cjnitest.c b/altosui/libaltos/cjnitest.c index 88e40d73..f0fe78f7 100644 --- a/altosui/libaltos/cjnitest.c +++ b/altosui/libaltos/cjnitest.c @@ -41,6 +41,7 @@ main () 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); @@ -64,6 +65,7 @@ main () } } altos_bt_list_finish(bt_list); +#endif altos_fini(); return 0; } diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 5e507cdf..b00a7704 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -582,6 +582,7 @@ altos_list_finish(struct altos_list *usbdevs) free(usbdevs); } +#if HAS_BLUETOOTH struct altos_bt_list { inquiry_info *ii; int sock; @@ -713,6 +714,7 @@ no_sock: no_file: return NULL; } +#endif /* HAS_BLUETOOTH */ #endif diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h index f710919c..dd091e51 100644 --- a/altosui/libaltos/libaltos.h +++ b/altosui/libaltos/libaltos.h @@ -34,6 +34,8 @@ # define PUBLIC #endif +#define HAS_BLUETOOTH 0 + #define USB_VENDOR_FSF 0xfffe #define USB_VENDOR_ALTUSMETRUM USB_VENDOR_FSF #define USB_PRODUCT_ALTUSMETRUM 0x000a @@ -109,6 +111,8 @@ altos_flush(struct altos_file *file); PUBLIC int altos_getchar(struct altos_file *file, int timeout); +#if HAS_BLUETOOTH + PUBLIC struct altos_bt_list * altos_bt_list_start(int inquiry_time); @@ -124,4 +128,6 @@ 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 + #endif /* _LIBALTOS_H_ */ -- cgit v1.2.3 From dd383b86b9a13d7af2d6b07f4fb85ccc666ed898 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 18:45:36 -0700 Subject: altosui: Must set radio calibration before radio setting Setting the radio calibration erases any previous radio setting as the radio calibration change invalidates any previously computed radio setting for a specific frequency. Hence, the radio setting must be configured *after* the radio calibration value lest it be ignored. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 694ef4db..d5d7d56a 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -132,13 +132,12 @@ public class AltosConfig implements ActionListener { config_ui.set_version(version.get()); config_ui.set_main_deploy(main_deploy.get()); config_ui.set_apogee_delay(apogee_delay.get()); - config_ui.set_radio_frequency(frequency()); config_ui.set_radio_calibration(radio_calibration.get()); + config_ui.set_radio_frequency(frequency()); config_ui.set_flight_log_max(flight_log_max.get()); config_ui.set_ignite_mode(ignite_mode.get()); config_ui.set_pad_orientation(pad_orientation.get()); config_ui.set_callsign(callsign.get()); - config_ui.set_radio_setting(radio_setting.get()); config_ui.set_clean(); config_ui.make_visible(); } @@ -218,10 +217,12 @@ public class AltosConfig implements ActionListener { void save_data() { try { double frequency = frequency(); - boolean has_setting = radio_setting.get() != 0; + boolean has_setting = radio_setting.get() > 0; start_serial(); serial_line.printf("c m %d\n", main_deploy.get()); serial_line.printf("c d %d\n", apogee_delay.get()); + if (!remote) + serial_line.printf("c f %d\n", radio_calibration.get()); serial_line.set_radio_frequency(frequency, has_setting, radio_calibration.get()); @@ -233,8 +234,6 @@ public class AltosConfig implements ActionListener { AltosPreferences.set_frequency(device.getSerial(), frequency); serial_line.start_remote(); } - if (!remote) - serial_line.printf("c f %d\n", radio_calibration.get()); serial_line.printf("c c %s\n", callsign.get()); if (flight_log_max.get() != 0) serial_line.printf("c l %d\n", flight_log_max.get()); @@ -321,18 +320,17 @@ public class AltosConfig implements ActionListener { } double frequency() { - int setting = radio_setting.get(); - - if (setting != 0) - return AltosConvert.radio_setting_to_frequency(setting, radio_calibration.get()); - else - return AltosConvert.radio_channel_to_frequency(radio_channel.get()); + System.out.printf("setting %d channel %d calibration %d\n", + radio_setting.get(), radio_channel.get(), radio_calibration.get()); + return AltosConvert.radio_to_frequency(radio_setting.get(), + radio_calibration.get(), + radio_channel.get()); } void set_frequency(double freq) { int setting = radio_setting.get(); - if (setting != 0) { + if (setting > 0) { radio_setting.set(AltosConvert.radio_frequency_to_setting(freq, radio_calibration.get())); radio_channel.set(0); -- cgit v1.2.3 From c8c01684fa011acf3bbe5c3ebbc84aa8e8457a5e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 18:47:36 -0700 Subject: altosui: A few misc cleanups. Initialize radio_setting as it won't be set for older devices ever. Remove unused set_radio_frequency function from AltosConfigUI. Signed-off-by: Keith Packard --- altosui/AltosConfigData.java | 1 + altosui/AltosConfigUI.java | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index aa7a90de..016033a3 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -85,6 +85,7 @@ public class AltosConfigData implements Iterable { public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { serial_line.printf("c s\nv\n"); lines = new LinkedList(); + radio_setting = 0; for (;;) { String line = serial_line.get_reply(); if (line == null) diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index c109924e..71664c91 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -563,9 +563,6 @@ public class AltosConfigUI callsign_value.setText(new_callsign); } - public void set_radio_setting(int new_radio_setting) { - } - public String callsign() { return callsign_value.getText(); } -- cgit v1.2.3 From 81bb6f42d8b859195ea5a35806c42d98ba82e8e1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 18:49:45 -0700 Subject: altosui: Have single radio_to_frequency function This takes all three radio params (setting, cal, channel) and computes the current frequency. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 2 -- altosui/AltosConvert.java | 22 ++++++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index d5d7d56a..7312ea6c 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -320,8 +320,6 @@ public class AltosConfig implements ActionListener { } double frequency() { - System.out.printf("setting %d channel %d calibration %d\n", - radio_setting.get(), radio_channel.get(), radio_calibration.get()); return AltosConvert.radio_to_frequency(radio_setting.get(), radio_calibration.get(), radio_channel.get()); diff --git a/altosui/AltosConvert.java b/altosui/AltosConvert.java index 6a9b699c..c2ae9a50 100644 --- a/altosui/AltosConvert.java +++ b/altosui/AltosConvert.java @@ -190,30 +190,24 @@ public class AltosConvert { return ignite / 32767 * 15.0; } - static double - radio_setting_to_frequency(int setting, int cal) { + static double radio_to_frequency(int setting, int cal, int channel) { double f; + if (setting <= 0) + setting = cal; f = 434.550 * setting / cal; /* Round to nearest 50KHz */ f = Math.floor (20.0 * f + 0.5) / 20.0; - return f; + return f + channel * 0.100; } - static int - radio_frequency_to_setting(double frequency, int cal) { + static int radio_frequency_to_setting(double frequency, int cal) { double set = frequency / 434.550 * cal; return (int) Math.floor (set + 0.5); } - static double - radio_channel_to_frequency(int channel) { - return 434.550 + channel * 0.100; - } - - static int - radio_frequency_to_channel(double frequency) { + static int radio_frequency_to_channel(double frequency) { int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); if (channel < 0) @@ -222,4 +216,8 @@ public class AltosConvert { channel = 9; return channel; } + + static double radio_channel_to_frequency(int channel) { + return 434.550 + channel * 0.100; + } } -- cgit v1.2.3 From d4cc16e111229b02d1081e2693ace0b33f662498 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 18:51:16 -0700 Subject: altosui: Save frequency after setting it in AltosFlightUI Otherwise we'll just save the old frequency. Signed-off-by: Keith Packard --- altosui/AltosFlightUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 8c3f821e..c31e02bf 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -147,12 +147,12 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { frequencies.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { double frequency = frequencies.frequency(); - reader.save_frequency(); try { reader.set_frequency(frequency); } catch (TimeoutException te) { } catch (InterruptedException ie) { } + reader.save_frequency(); } }); c.gridx = 0; -- cgit v1.2.3 From 364102d29ff4de0c252774f26417587fa88b7467 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 18:52:11 -0700 Subject: altosui: Show AltosFrequency in scan results Include frequency and description instead of just frequency. Signed-off-by: Keith Packard --- altosui/AltosScanUI.java | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 9a483138..b47405c8 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -30,17 +30,17 @@ import java.util.prefs.*; import java.util.concurrent.*; class AltosScanResult { - String callsign; - int serial; - int flight; - double frequency; - int telemetry; + String callsign; + int serial; + int flight; + AltosFrequency frequency; + int telemetry; boolean interrupted = false; public String toString() { - return String.format("%-9.9s serial %-4d flight %-4d (frequency %7.3f %s)", - callsign, serial, flight, frequency, Altos.telemetry_name(telemetry)); + return String.format("%-9.9s serial %-4d flight %-4d (%s %s)", + callsign, serial, flight, frequency.toShortString(), Altos.telemetry_name(telemetry)); } public String toShortString() { @@ -49,7 +49,7 @@ class AltosScanResult { } public AltosScanResult(String in_callsign, int in_serial, - int in_flight, double in_frequency, int in_telemetry) { + int in_flight, AltosFrequency in_frequency, int in_telemetry) { callsign = in_callsign; serial = in_serial; flight = in_flight; @@ -61,7 +61,7 @@ class AltosScanResult { return (callsign.equals(other.callsign) && serial == other.serial && flight == other.flight && - frequency == other.frequency && + frequency.frequency == other.frequency.frequency && telemetry == other.telemetry); } } @@ -119,7 +119,6 @@ public class AltosScanUI AltosScanResults results = new AltosScanResults(); int telemetry; - double frequency; final static int timeout = 1200; TelemetryHandler handler; @@ -172,7 +171,7 @@ public class AltosScanUI final AltosScanResult result = new AltosScanResult(record.callsign, record.serial, record.flight, - frequency, + frequencies[frequency_index], telemetry); Runnable r = new Runnable() { public void run() { @@ -259,7 +258,8 @@ public class AltosScanUI if (device != null) { if (reader != null) { reader.set_telemetry(r.telemetry); - reader.set_frequency(r.frequency); + reader.set_frequency(r.frequency.frequency); + reader.save_frequency(); owner.telemetry_window(device); } } -- cgit v1.2.3 From 97cf285d041062ae473c2823438b81c8fffe7f67 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 18:53:03 -0700 Subject: altosui: Remove debugging printfs from AltosSerial Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 6c687f5f..c0eeb920 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -215,7 +215,6 @@ public class AltosSerial implements Runnable { boolean can_cancel = true; ++in_reply; - System.out.printf("get_reply %d\n", timeout); if (SwingUtilities.isEventDispatchThread()) { can_cancel = false; System.out.printf("Uh-oh, reading serial device from swing thread\n"); @@ -246,7 +245,6 @@ public class AltosSerial implements Runnable { public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { flush_output(); - System.out.printf("get_reply_no_dialog\n"); AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); if (line != null) return line.line; -- cgit v1.2.3 From 13eacb49de4312509c3a729a31dcda4d601f8a8b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 18:53:27 -0700 Subject: altosui: Flush radio setting to serial device When changing frequencies, make sure the device hears about it. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index c0eeb920..5d4510b4 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -348,6 +348,7 @@ public class AltosSerial implements Runnable { setting, telemetry_len()); else printf("c R %d\nc r 0\n", setting); + flush_output(); } } -- cgit v1.2.3 From 2662c577a895c96fce7b2bf815b9e752d2dfbde6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 18:53:59 -0700 Subject: altosui: Remove unused AltosConfigData from AltosTelemetryReader Now that AltosSerial manages this data, it's not needed here. Signed-off-by: Keith Packard --- altosui/AltosTelemetryReader.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 4512e761..6abe95d8 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -27,7 +27,6 @@ class AltosTelemetryReader extends AltosFlightReader { AltosSerial serial; AltosLog log; AltosRecord previous; - AltosConfigData config_data; double frequency; int telemetry; -- cgit v1.2.3 From 7146311d9df541e075b4450cf9656a9aa7ffdd93 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 20:38:14 -0700 Subject: altosui: Reading serial from swing thread only bad if remote Make the warning on this condition based on whether the link is remote. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 5d4510b4..5e496d7f 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -217,7 +217,8 @@ public class AltosSerial implements Runnable { if (SwingUtilities.isEventDispatchThread()) { can_cancel = false; - System.out.printf("Uh-oh, reading serial device from swing thread\n"); + if (remote) + System.out.printf("Uh-oh, reading remote serial device from swing thread\n"); } flush_output(); if (remote && can_cancel) { -- cgit v1.2.3 From cbf54a826d12c49b1b1996be247869d5ff4e2236 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 20:38:44 -0700 Subject: altosui: Make set of telemetries to use while scanning configurable with a preference to remember across application runs. Signed-off-by: Keith Packard --- altosui/AltosPreferences.java | 20 ++++++++++++++++++ altosui/AltosScanUI.java | 48 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 7 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index 8609f94e..de926b38 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -52,6 +52,9 @@ class AltosPreferences { /* serial debug preference name */ final static String serialDebugPreference = "SERIAL-DEBUG"; + /* scanning telemetry preferences name */ + final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; + /* Default logdir is ~/TeleMetrum */ final static String logdirName = "TeleMetrum"; @@ -82,6 +85,9 @@ class AltosPreferences { /* Serial debug */ static boolean serial_debug; + /* Scanning telemetry */ + static int scanning_telemetry; + /* List of frequencies */ final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; static AltosFrequency[] common_frequencies; @@ -156,6 +162,8 @@ class AltosPreferences { callsign = preferences.get(callsignPreference,"N0CALL"); + scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << Altos.ao_telemetry_standard)); + String firmwaredir_string = preferences.get(firmwaredirPreference, null); if (firmwaredir_string != null) firmwaredir = new File(firmwaredir_string); @@ -279,6 +287,18 @@ class AltosPreferences { return telemetry; } + public static void set_scanning_telemetry(int new_scanning_telemetry) { + scanning_telemetry = new_scanning_telemetry; + synchronized (preferences) { + preferences.putInt(scanningTelemetryPreference, scanning_telemetry); + flush_preferences(); + } + } + + public static int scanning_telemetry() { + return scanning_telemetry; + } + public static void set_voice(boolean new_voice) { voice = new_voice; synchronized (preferences) { diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index b47405c8..dd6672aa 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -115,6 +115,7 @@ public class AltosScanUI private JLabel telemetry_label; private JButton cancel_button; private JButton monitor_button; + private JCheckBox[] telemetry_boxes; javax.swing.Timer timer; AltosScanResults results = new AltosScanResults(); @@ -210,11 +211,15 @@ public class AltosScanUI reader.serial.set_monitor(false); Thread.sleep(100); ++frequency_index; - if (frequency_index >= frequencies.length) { + if (frequency_index >= frequencies.length || + !telemetry_boxes[telemetry - Altos.ao_telemetry_min].isSelected()) + { frequency_index = 0; - ++telemetry; - if (telemetry > Altos.ao_telemetry_max) - telemetry = Altos.ao_telemetry_min; + do { + ++telemetry; + if (telemetry > Altos.ao_telemetry_max) + telemetry = Altos.ao_telemetry_min; + } while (!telemetry_boxes[telemetry - Altos.ao_telemetry_min].isSelected()); set_telemetry(); } set_frequency(); @@ -251,6 +256,21 @@ public class AltosScanUI if (cmd.equals("tick")) tick_timer(); + if (cmd.equals("telemetry")) { + int k; + int scanning_telemetry = 0; + for (k = Altos.ao_telemetry_min; k <= Altos.ao_telemetry_max; k++) { + int j = k - Altos.ao_telemetry_min; + if (telemetry_boxes[j].isSelected()) + scanning_telemetry |= (1 << k); + } + if (scanning_telemetry == 0) { + scanning_telemetry |= (1 << Altos.ao_telemetry_standard); + telemetry_boxes[Altos.ao_telemetry_standard - Altos.ao_telemetry_min].setSelected(true); + } + AltosPreferences.set_scanning_telemetry(scanning_telemetry); + } + if (cmd.equals("monitor")) { close(); AltosScanResult r = (AltosScanResult) (list.getSelectedValue()); @@ -382,6 +402,20 @@ public class AltosScanUI c.gridy = 2; pane.add(telemetry_label, c); + int scanning_telemetry = AltosPreferences.scanning_telemetry(); + telemetry_boxes = new JCheckBox[Altos.ao_telemetry_max - Altos.ao_telemetry_min + 1]; + for (int k = Altos.ao_telemetry_min; k <= Altos.ao_telemetry_max; k++) { + int j = k - Altos.ao_telemetry_min; + telemetry_boxes[j] = new JCheckBox(Altos.ao_telemetry_name[k]); + c.gridy = 3 + j; + pane.add(telemetry_boxes[j], c); + telemetry_boxes[j].setActionCommand("telemetry"); + telemetry_boxes[j].addActionListener(this); + telemetry_boxes[j].setSelected((scanning_telemetry & (1 << k)) != 0); + } + + int y_offset = 3 + (Altos.ao_telemetry_max - Altos.ao_telemetry_min + 1); + list = new JList(results) { //Subclass JList to workaround bug 4832765, which can cause the //scroll pane to not let the user easily scroll up to the beginning @@ -448,7 +482,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 0; - c.gridy = 3; + c.gridy = y_offset; c.gridwidth = 2; c.anchor = GridBagConstraints.CENTER; @@ -465,7 +499,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 0; - c.gridy = 4; + c.gridy = y_offset + 1; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; @@ -482,7 +516,7 @@ public class AltosScanUI c.weighty = 1; c.gridx = 1; - c.gridy = 4; + c.gridy = y_offset + 1; c.gridwidth = 1; c.anchor = GridBagConstraints.CENTER; -- cgit v1.2.3 From f3985ef8bc69bcec13ce155567a8ed7c5c6051cb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Aug 2011 20:41:34 -0700 Subject: altosui: Add close button to 'fire' dialog Easier to hit than the tiny close box in the frame. Signed-off-by: Keith Packard --- altosui/AltosIgniteUI.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 42120b92..806b87b9 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -43,6 +43,7 @@ public class AltosIgniteUI JToggleButton arm; JButton fire; javax.swing.Timer timer; + JButton close; int apogee_status; int main_status; @@ -402,6 +403,16 @@ public class AltosIgniteUI fire.addActionListener(this); fire.setActionCommand("fire"); + c.gridx = 0; + c.gridy = 4; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + close = new JButton ("Close"); + pane.add(close, c); + close.addActionListener(this); + close.setActionCommand("close"); + + pack(); setLocationRelativeTo(owner); -- cgit v1.2.3 From 12bfa6cc42e3689f09abae2bd2584cbacf2aa2e0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 9 Aug 2011 18:26:07 -0700 Subject: altosui: Don't export product defs from libaltos As we add new products, that would change the ABI generated for java, invaliding old library versions sitting around for windows and mac. Signed-off-by: Keith Packard --- altosui/libaltos/libaltos.c | 16 ++++++++++++++++ altosui/libaltos/libaltos.h | 19 +------------------ 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'altosui') diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index b00a7704..00a75de9 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -20,6 +20,22 @@ #include #include +#define USB_VENDOR_FSF 0xfffe +#define USB_VENDOR_ALTUSMETRUM USB_VENDOR_FSF +#define USB_PRODUCT_ALTUSMETRUM 0x000a +#define USB_PRODUCT_TELEMETRUM 0x000b +#define USB_PRODUCT_TELEDONGLE 0x000c +#define USB_PRODUCT_TELETERRA 0x000d +#define USB_PRODUCT_TELEBT 0x000e +#define USB_PRODUCT_ALTUSMETRUM_MIN 0x000a +#define USB_PRODUCT_ALTUSMETRUM_MAX 0x0013 + +#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 diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h index dd091e51..363a84fd 100644 --- a/altosui/libaltos/libaltos.h +++ b/altosui/libaltos/libaltos.h @@ -34,22 +34,6 @@ # define PUBLIC #endif -#define HAS_BLUETOOTH 0 - -#define USB_VENDOR_FSF 0xfffe -#define USB_VENDOR_ALTUSMETRUM USB_VENDOR_FSF -#define USB_PRODUCT_ALTUSMETRUM 0x000a -#define USB_PRODUCT_TELEMETRUM 0x000b -#define USB_PRODUCT_TELEDONGLE 0x000c -#define USB_PRODUCT_TELETERRA 0x000d -#define USB_PRODUCT_TELEBT 0x000e -#define USB_PRODUCT_ALTUSMETRUM_MIN 0x000a -#define USB_PRODUCT_ALTUSMETRUM_MAX 0x0013 - -#define USB_IS_ALTUSMETRUM(v,p) ((v) == USB_VENDOR_ALTUSMETRUM && \ - (USB_PRODUCT_ALTUSMETRUM_MIN <= (p) && \ - (p) <= USB_PRODUCT_ALTUSMETRUM_MAX)) - struct altos_device { //%immutable; int vendor; @@ -60,8 +44,6 @@ struct altos_device { //%mutable; }; -#define BLUETOOTH_PRODUCT_TELEBT "TeleBT" - struct altos_bt_device { //%immutable; char name[256]; @@ -111,6 +93,7 @@ altos_flush(struct altos_file *file); PUBLIC int altos_getchar(struct altos_file *file, int timeout); +// #define HAS_BLUETOOTH 1 #if HAS_BLUETOOTH PUBLIC struct altos_bt_list * -- cgit v1.2.3 From a680ce61bdcffeacb7f0e4dcef71a03cb7cfe07d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 9 Aug 2011 18:27:19 -0700 Subject: altosui: Ensure serial code tracks reply nesting correctly Trap any exceptional return conditions from 'get_reply' to make sure in_reply gets decremented. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 49 +++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 5e496d7f..b089c9c4 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -213,31 +213,38 @@ public class AltosSerial implements Runnable { public String get_reply(int timeout) throws InterruptedException { boolean can_cancel = true; - ++in_reply; + String reply = null; - if (SwingUtilities.isEventDispatchThread()) { - can_cancel = false; - if (remote) - System.out.printf("Uh-oh, reading remote serial device from swing thread\n"); - } - flush_output(); - if (remote && can_cancel) { - timeout = 500; - } - abort = false; - timeout_started = false; - for (;;) { - AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); - if (line != null) { - stop_timeout_dialog(); - --in_reply; - return line.line; + try { + ++in_reply; + + if (SwingUtilities.isEventDispatchThread()) { + can_cancel = false; + if (remote) + System.out.printf("Uh-oh, reading remote serial device from swing thread\n"); } - if (!remote || !can_cancel || check_timeout()) { - --in_reply; - return null; + flush_output(); + if (remote && can_cancel) { + timeout = 500; } + abort = false; + timeout_started = false; + for (;;) { + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) { + stop_timeout_dialog(); + reply = line.line; + break; + } + if (!remote || !can_cancel || check_timeout()) { + reply = null; + break; + } + } + } finally { + --in_reply; } + return reply; } public String get_reply() throws InterruptedException { -- cgit v1.2.3 From 94d9a2c36fabdf24d6a0b985851e95e4eb181fd9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 9 Aug 2011 18:28:19 -0700 Subject: altosui: Ship TeleMini v1.0 firmware with fat blobs Signed-off-by: Keith Packard --- altosui/Makefile.am | 5 ++++- altosui/altos-windows.nsi | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 713a02f4..a11e2c7f 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -160,7 +160,10 @@ FIRMWARE_TM_1_0=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx FIRMWARE_TM_1_1=$(top_srcdir)/src/telemetrum-v1.1-$(VERSION).ihx FIRMWARE_TM=$(FIRMWARE_TM_1_0) $(FIRMWARE_TM_1_1) -FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TD) +FIRMWARE_TELEMINI_1_0=$(top_srcdir)/src/telemini-v1.0-$(VERSION).ihx +FIRMWARE_TELEMINI=$(FIRMWARE_TELEMINI_1_0) + +FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf ALTOS_DOC=$(top_srcdir)/doc/altos.pdf diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index a1238095..d92d1eb3 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -81,6 +81,7 @@ Section "TeleMetrum and TeleDongle Firmware" File "../src/telemetrum-v1.0/telemetrum-v1.0-${VERSION}.ihx" File "../src/telemetrum-v1.1/telemetrum-v1.1-${VERSION}.ihx" + File "../src/telemini-v1.0/telemini-v1.0-${VERSION}.ihx" File "../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx" SectionEnd -- cgit v1.2.3 From 6ac604d11de44cd824f09e4b467264a2b74be7bd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 10 Aug 2011 13:35:26 -0700 Subject: Altosui: Add flight statistics tab to graph window Provide basic flight stats alongside the flight graph. Signed-off-by: Keith Packard --- altosui/Altos.java | 13 +++++ altosui/AltosFlightStats.java | 95 +++++++++++++++++++++++++++++++++ altosui/AltosFlightStatsTable.java | 104 +++++++++++++++++++++++++++++++++++++ altosui/AltosGraph.java | 1 + altosui/AltosGraphTime.java | 1 - altosui/AltosGraphUI.java | 36 ++++++++----- altosui/AltosState.java | 3 ++ altosui/Makefile.am | 2 + 8 files changed, 242 insertions(+), 13 deletions(-) create mode 100644 altosui/AltosFlightStats.java create mode 100644 altosui/AltosFlightStatsTable.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index b257ad7b..d90c4183 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -142,6 +142,19 @@ public class Altos { "invalid", }; + static String[] state_to_string_capital = { + "Startup", + "Idle", + "Pad", + "Boost", + "Fast", + "Coast", + "Drogue", + "Main", + "Landed", + "Invalid", + }; + static public int state(String state) { if (!map_initialized) initialize_map(); diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java new file mode 100644 index 00000000..e38142f0 --- /dev/null +++ b/altosui/AltosFlightStats.java @@ -0,0 +1,95 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosFlightStats { + double max_height; + double max_speed; + double max_acceleration; + double[] state_speed = new double[Altos.ao_flight_invalid + 1]; + double[] state_baro_speed = new double[Altos.ao_flight_invalid + 1]; + double[] state_accel = new double[Altos.ao_flight_invalid + 1]; + int[] state_count = new int[Altos.ao_flight_invalid + 1]; + double[] state_start = new double[Altos.ao_flight_invalid + 1]; + double[] state_end = new double[Altos.ao_flight_invalid + 1]; + + public AltosFlightStats(AltosFlightReader reader) throws InterruptedException, IOException { + AltosState state = null; + AltosState new_state = null; + double boost_time = -1; + double start_time; + + for (;;) { + try { + AltosRecord record = reader.read(); + if (record == null) + break; + new_state = new AltosState(record, state); + if (state == null) { + start_time = new_state.time; + } + state = new_state; + if (0 <= state.state && state.state < Altos.ao_flight_invalid) { + if (boost_time == -1 && state.state >= Altos.ao_flight_boost) + boost_time = state.time; + state_accel[state.state] += state.acceleration; + state_speed[state.state] += state.speed; + state_baro_speed[state.state] += state.baro_speed; + state_count[state.state]++; + if (state_start[state.state] == 0.0) + state_start[state.state] = state.time; + if (state_end[state.state] < state.time) + state_end[state.state] = state.time; + max_height = state.max_height; + max_speed = state.max_speed; + max_acceleration = state.max_acceleration; + } + } catch (ParseException pp) { + System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); + } catch (AltosCRCException ce) { + + } + } + for (int s = Altos.ao_flight_startup; s <= Altos.ao_flight_landed; s++) { + if (state_count[s] > 0) { + state_speed[s] /= state_count[s]; + state_baro_speed[s] /= state_count[s]; + state_accel[s] /= state_count[s]; + } + } + } + + public AltosFlightStats(AltosRecordIterable iterable, String filename) throws InterruptedException, IOException { + this(new AltosReplayReader(iterable.iterator(), filename)); + } + + public AltosFlightStats(AltosRecordIterable iterable) throws InterruptedException, IOException { + this(iterable, ""); + } +} diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java new file mode 100644 index 00000000..8676d306 --- /dev/null +++ b/altosui/AltosFlightStatsTable.java @@ -0,0 +1,104 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosFlightStatsTable extends JComponent { + GridBagLayout layout; + + class FlightStat { + JLabel label; + JTextField value; + + public FlightStat(GridBagLayout layout, int y, String label_text, String ... values) { + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad); + c.weighty = 1; + + label = new JLabel(label_text); + label.setFont(Altos.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); + + for (int j = 0; j < values.length; j++) { + value = new JTextField(values[j]); + value.setFont(Altos.value_font); + value.setHorizontalAlignment(SwingConstants.RIGHT); + c.gridx = j+1; c.gridy = y; + c.anchor = GridBagConstraints.EAST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + layout.setConstraints(value, c); + add(value); + } + } + + } + + public AltosFlightStatsTable(AltosFlightStats stats) { + layout = new GridBagLayout(); + + setLayout(layout); + int y = 0; + new FlightStat(layout, y++, "Maximum height", + String.format("%5.0f m", stats.max_height), + String.format("%5.0f ft", stats.max_height * 100 / 2.54 / 12)); + new FlightStat(layout, y++, "Maximum speed", + String.format("%5.0f m/s", stats.max_speed), + String.format("%5.0f ft/s", stats.max_speed * 100 / 2.54 / 12), + String.format("Mach %5.3f", stats.max_speed / 343.0)); + new FlightStat(layout, y++, "Maximum acceleration", + String.format("%5.0f m/s²", stats.max_acceleration), + String.format("%5.0f ft/s²", stats.max_acceleration * 100 / 2.54 /12), + String.format("%5.2f G", stats.max_acceleration / 9.80665)); + new FlightStat(layout, y++, "Average boost acceleration", + String.format("%5.0f m/s²", stats.state_accel[Altos.ao_flight_boost]), + String.format("%5.0f ft/s²", stats.state_accel[Altos.ao_flight_boost] * 100 / 2.54 /12), + String.format("%5.2f G", stats.state_accel[Altos.ao_flight_boost] / 9.80665)); + new FlightStat(layout, y++, "Drogue descent rate", + String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_drogue]), + String.format("%5.0f ft/s", stats.state_baro_speed[Altos.ao_flight_drogue] * 100 / 2.54 / 12)); + new FlightStat(layout, y++, "Main descent rate", + String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_main]), + String.format("%5.0f ft/s", stats.state_baro_speed[Altos.ao_flight_main] * 100 / 2.54 / 12)); + for (int s = Altos.ao_flight_boost; s <= Altos.ao_flight_main; s++) { + new FlightStat(layout, y++, String.format("%s time", Altos.state_to_string_capital[s]), + String.format("%6.2f s", stats.state_end[s] - stats.state_start[s])); + } + new FlightStat(layout, y++, "Flight Time", + String.format("%6.2f s", stats.state_end[Altos.ao_flight_main] - + stats.state_start[Altos.ao_flight_boost])); + + } + +} \ No newline at end of file diff --git a/altosui/AltosGraph.java b/altosui/AltosGraph.java index 58c27979..fbcefd61 100644 --- a/altosui/AltosGraph.java +++ b/altosui/AltosGraph.java @@ -13,6 +13,7 @@ abstract class AltosGraph { public String filename; public abstract void addData(AltosDataPoint d); public abstract JFreeChart createChart(); + public String title; public void toPNG() throws java.io.IOException { toPNG(300, 500); } public void toPNG(int width, int height) throws java.io.IOException diff --git a/altosui/AltosGraphTime.java b/altosui/AltosGraphTime.java index a5451280..ada6ef13 100644 --- a/altosui/AltosGraphTime.java +++ b/altosui/AltosGraphTime.java @@ -132,7 +132,6 @@ class AltosGraphTime extends AltosGraph { private Integer serial = null; private Integer flight = null; - private String title; private ArrayList elements; private HashMap axes; private HashMap datasets; diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index a27aa37f..16b0fd48 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -7,8 +7,11 @@ package altosui; import java.io.*; import java.util.ArrayList; -import javax.swing.JFrame; -import java.awt.Color; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartUtilities; @@ -19,6 +22,8 @@ import org.jfree.ui.RefineryUtilities; public class AltosGraphUI extends JFrame { + JTabbedPane pane; + static final private Color red = new Color(194,31,31); static final private Color green = new Color(31,194,31); static final private Color blue = new Color(31,31,194); @@ -173,7 +178,7 @@ public class AltosGraphUI extends JFrame } } - public AltosGraphUI(AltosRecordIterable records) { + public AltosGraphUI(AltosRecordIterable records) throws InterruptedException, IOException { super("Altos Graph"); AltosDataPointReader reader = new AltosDataPointReader (records); @@ -181,25 +186,32 @@ public class AltosGraphUI extends JFrame return; if (reader.has_accel) - init(reader, 0); + init(reader, records, 0); else - init(reader, 1); + init(reader, records, 1); } - public AltosGraphUI(AltosDataPointReader data, int which) - { - super("Altos Graph"); - init(data, which); - } +// public AltosGraphUI(AltosDataPointReader data, int which) + // { +// super("Altos Graph"); +// init(data, which); +// } + + private void init(AltosDataPointReader data, AltosRecordIterable records, int which) throws InterruptedException, IOException { + pane = new JTabbedPane(); - private void init(AltosDataPointReader data, int which) { AltosGraph graph = createGraph(data, which); JFreeChart chart = graph.createChart(); ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setMouseWheelEnabled(true); chartPanel.setPreferredSize(new java.awt.Dimension(800, 500)); - setContentPane(chartPanel); + pane.add(graph.title, chartPanel); + + AltosFlightStatsTable stats = new AltosFlightStatsTable(new AltosFlightStats(records)); + pane.add("Flight Statistics", stats); + + setContentPane (pane); pack(); diff --git a/altosui/AltosState.java b/altosui/AltosState.java index d374aed8..1ac816d5 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -28,6 +28,7 @@ public class AltosState { long report_time; + double time; double time_change; int tick; @@ -130,6 +131,8 @@ public class AltosState { time_change = 0; } + time = tick / 100.0; + if (state == Altos.ao_flight_pad || state == Altos.ao_flight_idle) { /* Track consecutive 'good' gps reports, waiting for 10 of them */ diff --git a/altosui/Makefile.am b/altosui/Makefile.am index a11e2c7f..3bc68cdb 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -51,6 +51,8 @@ altosui_JAVA = \ AltosFlightDisplay.java \ AltosFlightInfoTableModel.java \ AltosFlightReader.java \ + AltosFlightStats.java \ + AltosFlightStatsTable.java \ AltosFlightStatus.java \ AltosFlightUI.java \ AltosFrequency.java \ -- cgit v1.2.3 From 9e1487b1a5db0afd1d23c86d82c60b1c1a62aab0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 10 Aug 2011 14:08:21 -0700 Subject: altosui: Add a 'Graph Flight' button to the 'landed' tab This lets you see the results of a flight as soon as the rocket lands using the telemetry data. Signed-off-by: Keith Packard --- altosui/AltosFlightReader.java | 2 ++ altosui/AltosFlightStats.java | 6 ++-- altosui/AltosFlightUI.java | 2 +- altosui/AltosLanded.java | 59 +++++++++++++++++++++++++++++++++++++-- altosui/AltosLog.java | 6 ++++ altosui/AltosReplayReader.java | 8 ++++-- altosui/AltosTelemetryReader.java | 4 +++ altosui/AltosUI.java | 10 +++++-- 8 files changed, 86 insertions(+), 11 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightReader.java b/altosui/AltosFlightReader.java index 3a171444..47df375d 100644 --- a/altosui/AltosFlightReader.java +++ b/altosui/AltosFlightReader.java @@ -42,4 +42,6 @@ public class AltosFlightReader { void save_telemetry() { } void update(AltosState state) throws InterruptedException { } + + File backing_file() { return null; } } diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index e38142f0..e644b0ba 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -85,11 +85,11 @@ public class AltosFlightStats { } } - public AltosFlightStats(AltosRecordIterable iterable, String filename) throws InterruptedException, IOException { - this(new AltosReplayReader(iterable.iterator(), filename)); + public AltosFlightStats(AltosRecordIterable iterable, File file) throws InterruptedException, IOException { + this(new AltosReplayReader(iterable.iterator(), file)); } public AltosFlightStats(AltosRecordIterable iterable) throws InterruptedException, IOException { - this(iterable, ""); + this(iterable, new File("")); } } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index c31e02bf..f0626e7c 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -210,7 +210,7 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { descent = new AltosDescent(); pane.add("Descent", descent); - landed = new AltosLanded(); + landed = new AltosLanded(reader); pane.add("Landed", landed); flightInfo = new AltosInfoTable(); diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index d5c8e434..47aca29d 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -28,7 +28,7 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; -public class AltosLanded extends JComponent implements AltosFlightDisplay { +public class AltosLanded extends JComponent implements AltosFlightDisplay, ActionListener { GridBagLayout layout; Font label_font; Font value_font; @@ -214,11 +214,51 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { height.show(state, crc_errors); speed.show(state, crc_errors); accel.show(state, crc_errors); + if (reader.backing_file() != null) + graph.setEnabled(true); } - public AltosLanded() { + JButton graph; + AltosFlightReader reader; + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if (cmd.equals("graph")) { + File file = reader.backing_file(); + if (file != null) { + String filename = file.getName(); + try { + AltosRecordIterable records = null; + if (filename.endsWith("eeprom")) { + FileInputStream in = new FileInputStream(file); + records = new AltosEepromIterable(in); + } else if (filename.endsWith("telem")) { + FileInputStream in = new FileInputStream(file); + records = new AltosTelemetryIterable(in); + } else { + throw new FileNotFoundException(); + } + try { + new AltosGraphUI(records); + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + } catch (FileNotFoundException fe) { + JOptionPane.showMessageDialog(null, + filename, + "Cannot open file", + JOptionPane.ERROR_MESSAGE); + } + } + } + } + + public AltosLanded(AltosFlightReader in_reader) { layout = new GridBagLayout(); + reader = in_reader; + label_font = new Font("Dialog", Font.PLAIN, 22); value_font = new Font("Monospaced", Font.PLAIN, 22); setLayout(layout); @@ -231,5 +271,20 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay { height = new Height(layout, 4); speed = new Speed(layout, 5); accel = new Accel(layout, 6); + + graph = new JButton ("Graph Flight"); + graph.setActionCommand("graph"); + graph.addActionListener(this); + graph.setEnabled(false); + + GridBagConstraints c = new GridBagConstraints(); + + c.gridx = 0; c.gridy = 7; + c.insets = new Insets(10, 10, 10, 10); + c.anchor = GridBagConstraints.WEST; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.VERTICAL; + add(graph, c); } } diff --git a/altosui/AltosLog.java b/altosui/AltosLog.java index 6157a656..a5f1830d 100644 --- a/altosui/AltosLog.java +++ b/altosui/AltosLog.java @@ -35,6 +35,7 @@ class AltosLog implements Runnable { int flight; FileWriter log_file; Thread log_thread; + AltosFile file; private void close_log_file() { if (log_file != null) { @@ -54,6 +55,10 @@ class AltosLog implements Runnable { } } + File file() { + return file; + } + boolean open (AltosRecord telem) throws IOException { AltosFile a = new AltosFile(telem); @@ -69,6 +74,7 @@ class AltosLog implements Runnable { } } log_file.flush(); + file = a; } return log_file != null; } diff --git a/altosui/AltosReplayReader.java b/altosui/AltosReplayReader.java index 4e5e1d93..eed56cff 100644 --- a/altosui/AltosReplayReader.java +++ b/altosui/AltosReplayReader.java @@ -34,6 +34,7 @@ import java.util.concurrent.LinkedBlockingQueue; public class AltosReplayReader extends AltosFlightReader { Iterator iterator; + File file; public AltosRecord read() { if (iterator.hasNext()) @@ -50,8 +51,11 @@ public class AltosReplayReader extends AltosFlightReader { Thread.sleep((int) (Math.min(state.time_change,10) * 1000)); } - public AltosReplayReader(Iterator in_iterator, String in_name) { + public File backing_file() { return file; } + + public AltosReplayReader(Iterator in_iterator, File in_file) { iterator = in_iterator; - name = in_name; + file = in_file; + name = file.getName(); } } diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 6abe95d8..1f327a67 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -69,6 +69,10 @@ class AltosTelemetryReader extends AltosFlightReader { AltosPreferences.set_telemetry(device.getSerial(), telemetry); } + File backing_file() { + return log.file(); + } + public AltosTelemetryReader (AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException, IOException, InterruptedException, TimeoutException { device = in_device; diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index fefe74e8..62e612ed 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -276,7 +276,7 @@ public class AltosUI extends JFrame { AltosRecordIterable iterable = chooser.runDialog(); if (iterable != null) { AltosFlightReader reader = new AltosReplayReader(iterable.iterator(), - chooser.filename()); + chooser.file()); new AltosFlightUI(voice, reader); } } @@ -310,7 +310,11 @@ public class AltosUI extends JFrame { AltosRecordIterable record_reader = chooser.runDialog(); if (record_reader == null) return; - new AltosGraphUI(record_reader); + try { + new AltosGraphUI(record_reader); + } catch (InterruptedException ie) { + } catch (IOException ie) { + } } private void ConfigureAltosUI() { @@ -427,7 +431,7 @@ public class AltosUI extends JFrame { } else { recs = new AltosTelemetryIterable(in); } - reader = new AltosReplayReader(recs.iterator(), filename); + reader = new AltosReplayReader(recs.iterator(), new File(filename)); AltosFlightUI flight_ui = new AltosFlightUI(new AltosVoice(), reader); flight_ui.set_exit_on_close(); return; -- cgit v1.2.3 From 01b9352eb8ca0e4e2d023ce973c4e863cdcc0c51 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 10 Aug 2011 14:34:39 -0700 Subject: altosui: Prune telemetry file graphs to just the flight Remove data earlier than 1 second before boost and data after landing. Signed-off-by: Keith Packard --- altosui/AltosDataPointReader.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index fa48013f..c3aabb0c 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -69,10 +69,14 @@ class AltosDataPointReader implements Iterable { throw new UnsupportedOperationException(); } public boolean hasNext() { + if (record != null && record.state == Altos.ao_flight_landed) + return false; return iter.hasNext(); } public AltosDataPoint next() { - read_next_record(); + do { + read_next_record(); + } while (record.time < -1.0 && hasNext()); return current_dp(); } }; -- cgit v1.2.3 From 4962bcf1ce15c21a946ea718bd676b901f0f2bd0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 10 Aug 2011 14:35:21 -0700 Subject: altosui: Plot reasonable data from Tm files Don't plot acceleration based on baro data. Display baro speed if accel speed isn't available. Signed-off-by: Keith Packard --- altosui/AltosFlightStats.java | 5 ++++- altosui/AltosFlightStatsTable.java | 18 ++++++++++-------- altosui/AltosState.java | 4 ++++ 3 files changed, 18 insertions(+), 9 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index e644b0ba..19471e9f 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -67,7 +67,10 @@ public class AltosFlightStats { if (state_end[state.state] < state.time) state_end[state.state] = state.time; max_height = state.max_height; - max_speed = state.max_speed; + if (state.max_speed != 0) + max_speed = state.max_speed; + else + max_speed = state.max_baro_speed; max_acceleration = state.max_acceleration; } } catch (ParseException pp) { diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index 8676d306..e2c0dd46 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -77,14 +77,16 @@ public class AltosFlightStatsTable extends JComponent { String.format("%5.0f m/s", stats.max_speed), String.format("%5.0f ft/s", stats.max_speed * 100 / 2.54 / 12), String.format("Mach %5.3f", stats.max_speed / 343.0)); - new FlightStat(layout, y++, "Maximum acceleration", - String.format("%5.0f m/s²", stats.max_acceleration), - String.format("%5.0f ft/s²", stats.max_acceleration * 100 / 2.54 /12), - String.format("%5.2f G", stats.max_acceleration / 9.80665)); - new FlightStat(layout, y++, "Average boost acceleration", - String.format("%5.0f m/s²", stats.state_accel[Altos.ao_flight_boost]), - String.format("%5.0f ft/s²", stats.state_accel[Altos.ao_flight_boost] * 100 / 2.54 /12), - String.format("%5.2f G", stats.state_accel[Altos.ao_flight_boost] / 9.80665)); + if (stats.max_acceleration != AltosRecord.MISSING) { + new FlightStat(layout, y++, "Maximum acceleration", + String.format("%5.0f m/s²", stats.max_acceleration), + String.format("%5.0f ft/s²", stats.max_acceleration * 100 / 2.54 /12), + String.format("%5.2f G", stats.max_acceleration / 9.80665)); + new FlightStat(layout, y++, "Average boost acceleration", + String.format("%5.0f m/s²", stats.state_accel[Altos.ao_flight_boost]), + String.format("%5.0f ft/s²", stats.state_accel[Altos.ao_flight_boost] * 100 / 2.54 /12), + String.format("%5.2f G", stats.state_accel[Altos.ao_flight_boost] / 9.80665)); + } new FlightStat(layout, y++, "Drogue descent rate", String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_drogue]), String.format("%5.0f ft/s", stats.state_baro_speed[Altos.ao_flight_drogue] * 100 / 2.54 / 12)); diff --git a/altosui/AltosState.java b/altosui/AltosState.java index 1ac816d5..378930bf 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -49,6 +49,7 @@ public class AltosState { double max_height; double max_acceleration; double max_speed; + double max_baro_speed; AltosGPS gps; @@ -105,6 +106,7 @@ public class AltosState { max_height = prev_state.max_height; max_acceleration = prev_state.max_acceleration; max_speed = prev_state.max_speed; + max_baro_speed = prev_state.max_baro_speed; /* make sure the clock is monotonic */ while (tick < prev_state.tick) @@ -171,6 +173,8 @@ public class AltosState { max_acceleration = acceleration; if (ascent && speed > max_speed) max_speed = speed; + if (ascent && baro_speed > max_baro_speed) + max_baro_speed = baro_speed; if (height > max_height) max_height = height; -- cgit v1.2.3 From 9f5623c8c32a38eaeb63fa74ab370025ac015d52 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 10 Aug 2011 15:00:44 -0700 Subject: altosui: Move launch-sites.txt file to altusmetrum.org The official URL is now: http://www.altusmetrum.org/AltOS/launch-sites.txt Signed-off-by: Keith Packard --- altosui/Altos.java | 2 ++ altosui/AltosSiteMapPreload.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index d90c4183..73dc7468 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -80,6 +80,8 @@ public class Altos { "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" }; + static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; + static final int ao_telemetry_standard_len = 32; static final int ao_telemetry_0_9_len = 95; static final int ao_telemetry_0_8_len = 94; diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 5d437e17..aa07bebc 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -204,7 +204,7 @@ class AltosSites extends Thread { sites = new LinkedList(); preload = in_preload; try { - url = new URL("http://gag.com/~keithp/launch-sites.txt"); + url = new URL(Altos.launch_sites_url); } catch (java.net.MalformedURLException e) { notify_complete(); } -- cgit v1.2.3 From 5aa3e49f794ba5ed2680016f3dca47d67ae99836 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 10 Aug 2011 18:32:05 -0700 Subject: doc: Add telemetry docs to debian/linux/mac/windows packages Signed-off-by: Keith Packard --- altosui/Makefile.am | 3 ++- altosui/altos-windows.nsi | 1 + debian/docs | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 3bc68cdb..bab8f816 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -169,9 +169,10 @@ FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf ALTOS_DOC=$(top_srcdir)/doc/altos.pdf +TELEMETRY_DOC=$(top_srcdir)/doc/telemetry.pdf TEMPLATE_DOC=$(top_srcdir)/doc/telemetrum-outline.pdf -DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TEMPLATE_DOC) +DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TELEMETRY_DOC) $(TEMPLATE_DOC) # Distribution targets LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2 diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index d92d1eb3..7c9b7a28 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -92,6 +92,7 @@ Section "Documentation" File "../doc/altusmetrum.pdf" File "../doc/altos.pdf" + File "../doc/telemetry.pdf" File "../doc/telemetrum-outline.pdf" SectionEnd diff --git a/debian/docs b/debian/docs index 13fda8f2..6652abf7 100644 --- a/debian/docs +++ b/debian/docs @@ -2,3 +2,8 @@ NEWS README doc/altusmetrum.html doc/altusmetrum.pdf +doc/telemetry.html +doc/telemetry.pdf +doc/altos.html +doc/altos.pdf +doc/telemetrum-outline.pdf -- cgit v1.2.3 From 313d740b5284b24f1cc7a1ba5779136b55d49ebe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 18:33:07 -0700 Subject: libaltos: Mis-allocated device list in libaltos Would overrun mis-allocated array, causing chaos. Signed-off-by: Keith Packard --- altosui/libaltos/libaltos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 00a75de9..f2c8bd8d 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -559,7 +559,7 @@ altos_list_start(void) if (USB_IS_ALTUSMETRUM(dev->idVendor, dev->idProduct)) { if (devs->dev) devs->dev = realloc(devs->dev, - devs->ndev + 1 * sizeof (struct usbdev *)); + (devs->ndev + 1) * sizeof (struct usbdev *)); else devs->dev = malloc (sizeof (struct usbdev *)); devs->dev[devs->ndev++] = dev; -- cgit v1.2.3 From bf06af154e232d4caa1585a1d6d5279a075292e4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 12 Aug 2011 21:43:56 -0700 Subject: altos/altosui: Report log format in the version command This will make it easier to figure out what the contents of the flash should look like from altosui; the current 'guessing' mechanism will not scale to many more formats. Signed-off-by: Keith Packard --- altosui/Altos.java | 32 ++++++++++++++++++++++++++++++++ altosui/AltosConfig.java | 3 +++ altosui/AltosConfigData.java | 2 ++ altosui/AltosEepromDownload.java | 26 +++++++++++++------------- altosui/AltosEepromRecord.java | 3 +++ src/ao.h | 9 +++++++++ src/ao_cmd.c | 3 +++ src/ao_log.c | 2 ++ src/ao_log_tiny.c | 2 ++ src/ao_telebt.c | 2 ++ 10 files changed, 71 insertions(+), 13 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 73dc7468..416d9328 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -51,6 +51,7 @@ public class Altos { static final int AO_LOG_MANUFACTURER = 2000; static final int AO_LOG_PRODUCT = 2001; static final int AO_LOG_SERIAL_NUMBER = 2002; + static final int AO_LOG_LOG_FORMAT = 2003; static final int AO_LOG_SOFTWARE_VERSION = 9999; /* Added to flag invalid records */ @@ -177,6 +178,13 @@ public class Altos { static final int AO_GPS_NUM_SAT_SHIFT = 0; static final int AO_GPS_NUM_SAT_MASK = 0xf; + static final int AO_LOG_FORMAT_UNKNOWN = 0; + static final int AO_LOG_FORMAT_FULL = 1; + static final int AO_LOG_FORMAT_TINY = 2; + static final int AO_LOG_FORMAT_TELEMETRY = 3; + static final int AO_LOG_FORMAT_TELESCIENCE = 4; + static final int AO_LOG_FORMAT_NONE = 127; + static boolean isspace(int c) { switch (c) { case ' ': @@ -404,12 +412,36 @@ public class Altos { return 0x000e; } + static int usb_product_telelaunch() { + load_library(); + return 0x000f; + } + + static int usb_product_telelco() { + load_library(); + return 0x0010; + } + + static int usb_product_telescience() { + load_library(); + return 0x0011; + } + + static int usb_product_telepyro() { + load_library(); + return 0x0012; + } + public final static int vendor_altusmetrum = usb_vendor_altusmetrum(); public final static int product_altusmetrum = usb_product_altusmetrum(); public final static int product_telemetrum = usb_product_telemetrum(); public final static int product_teledongle = usb_product_teledongle(); public final static int product_teleterra = usb_product_teleterra(); public final static int product_telebt = usb_product_telebt(); + public final static int product_telelaunch = usb_product_telelaunch(); + public final static int product_tele10 = usb_product_telelco(); + public final static int product_telescience = usb_product_telescience(); + public final static int product_telepyro = usb_product_telepyro(); public final static int product_altusmetrum_min = usb_product_altusmetrum_min(); public final static int product_altusmetrum_max = usb_product_altusmetrum_max(); diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 7312ea6c..ffabe209 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -67,6 +67,7 @@ public class AltosConfig implements ActionListener { AltosConfigData remote_config_data; double remote_frequency; int_ref serial; + int_ref log_format; int_ref main_deploy; int_ref apogee_delay; int_ref radio_channel; @@ -153,6 +154,7 @@ public class AltosConfig implements ActionListener { return; } get_int(line, "serial-number", serial); + get_int(line, "log-format", log_format); get_int(line, "Main deploy:", main_deploy); get_int(line, "Apogee delay:", apogee_delay); get_int(line, "Radio channel:", radio_channel); @@ -374,6 +376,7 @@ public class AltosConfig implements ActionListener { owner = given_owner; serial = new int_ref(0); + log_format = new int_ref(Altos.AO_LOG_FORMAT_UNKNOWN); main_deploy = new int_ref(250); apogee_delay = new int_ref(0); radio_channel = new int_ref(0); diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 016033a3..710231d7 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -36,6 +36,7 @@ public class AltosConfigData implements Iterable { String manufacturer; String product; String version; + int log_format; int serial; /* Strings returned */ @@ -94,6 +95,7 @@ public class AltosConfigData implements Iterable { continue; lines.add(line); try { serial = get_int(line, "serial-number"); } catch (Exception e) {} + try { log_format = get_int(line, "log-format"); } catch (Exception e) {} try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 64dcdff7..417aab00 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -89,9 +89,6 @@ public class AltosEepromDownload implements Runnable { } } - static final int log_full = 1; - static final int log_tiny = 2; - boolean done; int state; @@ -186,7 +183,7 @@ public class AltosEepromDownload implements Runnable { void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException { int block, state_block = 0; - int log_style = 0; + int log_format = flights.config_data.log_format; state = 0; done = false; @@ -215,21 +212,24 @@ public class AltosEepromDownload implements Runnable { AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block); /* - * Figure out what kind of data is there + * Guess what kind of data is there if the device + * didn't tell us */ - if (block == log.start_block) { - if (eechunk.data(0) == Altos.AO_LOG_FLIGHT) - log_style = log_full; - else - log_style = log_tiny; + if (log_format == Altos.AO_LOG_FORMAT_UNKNOWN) { + if (block == log.start_block) { + if (eechunk.data(0) == Altos.AO_LOG_FLIGHT) + log_format = Altos.AO_LOG_FORMAT_FULL; + else + log_format = Altos.AO_LOG_FORMAT_TINY; + } } - switch (log_style) { - case log_full: + switch (log_format) { + case Altos.AO_LOG_FORMAT_FULL: CaptureFull(eechunk); break; - case log_tiny: + case Altos.AO_LOG_FORMAT_TINY: CaptureTiny(eechunk); break; } diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index 52acb435..c0f97035 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -143,6 +143,9 @@ public class AltosEepromRecord { } else if (tokens[0].equals("serial-number")) { cmd = Altos.AO_LOG_SERIAL_NUMBER; a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("log-format")) { + cmd = Altos.AO_LOG_LOG_FORMAT; + a = Integer.parseInt(tokens[1]); } else if (tokens[0].equals("software-version")) { cmd = Altos.AO_LOG_SOFTWARE_VERSION; data = tokens[1]; diff --git a/src/ao.h b/src/ao.h index 0699fc2c..1c8f5bbf 100644 --- a/src/ao.h +++ b/src/ao.h @@ -539,6 +539,15 @@ extern __pdata enum flight_state ao_log_state; /* required functions from the underlying log system */ +#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */ +#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */ +#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ +#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ +#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ +#define AO_LOG_FORMAT_NONE 127 /* No log at all */ + +extern __code uint8_t ao_log_format; + /* Return the flight number from the given log slot, 0 if none */ uint16_t ao_log_flight(uint8_t slot); diff --git a/src/ao_cmd.c b/src/ao_cmd.c index 6d3ae38d..1442ebea 100644 --- a/src/ao_cmd.c +++ b/src/ao_cmd.c @@ -219,6 +219,9 @@ version(void) printf("manufacturer %s\n", ao_manufacturer); printf("product %s\n", ao_product); printf("serial-number %u\n", ao_serial_number); +#if HAS_EEPROM + printf("log-format %u\n", ao_log_format); +#endif printf("software-version %s\n", ao_version); } diff --git a/src/ao_log.c b/src/ao_log.c index 80d7243d..6d3ad535 100644 --- a/src/ao_log.c +++ b/src/ao_log.c @@ -24,6 +24,8 @@ __xdata uint8_t ao_log_running; __pdata enum flight_state ao_log_state; __xdata uint16_t ao_flight_number; +__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL; + void ao_log_flush(void) { diff --git a/src/ao_log_tiny.c b/src/ao_log_tiny.c index d26e0080..d5a3b99f 100644 --- a/src/ao_log_tiny.c +++ b/src/ao_log_tiny.c @@ -28,6 +28,8 @@ static __data uint16_t ao_log_tiny_interval; #define AO_PAD_RING 2 #endif +__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY; + void ao_log_tiny_set_interval(uint16_t ticks) { diff --git a/src/ao_telebt.c b/src/ao_telebt.c index 8e77c4d9..85565172 100644 --- a/src/ao_telebt.c +++ b/src/ao_telebt.c @@ -17,6 +17,8 @@ #include "ao.h" +__code uint8_t ao_log_format = AO_LOG_FORMAT_NONE; /* until we actually log stuff */ + void main(void) { -- cgit v1.2.3 From 578c4b17b8f62f2727654ebda78ee139f9fe13fa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 18:38:38 -0700 Subject: altos: Don't try to use non-basestations for remote eeprom download Companion boards may also have eeprom data to fetch; don't try to use them as a radio. Signed-off-by: Keith Packard --- altosui/AltosEepromManage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index cd2b74fe..0652ca04 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -206,7 +206,7 @@ public class AltosEepromManage implements ActionListener { if (device != null) { try { serial_line = new AltosSerial(device); - if (!device.matchProduct(Altos.product_telemetrum)) + if (device.matchProduct(Altos.product_basestation)) remote = true; serial_line.set_frame(frame); -- cgit v1.2.3 From c7f540330c040c521f9d7626009a406e704a5e41 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 12 Aug 2011 14:58:34 -0700 Subject: altosui: Add companion support to the flight UI and CSV conversion Shows the companion data in a new tab. Also put companion data into CSV file. Signed-off-by: Keith Packard --- altosui/AltosCSV.java | 49 +++++++++++-- altosui/AltosCompanionInfo.java | 111 +++++++++++++++++++++++++++++ altosui/AltosFlightUI.java | 20 +++++- altosui/AltosRecord.java | 5 ++ altosui/AltosRecordCompanion.java | 38 ++++++++++ altosui/AltosState.java | 1 - altosui/AltosTelemetryRecordCompanion.java | 52 ++++++++++++++ altosui/AltosTelemetryRecordRaw.java | 10 ++- altosui/Makefile.am | 3 + 9 files changed, 281 insertions(+), 8 deletions(-) create mode 100644 altosui/AltosCompanionInfo.java create mode 100644 altosui/AltosRecordCompanion.java create mode 100644 altosui/AltosTelemetryRecordCompanion.java (limited to 'altosui') diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index 5277c160..cf649db0 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -31,9 +31,9 @@ public class AltosCSV implements AltosWriter { LinkedList pad_records; AltosState state; - static final int ALTOS_CSV_VERSION = 2; + static final int ALTOS_CSV_VERSION = 3; - /* Version 2 format: + /* Version 3 format: * * General info * version number @@ -81,6 +81,13 @@ public class AltosCSV implements AltosWriter { * * GPS Sat data * C/N0 data for all 32 valid SDIDs + * + * Companion data + * companion_id (1-255. 10 is TeleScience) + * time of last companion data (seconds since boost) + * update_period (0.1-2.55 minimum telemetry interval) + * channels (0-12) + * channel data for all 12 possible channels */ void write_general_header() { @@ -179,7 +186,32 @@ public class AltosCSV implements AltosWriter { } } - void write_header(boolean gps) { + void write_companion_header() { + out.printf("companion_id,companion_time,companion_update,companion_channels"); + for (int i = 0; i < 12; i++) + out.printf(",companion_%02d", i); + } + + void write_companion(AltosRecord record) { + AltosRecordCompanion companion = record.companion; + + int channels_written = 0; + if (companion == null) { + out.printf("0,0,0,0"); + } else { + out.printf("%3d,%5.2f,%5.2f,%2d", + companion.board_id, + (companion.tick - boost_tick) / 100.0, + companion.update_period / 100.0, + companion.channels); + for (; channels_written < companion.channels; channels_written++) + out.printf(",%5d", companion.companion_data[channels_written]); + } + for (; channels_written < 12; channels_written++) + out.printf(",0"); + } + + void write_header(boolean gps, boolean companion) { out.printf("#"); write_general_header(); out.printf(","); write_flight_header(); out.printf(","); write_basic_header(); @@ -187,6 +219,9 @@ public class AltosCSV implements AltosWriter { out.printf(","); write_gps_header(); out.printf(","); write_gps_sat_header(); } + if (companion) { + out.printf(","); write_companion_header(); + } out.printf ("\n"); } @@ -200,6 +235,10 @@ public class AltosCSV implements AltosWriter { write_gps(record); out.printf(","); write_gps_sat(record); } + if (record.companion != null) { + out.printf(","); + write_companion(record); + } out.printf ("\n"); } @@ -210,8 +249,10 @@ public class AltosCSV implements AltosWriter { } public void write(AltosRecord record) { + if (record.state == Altos.ao_flight_startup) + return; if (!header_written) { - write_header(record.gps != null); + write_header(record.gps != null, record.companion != null); header_written = true; } if (!seen_boost) { diff --git a/altosui/AltosCompanionInfo.java b/altosui/AltosCompanionInfo.java new file mode 100644 index 00000000..f287a8ea --- /dev/null +++ b/altosui/AltosCompanionInfo.java @@ -0,0 +1,111 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public class AltosCompanionInfo extends JTable { + private AltosFlightInfoTableModel model; + + private Font infoLabelFont = new Font("SansSerif", Font.PLAIN, 14); + private Font infoValueFont = new Font("Monospaced", Font.PLAIN, 14); + + static final int info_columns = 2; + static final int info_rows = 17; + + int desired_row_height() { + FontMetrics infoValueMetrics = getFontMetrics(infoValueFont); + return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10; + } + + public AltosCompanionInfo() { + super(new AltosFlightInfoTableModel(info_rows, info_columns)); + model = (AltosFlightInfoTableModel) getModel(); + setFont(infoValueFont); + setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS); + setShowGrid(true); + setRowHeight(desired_row_height()); + doLayout(); + } + + public Dimension getPreferredScrollableViewportSize() { + return getPreferredSize(); + } + + void info_reset() { + model.reset(); + } + + void info_add_row(int col, String name, String value) { + model.addRow(col, name, value); + } + + void info_add_row(int col, String name, String format, Object... parameters) { + info_add_row (col, name, String.format(format, parameters)); + } + + void info_finish() { + model.finish(); + } + + public void clear() { + model.clear(); + } + + AltosRecordCompanion companion; + + public String board_name() { + if (companion == null) + return "None"; + switch (companion.board_id) { + case AltosRecordCompanion.board_id_telescience: + return "TeleScience"; + default: + return String.format("%02x\n", companion.board_id); + } + } + + public void show(AltosState state, int crc_errors) { + if (state == null) + return; + if (state.data.companion != null) + companion = state.data.companion; + info_reset(); + info_add_row(0, "Companion board", "%s", board_name()); + if (companion != null) { + info_add_row(0, "Last Data", "%5d", companion.tick); + info_add_row(0, "Update period", "%5.2f s", + companion.update_period / 100.0); + info_add_row(0, "Channels", "%3d", companion.channels); + + for (int i = 0; i < companion.channels; i++) + info_add_row(1, String.format("Channel %2d", i), + "%6d", companion.companion_data[i]); + } + info_finish(); + } +} diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index f0626e7c..51768046 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -39,8 +39,10 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { AltosAscent ascent; AltosDescent descent; AltosLanded landed; + AltosCompanionInfo companion; AltosSiteMap sitemap; boolean has_map; + boolean has_companion; private AltosFlightStatus flightStatus; private AltosInfoTable flightInfo; @@ -96,7 +98,20 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { } flightStatus.show(state, crc_errors); flightInfo.show(state, crc_errors); - if (state.gps != null) { + + if (state.data.companion != null) { + if (!has_companion) { + pane.add("Companion", companion); + has_companion= true; + } + companion.show(state, crc_errors); + } else { + if (has_companion) { + pane.remove(companion); + has_companion = false; + } + } + if (state.gps != null && state.gps.connected) { if (!has_map) { pane.add("Site Map", sitemap); has_map = true; @@ -216,6 +231,9 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { flightInfo = new AltosInfoTable(); pane.add("Table", new JScrollPane(flightInfo)); + companion = new AltosCompanionInfo(); + has_companion = false; + sitemap = new AltosSiteMap(); has_map = false; diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index 144b1c3c..ce6d86ab 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -32,6 +32,7 @@ public class AltosRecord { static final int seen_gps_time = 16; static final int seen_gps_lat = 32; static final int seen_gps_lon = 64; + static final int seen_companion = 128; int seen; int version; @@ -74,6 +75,8 @@ public class AltosRecord { int main_deploy; int flight_log_max; String firmware_version; + + AltosRecordCompanion companion; /* * Values for our MP3H6115A pressure sensor * @@ -267,6 +270,7 @@ public class AltosRecord { speed = old.speed; height = old.height; gps = new AltosGPS(old.gps); + companion = old.companion; } public AltosRecord() { @@ -296,5 +300,6 @@ public class AltosRecord { speed = MISSING; height = MISSING; gps = new AltosGPS(); + companion = null; } } diff --git a/altosui/AltosRecordCompanion.java b/altosui/AltosRecordCompanion.java new file mode 100644 index 00000000..0a8f9f4b --- /dev/null +++ b/altosui/AltosRecordCompanion.java @@ -0,0 +1,38 @@ +/* + * 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 altosui; + +public class AltosRecordCompanion { + final static int board_id_telescience = 0x0a; + final static int MAX_CHANNELS = 12; + + int tick; + int board_id; + int update_period; + int channels; + int[] companion_data; + + public AltosRecordCompanion(int in_channels) { + channels = in_channels; + if (channels < 0) + channels = 0; + if (channels > MAX_CHANNELS) + channels = MAX_CHANNELS; + companion_data = new int[channels]; + } +} diff --git a/altosui/AltosState.java b/altosui/AltosState.java index 378930bf..072cb790 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -73,7 +73,6 @@ public class AltosState { int speak_tick; double speak_altitude; - void init (AltosRecord cur, AltosState prev_state) { int i; AltosRecord prev; diff --git a/altosui/AltosTelemetryRecordCompanion.java b/altosui/AltosTelemetryRecordCompanion.java new file mode 100644 index 00000000..11b349e1 --- /dev/null +++ b/altosui/AltosTelemetryRecordCompanion.java @@ -0,0 +1,52 @@ +/* + * 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 altosui; + +public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { + + AltosRecordCompanion companion; + + public AltosTelemetryRecordCompanion(int[] in_bytes) { + super(in_bytes); + + int off = 0; + if (uint8(6) == 0) + off = 1; + int channels = uint8(7+off); + + if (off != 0 && channels >= 12) + channels = 11; + + companion = new AltosRecordCompanion(channels); + companion.tick = tick; + companion.board_id = uint8(5); + companion.update_period = uint8(6+off); + for (int i = 0; i < channels; i++) + companion.companion_data[i] = uint16(8 + off + i * 2); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + next.companion = companion; + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + + companion.tick = tick; + return next; + } +} diff --git a/altosui/AltosTelemetryRecordRaw.java b/altosui/AltosTelemetryRecordRaw.java index 4b34f017..39b2ba07 100644 --- a/altosui/AltosTelemetryRecordRaw.java +++ b/altosui/AltosTelemetryRecordRaw.java @@ -33,6 +33,7 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { final static int packet_type_configuration = 0x04; final static int packet_type_location = 0x05; final static int packet_type_satellite = 0x06; + final static int packet_type_companion = 0x07; final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); @@ -89,6 +90,9 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { case packet_type_satellite: r = new AltosTelemetryRecordSatellite(bytes); break; + case packet_type_companion: + r = new AltosTelemetryRecordCompanion(bytes); + break; default: r = new AltosTelemetryRecordRaw(bytes); break; @@ -139,9 +143,11 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { public AltosRecord update_state(AltosRecord previous) { AltosRecord next; - if (previous != null) + if (previous != null) { next = new AltosRecord(previous); - else + while (tick < previous.tick) + tick += 65536; + } else next = new AltosRecord(); next.serial = serial; next.tick = tick; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index bab8f816..83510352 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -20,6 +20,7 @@ altosui_JAVA = \ GrabNDrag.java \ AltosAscent.java \ AltosChannelMenu.java \ + AltosCompanionInfo.java \ AltosConfig.java \ AltosConfigData.java \ AltosConfigFreqUI.java \ @@ -77,6 +78,7 @@ altosui_JAVA = \ AltosPreferences.java \ AltosReader.java \ AltosRecord.java \ + AltosRecordCompanion.java \ AltosRecordIterable.java \ AltosTelemetryReader.java \ AltosTelemetryRecord.java \ @@ -86,6 +88,7 @@ altosui_JAVA = \ AltosTelemetryRecordConfiguration.java \ AltosTelemetryRecordLocation.java \ AltosTelemetryRecordSatellite.java \ + AltosTelemetryRecordCompanion.java \ AltosTelemetryRecordLegacy.java \ AltosTelemetryMap.java \ AltosReplayReader.java \ -- cgit v1.2.3 From 5a3e96bef31959a287b8696778d7d8cf911a7dc4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 18:36:18 -0700 Subject: altosui: Clean up eeprom parsing a bit Export basic parsing and checksum functions for shared use. Create 'erased' function to check a chunk of eeprom data for data. Signed-off-by: Keith Packard --- altosui/AltosConvert.java | 20 ++++++++++++++++++++ altosui/AltosEepromChunk.java | 7 +++++++ altosui/AltosEepromRecord.java | 30 +++--------------------------- 3 files changed, 30 insertions(+), 27 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConvert.java b/altosui/AltosConvert.java index c2ae9a50..207470a5 100644 --- a/altosui/AltosConvert.java +++ b/altosui/AltosConvert.java @@ -220,4 +220,24 @@ public class AltosConvert { static double radio_channel_to_frequency(int channel) { return 434.550 + channel * 0.100; } + + static int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + static int checksum(int[] data, int start, int length) { + int csum = 0x5a; + for (int i = 0; i < length; i++) + csum += data[i + start]; + return csum & 0xff; + } } diff --git a/altosui/AltosEepromChunk.java b/altosui/AltosEepromChunk.java index 1e42077f..fb632a3f 100644 --- a/altosui/AltosEepromChunk.java +++ b/altosui/AltosEepromChunk.java @@ -52,6 +52,13 @@ public class AltosEepromChunk { return data[offset] | (data[offset + 1] << 8); } + boolean erased(int start, int len) { + for (int i = 0; i < len; i++) + if (data[start+i] != 0xff) + return false; + return true; + } + public AltosEepromChunk(AltosSerial serial_line, int block) throws TimeoutException, InterruptedException { diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index c0f97035..d8a07951 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -40,42 +40,18 @@ public class AltosEepromRecord { static final int record_length = 8; - int[] ParseHex(String line) { - String[] tokens = line.split("\\s+"); - int[] array = new int[tokens.length]; - - for (int i = 0; i < tokens.length; i++) - try { - array[i] = Integer.parseInt(tokens[i], 16); - } catch (NumberFormatException ne) { - return null; - } - return array; - } - - int checksum(int[] data, int start) { - int csum = 0x5a; - for (int i = 0; i < record_length; i++) - csum += data[i + start]; - return csum & 0xff; - } - public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException { cmd = chunk.data(start); tick_valid = true; - int i; - for (i = 0; i < record_length; i++) - if (chunk.data[start + i] != 0xff) - break; - if (i != 8) { - if (checksum(chunk.data, start) != 0) + tick_valid = !chunk.erased(start, record_length); + if (tick_valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) throw new ParseException(String.format("invalid checksum at 0x%x", chunk.address + start), 0); } else { cmd = Altos.AO_LOG_INVALID; - tick_valid = false; } tick = chunk.data16(start + 2); -- cgit v1.2.3 From 03e201e1acc8742399054e4ad36b533120ea1612 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 18:39:35 -0700 Subject: altosui: Add support for TeleScience eeprom download Using the existing eeprom methods, fetch and save TeleScience eeprom data, storing to a filename generated from the serial/flight from the TM connected to the TS board. Signed-off-by: Keith Packard --- altosui/AltosEepromDownload.java | 95 +++++++++++++++++++++++++++++++++---- altosui/AltosEepromList.java | 4 +- altosui/AltosEepromLog.java | 65 +++++++++++++------------ altosui/AltosEepromTeleScience.java | 64 +++++++++++++++++++++++++ altosui/Makefile.am | 1 + 5 files changed, 188 insertions(+), 41 deletions(-) create mode 100644 altosui/AltosEepromTeleScience.java (limited to 'altosui') diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 417aab00..6112a3b1 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -39,6 +39,7 @@ public class AltosEepromDownload implements Runnable { AltosEepromMonitor monitor; int flight; + int serial; int year, month, day; boolean want_file; FileWriter eeprom_file; @@ -48,6 +49,7 @@ public class AltosEepromDownload implements Runnable { ActionListener listener; boolean success; ParseException parse_exception; + String extension; private void FlushPending() throws IOException { for (String s : flights.config_data) { @@ -64,10 +66,13 @@ public class AltosEepromDownload implements Runnable { return; if (force || (flight != 0 && want_file)) { AltosFile eeprom_name; + + if (extension == null) + extension = "data"; if (year != 0 && month != 0 && day != 0) - eeprom_name = new AltosFile(year, month, day, flights.config_data.serial, flight, "eeprom"); + eeprom_name = new AltosFile(year, month, day, serial, flight, extension); else - eeprom_name = new AltosFile(flights.config_data.serial, flight, "eeprom"); + eeprom_name = new AltosFile(serial, flight, extension); eeprom_file = new FileWriter(eeprom_name); if (eeprom_file != null) { @@ -89,18 +94,29 @@ public class AltosEepromDownload implements Runnable { } } + void set_serial(int in_serial) { + serial = in_serial; + monitor.set_serial(serial); + } + + void set_flight(int in_flight) { + flight = in_flight; + monitor.set_flight(flight); + } + boolean done; int state; void CaptureFull(AltosEepromChunk eechunk) throws IOException { boolean any_valid = false; + + extension = "eeprom"; + set_serial(flights.config_data.serial); for (int i = 0; i < eechunk.chunk_size && !done; i += AltosEepromRecord.record_length) { try { AltosEepromRecord r = new AltosEepromRecord(eechunk, i); - if (r.cmd == Altos.AO_LOG_FLIGHT) { - flight = r.b; - monitor.set_flight(flight); - } + if (r.cmd == Altos.AO_LOG_FLIGHT) + set_flight(r.b); /* Monitor state transitions to update display */ if (r.cmd == Altos.AO_LOG_STATE && r.a <= Altos.ao_flight_landed) { @@ -137,6 +153,8 @@ public class AltosEepromDownload implements Runnable { void CaptureTiny (AltosEepromChunk eechunk) throws IOException { boolean any_valid = false; + extension = "eeprom"; + set_serial(flights.config_data.serial); for (int i = 0; i < eechunk.data.length && !done; i += 2) { int v = eechunk.data16(i); AltosEepromRecord r; @@ -144,8 +162,7 @@ public class AltosEepromDownload implements Runnable { if (i == 0 && start) { tiny_tick = 0; start = false; - flight = v; - monitor.set_flight(flight); + set_flight(v); r = new AltosEepromRecord(Altos.AO_LOG_FLIGHT, tiny_tick, 0, v); any_valid = true; } else { @@ -181,6 +198,56 @@ public class AltosEepromDownload implements Runnable { done = true; } + void LogTeleScience(AltosEepromTeleScience r) throws IOException { + if (r.type != Altos.AO_LOG_INVALID) { + String log_line = String.format("%c %4x %4x %d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", + r.type, r.tick, r.tm_tick, r.tm_state, + r.data[0], r.data[1], r.data[2], r.data[3], + r.data[4], r.data[5], r.data[6], r.data[7], + r.data[8], r.data[9], r.data[10], r.data[11]); + if (eeprom_file != null) + eeprom_file.write(log_line); + else + eeprom_pending.add(log_line); + } + } + + boolean telescience_start; + + void CaptureTeleScience (AltosEepromChunk eechunk) throws IOException { + boolean any_valid = false; + + extension = "science"; + for (int i = 0; i < eechunk.chunk_size && !done; i += AltosEepromTeleScience.record_length) { + try { + AltosEepromTeleScience r = new AltosEepromTeleScience(eechunk, i); + if (r.type == AltosEepromTeleScience.AO_LOG_TELESCIENCE_START) { + if (telescience_start) { + done = true; + break; + } + set_serial(r.data[0]); + set_flight(r.data[1]); + telescience_start = true; + } else { + if (!telescience_start) + break; + } + state = r.tm_state; + want_file =true; + any_valid = true; + LogTeleScience(r); + } catch (ParseException pe) { + if (parse_exception == null) + parse_exception = pe; + } + } + + CheckFile(false); + if (!any_valid) + done = true; + } + void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException { int block, state_block = 0; int log_format = flights.config_data.log_format; @@ -202,7 +269,6 @@ public class AltosEepromDownload implements Runnable { eeprom_pending = new LinkedList(); /* Set serial number in the monitor dialog window */ - monitor.set_serial(flights.config_data.serial); /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */ state = 0; state_block = log.start_block; @@ -227,11 +293,21 @@ public class AltosEepromDownload implements Runnable { switch (log_format) { case Altos.AO_LOG_FORMAT_FULL: + extension = "eeprom"; CaptureFull(eechunk); break; case Altos.AO_LOG_FORMAT_TINY: + extension = "eeprom"; CaptureTiny(eechunk); break; +// case Altos.AO_LOG_FORMAT_TELEMETRY: +// extension = "telem"; +// CaptureTelemetry(eechunk); +// break; + case Altos.AO_LOG_FORMAT_TELESCIENCE: + extension = "science"; + CaptureTeleScience(eechunk); + break; } } CheckFile(true); @@ -290,6 +366,7 @@ public class AltosEepromDownload implements Runnable { serial_line.device.toShortString(), JOptionPane.ERROR_MESSAGE); } catch (InterruptedException ie) { + System.out.printf("download interrupted\n"); } catch (TimeoutException te) { show_message(String.format("Connection to \"%s\" failed", serial_line.device.toShortString()), diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index 185fec91..da4b1166 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -67,7 +67,7 @@ public class AltosEepromList extends ArrayList { ArrayList flights = new ArrayList(); - if (config_data.flight_log_max != 0) { + if (config_data.flight_log_max != 0 || config_data.log_format != 0) { /* Devices with newer firmware will support the 'l' * command which will list the region of storage @@ -113,7 +113,7 @@ public class AltosEepromList extends ArrayList { * firmware, this will also extract the flight number. */ for (AltosEepromFlight flight : flights) { - add(new AltosEepromLog(serial_line, config_data.serial, + add(new AltosEepromLog(config_data, serial_line, flight.flight, flight.start, flight.end)); } } finally { diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index 0cf420d9..be2549cb 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -46,7 +46,8 @@ public class AltosEepromLog { boolean download; boolean delete; - public AltosEepromLog(AltosSerial serial_line, int in_serial, + public AltosEepromLog(AltosConfigData config_data, + AltosSerial serial_line, int in_flight, int in_start_block, int in_end_block) throws InterruptedException, TimeoutException { @@ -54,51 +55,55 @@ public class AltosEepromLog { int block; boolean has_date = false; + flight = in_flight; + if (flight != 0) + has_flight = true; start_block = in_start_block; end_block = in_end_block; - serial = in_serial; + serial = config_data.serial; /* * By default, request that every log be downloaded but not deleted */ download = true; delete = false; + /* - * Only look in the first two blocks so that this - * process doesn't take a long time + * Look in TeleMetrum log data for date */ - if (in_end_block > in_start_block + 2) - in_end_block = in_start_block + 2; + if (config_data.log_format == Altos.AO_LOG_FORMAT_UNKNOWN || + config_data.log_format == Altos.AO_LOG_FORMAT_FULL) + { + /* + * Only look in the first two blocks so that this + * process doesn't take a long time + */ + if (in_end_block > in_start_block + 2) + in_end_block = in_start_block + 2; - for (block = in_start_block; block < in_end_block; block++) { - AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block); + for (block = in_start_block; block < in_end_block; block++) { + AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block); - if (block == in_start_block) { - if (eechunk.data16(0) == in_flight) { - flight = in_flight; - has_flight = true; - break; - } - } - for (int i = 0; i < eechunk.chunk_size; i += AltosEepromRecord.record_length) { - try { - AltosEepromRecord r = new AltosEepromRecord(eechunk, i); + for (int i = 0; i < eechunk.chunk_size; i += AltosEepromRecord.record_length) { + try { + AltosEepromRecord r = new AltosEepromRecord(eechunk, i); - if (r.cmd == Altos.AO_LOG_FLIGHT) { - flight = r.b; - has_flight = true; - } - if (r.cmd == Altos.AO_LOG_GPS_DATE) { - year = 2000 + (r.a & 0xff); - month = (r.a >> 8) & 0xff; - day = (r.b & 0xff); - has_date = true; + if (r.cmd == Altos.AO_LOG_FLIGHT) { + flight = r.b; + has_flight = true; + } + if (r.cmd == Altos.AO_LOG_GPS_DATE) { + year = 2000 + (r.a & 0xff); + month = (r.a >> 8) & 0xff; + day = (r.b & 0xff); + has_date = true; + } + } catch (ParseException pe) { } - } catch (ParseException pe) { } + if (has_date && has_flight) + break; } - if (has_date && has_flight) - break; } } } diff --git a/altosui/AltosEepromTeleScience.java b/altosui/AltosEepromTeleScience.java new file mode 100644 index 00000000..ee1840b0 --- /dev/null +++ b/altosui/AltosEepromTeleScience.java @@ -0,0 +1,64 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosEepromTeleScience { + int type; + int tick; + int tm_state; + int tm_tick; + int[] data; + boolean valid; + + static final int AO_LOG_TELESCIENCE_START = 's'; + static final int AO_LOG_TELESCIENCE_DATA = 'd'; + + static final int max_data = 12; + static final int record_length = 32; + + public AltosEepromTeleScience (AltosEepromChunk chunk, int start) throws ParseException { + type = chunk.data(start); + + valid = !chunk.erased(start, record_length); + if (valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + type = Altos.AO_LOG_INVALID; + } + + tick = chunk.data16(start+2); + tm_tick = chunk.data16(start+4); + tm_state = chunk.data(start+6); + data = new int[max_data]; + for (int i = 0; i < max_data; i++) + data[i] = chunk.data16(start + 8 + i * 2); + } +} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 83510352..e4986ba5 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -45,6 +45,7 @@ altosui_JAVA = \ AltosEepromMonitor.java \ AltosEepromIterable.java \ AltosEepromRecord.java \ + AltosEepromTeleScience.java \ AltosEepromSelect.java \ AltosFile.java \ AltosFlash.java \ -- cgit v1.2.3 From 3ba7b6196f68078f4ed4538c4e7fe30699dfe908 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 21:05:46 -0700 Subject: altosui: Devices with log-format can also delete flights Any device with either flight-log-max or log-format can delete flights. Signed-off-by: Keith Packard --- altosui/AltosEepromDelete.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index 94951ced..cd9abfab 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -42,7 +42,7 @@ public class AltosEepromDelete implements Runnable { private void DeleteLog (AltosEepromLog log) throws IOException, InterruptedException, TimeoutException { - if (flights.config_data.flight_log_max != 0) { + if (flights.config_data.flight_log_max != 0 || flights.config_data.log_format != 0) { /* Devices with newer firmware can erase the * flash blocks containing each flight -- cgit v1.2.3 From dcd15032eec45f3fdd003050710ebd5b85052662 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 21:09:19 -0700 Subject: altosui: Eliminate inter-chunk flush_input calls Once the serial line is nicely synchronized, we don't need to flush input between chunks. This speeds up eeprom downloading quite a bit. Signed-off-by: Keith Packard --- altosui/AltosEepromChunk.java | 5 +++-- altosui/AltosEepromDownload.java | 2 +- altosui/AltosEepromLog.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromChunk.java b/altosui/AltosEepromChunk.java index fb632a3f..59767c2a 100644 --- a/altosui/AltosEepromChunk.java +++ b/altosui/AltosEepromChunk.java @@ -59,14 +59,15 @@ public class AltosEepromChunk { return true; } - public AltosEepromChunk(AltosSerial serial_line, int block) + public AltosEepromChunk(AltosSerial serial_line, int block, boolean flush) throws TimeoutException, InterruptedException { int offset; data = new int[chunk_size]; address = block * chunk_size; - serial_line.flush_input(); + if (flush) + serial_line.flush_input(); serial_line.printf("e %x\n", block); for (offset = 0; offset < chunk_size; offset += per_line) { diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 6112a3b1..b44a1451 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -275,7 +275,7 @@ public class AltosEepromDownload implements Runnable { for (block = log.start_block; !done && block < log.end_block; block++) { monitor.set_value(Altos.state_to_string[state], state, block - state_block); - AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block); + AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block, block == log.start_block); /* * Guess what kind of data is there if the device diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index be2549cb..ee77e5c8 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -82,7 +82,7 @@ public class AltosEepromLog { in_end_block = in_start_block + 2; for (block = in_start_block; block < in_end_block; block++) { - AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block); + AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block, block == in_start_block); for (int i = 0; i < eechunk.chunk_size; i += AltosEepromRecord.record_length) { try { -- cgit v1.2.3 From 924d56a4d2d8b16530cd378b18cfc5d6e08420ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 21:10:15 -0700 Subject: altos: AltosSerial.flush_input shouldn't discard Interrupted exceptions The eeprom download code wants to interrupt serial communication so that it can stop downloading stuff in the middle of a run. Make flush_input pass the exception along instead of discarding it. Signed-off-by: Keith Packard --- altosui/AltosDebug.java | 5 ++++- altosui/AltosEepromDelete.java | 12 ++++++++---- altosui/AltosEepromDownload.java | 8 ++++++-- altosui/AltosEepromManage.java | 5 ++++- altosui/AltosSerial.java | 17 +++++++++-------- 5 files changed, 31 insertions(+), 16 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosDebug.java b/altosui/AltosDebug.java index 8d435b66..d18de80d 100644 --- a/altosui/AltosDebug.java +++ b/altosui/AltosDebug.java @@ -62,7 +62,10 @@ public class AltosDebug extends AltosSerial { void ensure_debug_mode() { if (!debug_mode) { printf("D\n"); - flush_input(); + try { + flush_input(); + } catch (InterruptedException ie) { + } debug_mode = true; } } diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index cd9abfab..a9d77788 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -104,10 +104,14 @@ public class AltosEepromDelete implements Runnable { serial_line.device.toShortString()), "Connection Failed"); } finally { - if (remote) - serial_line.stop_remote(); - serial_line.flush_output(); - serial_line.close(); + try { + if (remote) + serial_line.stop_remote(); + } catch (InterruptedException ie) { + } finally { + serial_line.flush_output(); + serial_line.close(); + } } if (listener != null) { Runnable r = new Runnable() { diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index b44a1451..358ad337 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -373,8 +373,12 @@ public class AltosEepromDownload implements Runnable { "Connection Failed", JOptionPane.ERROR_MESSAGE); } finally { - if (remote) - serial_line.stop_remote(); + if (remote) { + try { + serial_line.stop_remote(); + } catch (InterruptedException ie) { + } + } serial_line.flush_output(); } monitor.done(); diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index 0652ca04..2e520628 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -44,7 +44,10 @@ public class AltosEepromManage implements ActionListener { public void finish() { if (serial_line != null) { - serial_line.flush_input(); + try { + serial_line.flush_input(); + } catch (InterruptedException ie) { + } serial_line.close(); serial_line = null; } diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index b089c9c4..f0e25fa5 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -187,7 +187,7 @@ public class AltosSerial implements Runnable { return abort; } - public void flush_input() { + public void flush_input() throws InterruptedException { flush_output(); boolean got_some; @@ -195,10 +195,7 @@ public class AltosSerial implements Runnable { if (remote) timeout = 500; do { - try { - Thread.sleep(timeout); - } catch (InterruptedException ie) { - } + Thread.sleep(timeout); got_some = !reply_queue.isEmpty(); synchronized(this) { if (!"VERSION".startsWith(line) && @@ -271,8 +268,12 @@ public class AltosSerial implements Runnable { } public void close() { - if (remote) - stop_remote(); + if (remote) { + try { + stop_remote(); + } catch (InterruptedException ie) { + } + } if (in_reply != 0) System.out.printf("Uh-oh. Closing active serial device\n"); @@ -422,7 +423,7 @@ public class AltosSerial implements Runnable { remote = true; } - public void stop_remote() { + public void stop_remote() throws InterruptedException { if (debug) System.out.printf("stop remote\n"); try { -- cgit v1.2.3 From 746d6a472a20243a8c0eacc8edf8e81e0641bc17 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 14 Aug 2011 00:00:07 -0700 Subject: altosui: don't set channel when using radio setting altos now sets the radio back to channel 0 when the radio setting is changed. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index f0e25fa5..0a531aa9 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -353,10 +353,10 @@ public class AltosSerial implements Runnable { private void set_radio_setting(int setting) { if (altos != null) { if (monitor_mode) - printf("m 0\nc R %d\nc r 0\nm %x\n", + printf("m 0\nc R %d\nm %x\n", setting, telemetry_len()); else - printf("c R %d\nc r 0\n", setting); + printf("c R %d\n", setting); flush_output(); } } @@ -364,6 +364,8 @@ public class AltosSerial implements Runnable { public void set_radio_frequency(double frequency, boolean has_setting, int cal) { + if (debug) + System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); if (has_setting) set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); else @@ -413,7 +415,7 @@ public class AltosSerial implements Runnable { public void start_remote() throws TimeoutException, InterruptedException { if (debug) - System.out.printf("start remote\n"); + System.out.printf("start remote %7.3f\n", frequency); if (frequency == 0.0) frequency = AltosPreferences.frequency(device.getSerial()); set_radio_frequency(frequency); -- cgit v1.2.3 From ef7f60df841f1eb22b9cec0d7f68cf2c003d6b30 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 14 Aug 2011 00:00:54 -0700 Subject: altosui: Respect storage limits in flight log max config Compute the maximum flight log using the data returned from the 'f' command (total storage and erase block size). Limit menu to choices which fall within this limit, complain if the user asks for too big a value. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 40 ++++++++++++++++++++++++++++++++++------ altosui/AltosConfigData.java | 8 ++++++-- altosui/AltosConfigUI.java | 22 ++++++++++++++++++++-- 3 files changed, 60 insertions(+), 10 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index ffabe209..9a44c1c5 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -76,6 +76,8 @@ public class AltosConfig implements ActionListener { int_ref ignite_mode; int_ref pad_orientation; int_ref radio_setting; + int_ref storage_size; + int_ref storage_erase_unit; string_ref version; string_ref product; string_ref callsign; @@ -127,6 +129,15 @@ public class AltosConfig implements ActionListener { serial_line.stop_remote(); } + int log_limit() { + if (storage_size.get() > 0 && storage_erase_unit.get() > 0) { + int log_limit = storage_size.get() - storage_erase_unit.get(); + if (log_limit > 0) + return log_limit / 1024; + } + return 1024; + } + void update_ui() { config_ui.set_serial(serial.get()); config_ui.set_product(product.get()); @@ -135,6 +146,7 @@ public class AltosConfig implements ActionListener { config_ui.set_apogee_delay(apogee_delay.get()); config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_radio_frequency(frequency()); + config_ui.set_flight_log_max_limit(log_limit()); config_ui.set_flight_log_max(flight_log_max.get()); config_ui.set_ignite_mode(ignite_mode.get()); config_ui.set_pad_orientation(pad_orientation.get()); @@ -163,6 +175,8 @@ public class AltosConfig implements ActionListener { get_int(line, "Ignite mode:", ignite_mode); get_int(line, "Pad orientation:", pad_orientation); get_int(line, "Radio setting:", radio_setting); + get_int(line, "Storage size:", storage_size); + get_int(line, "Storage erase unit:", storage_erase_unit); get_string(line, "Callsign:", callsign); get_string(line,"software-version", version); get_string(line,"product", product); @@ -192,7 +206,7 @@ public class AltosConfig implements ActionListener { void get_data() { try { config.start_serial(); - config.serial_line.printf("c s\nv\n"); + config.serial_line.printf("c s\nf\nv\n"); for (;;) { try { String line = config.serial_line.get_reply(5000); @@ -230,9 +244,7 @@ public class AltosConfig implements ActionListener { radio_calibration.get()); if (remote) { serial_line.stop_remote(); - serial_line.set_radio_frequency(frequency, - has_setting, - radio_calibration.get()); + serial_line.set_radio_frequency(frequency); AltosPreferences.set_frequency(device.getSerial(), frequency); serial_line.start_remote(); } @@ -340,13 +352,27 @@ public class AltosConfig implements ActionListener { } void save_data() { + + /* bounds check stuff */ + if (config_ui.flight_log_max() > log_limit()) { + JOptionPane.showMessageDialog(owner, + String.format("Requested flight log, %dk, is larger than the available space, %dk.\n", + config_ui.flight_log_max(), + log_limit()), + "Maximum Flight Log Too Large", + JOptionPane.ERROR_MESSAGE); + return; + } + main_deploy.set(config_ui.main_deploy()); apogee_delay.set(config_ui.apogee_delay()); radio_calibration.set(config_ui.radio_calibration()); set_frequency(config_ui.radio_frequency()); flight_log_max.set(config_ui.flight_log_max()); - ignite_mode.set(config_ui.ignite_mode()); - pad_orientation.set(config_ui.pad_orientation()); + if (ignite_mode.get() >= 0) + ignite_mode.set(config_ui.ignite_mode()); + if (pad_orientation.get() >= 0) + pad_orientation.set(config_ui.pad_orientation()); callsign.set(config_ui.callsign()); run_serial_thread(serial_mode_save); } @@ -385,6 +411,8 @@ public class AltosConfig implements ActionListener { flight_log_max = new int_ref(0); ignite_mode = new int_ref(-1); pad_orientation = new int_ref(-1); + storage_size = new int_ref(-1); + storage_erase_unit = new int_ref(-1); callsign = new string_ref("N0CALL"); version = new string_ref("unknown"); product = new string_ref("unknown"); diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 710231d7..272dd402 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -54,7 +54,8 @@ public class AltosConfigData implements Iterable { int radio_calibration; int flight_log_max; int ignite_mode; - + int storage_size; + int storage_erase_unit; static String get_string(String line, String label) throws ParseException { if (line.startsWith(label)) { @@ -84,7 +85,7 @@ public class AltosConfigData implements Iterable { } public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { - serial_line.printf("c s\nv\n"); + serial_line.printf("c s\nf\nv\n"); lines = new LinkedList(); radio_setting = 0; for (;;) { @@ -116,6 +117,9 @@ public class AltosConfigData implements Iterable { try { version = get_string(line,"software-version"); } catch (Exception e) {} try { product = get_string(line,"product"); } catch (Exception e) {} + try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} + try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} + /* signals the end of the version info */ if (line.startsWith("software-version")) break; diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 71664c91..63e0ba78 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -577,6 +577,18 @@ public class AltosConfigUI return Integer.parseInt(flight_log_max_value.getSelectedItem().toString()); } + public void set_flight_log_max_limit(int flight_log_max_limit) { + boolean any_added = false; + flight_log_max_value.removeAllItems(); + for (int i = 0; i < flight_log_max_values.length; i++) { + if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){ + flight_log_max_value.addItem(flight_log_max_values[i]); + any_added = true; + } + } + flight_log_max_value.addItem(String.format("%d", flight_log_max_limit)); + } + public void set_ignite_mode(int new_ignite_mode) { if (new_ignite_mode < 0) { ignite_mode_value.setEnabled(false); @@ -588,7 +600,10 @@ public class AltosConfigUI } public int ignite_mode() { - return ignite_mode_value.getSelectedIndex(); + if (ignite_mode_value.isEnabled()) + return ignite_mode_value.getSelectedIndex(); + else + return -1; } @@ -603,7 +618,10 @@ public class AltosConfigUI } public int pad_orientation() { - return pad_orientation_value.getSelectedIndex(); + if (pad_orientation_value.isEnabled()) + return pad_orientation_value.getSelectedIndex(); + else + return -1; } public void set_clean() { -- cgit v1.2.3 From adb7d345963ab9981c49c7cc68c6b4d7156dce46 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 14 Aug 2011 21:09:42 -0700 Subject: altosui: Ancient log files used 'apogee' for 'coast' state 2009-07-18-serial-004-flight-000 says 'apogee' for the apogee-detect phase of the flight; map this to coast so that this flight replays correctly (although the log terminates at apogee...) Signed-off-by: Keith Packard --- altosui/Altos.java | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 416d9328..d3f8fa67 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -112,6 +112,7 @@ public class Altos { string_to_state.put("fast", ao_flight_fast); string_to_state.put("coast", ao_flight_coast); string_to_state.put("drogue", ao_flight_drogue); + string_to_state.put("apogee", ao_flight_coast); string_to_state.put("main", ao_flight_main); string_to_state.put("landed", ao_flight_landed); string_to_state.put("invalid", ao_flight_invalid); -- cgit v1.2.3 From 048b3eb45169e572f33c68ff152b89db9ef97d31 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 14 Aug 2011 21:11:41 -0700 Subject: altosui: Add 'On-board Data Logging' indicator to pad tab This shows whether the on-board data memory is full, or is ready to record the flight. This is indicated in the telemetry stream by a flight number of '0'. Signed-off-by: Keith Packard --- altosui/AltosPad.java | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index d08925be..2ed1ab2c 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -173,6 +173,29 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { Main main; + class LoggingReady extends LaunchStatus { + void show (AltosState state, int crc_errors) { + show(); + System.out.printf("flight %d state %d\n", state.data.flight, state.data.state); + if (state.data.flight != 0) { + if (state.data.state <= Altos.ao_flight_pad) + value.setText("Ready to record"); + else if (state.data.state < Altos.ao_flight_landed) + value.setText("Recording data"); + else + value.setText("Recorded data"); + } + else + value.setText("Storage full"); + lights.set(state.data.flight != 0); + } + public LoggingReady (GridBagLayout layout, int y) { + super(layout, y, "On-board Data Logging"); + } + } + + LoggingReady logging_ready; + class GPSLocked extends LaunchStatus { void show (AltosState state, int crc_errors) { show(); @@ -252,6 +275,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { battery.reset(); apogee.reset(); main.reset(); + logging_ready.reset(); gps_locked.reset(); gps_ready.reset(); pad_lat.reset(); @@ -269,6 +293,7 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { main.hide(); else main.show(state, crc_errors); + logging_ready.show(state, crc_errors); pad_alt.show(state, crc_errors); if (state.gps != null && state.gps.connected) { gps_locked.show(state, crc_errors); @@ -301,10 +326,11 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { battery = new Battery(layout, 0); apogee = new Apogee(layout, 1); main = new Main(layout, 2); - gps_locked = new GPSLocked(layout, 3); - gps_ready = new GPSReady(layout, 4); - pad_lat = new PadLat(layout, 5); - pad_lon = new PadLon(layout, 6); - pad_alt = new PadAlt(layout, 7); + logging_ready = new LoggingReady(layout, 3); + gps_locked = new GPSLocked(layout, 4); + gps_ready = new GPSReady(layout, 5); + pad_lat = new PadLat(layout, 6); + pad_lon = new PadLon(layout, 7); + pad_alt = new PadAlt(layout, 8); } } -- cgit v1.2.3 From fcff63baf8fde1174571a2c7c860099e19dbf629 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 20 Aug 2011 10:43:28 -0700 Subject: altosui: remove debug printf in pad pane Signed-off-by: Keith Packard --- altosui/AltosPad.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index 2ed1ab2c..3a8d04fe 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -176,7 +176,6 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { class LoggingReady extends LaunchStatus { void show (AltosState state, int crc_errors) { show(); - System.out.printf("flight %d state %d\n", state.data.flight, state.data.state); if (state.data.flight != 0) { if (state.data.state <= Altos.ao_flight_pad) value.setText("Ready to record"); -- cgit v1.2.3 From 67f28c58db0deca8f8050d33e97ad96017f4baaa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 20 Aug 2011 11:19:57 -0700 Subject: altosui: Disable 'max flight log' config when there are stored flights When flights are stored in flash, the maximum flight log value cannot be changed as the flight data might need to be moved around in memory. Check for this case by looking for stored flights and disabling the combo box when storage is not empty. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 7 ++++++- altosui/AltosConfigUI.java | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 9a44c1c5..84c8a4a3 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -78,6 +78,7 @@ public class AltosConfig implements ActionListener { int_ref radio_setting; int_ref storage_size; int_ref storage_erase_unit; + int_ref stored_flight; string_ref version; string_ref product; string_ref callsign; @@ -146,6 +147,7 @@ public class AltosConfig implements ActionListener { config_ui.set_apogee_delay(apogee_delay.get()); config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_radio_frequency(frequency()); + config_ui.set_flight_log_max_enabled(stored_flight.get() < 0); config_ui.set_flight_log_max_limit(log_limit()); config_ui.set_flight_log_max(flight_log_max.get()); config_ui.set_ignite_mode(ignite_mode.get()); @@ -177,6 +179,7 @@ public class AltosConfig implements ActionListener { get_int(line, "Radio setting:", radio_setting); get_int(line, "Storage size:", storage_size); get_int(line, "Storage erase unit:", storage_erase_unit); + get_int(line, "flight", stored_flight); get_string(line, "Callsign:", callsign); get_string(line,"software-version", version); get_string(line,"product", product); @@ -206,7 +209,8 @@ public class AltosConfig implements ActionListener { void get_data() { try { config.start_serial(); - config.serial_line.printf("c s\nf\nv\n"); + stored_flight.set(-1); + config.serial_line.printf("c s\nf\nl\nv\n"); for (;;) { try { String line = config.serial_line.get_reply(5000); @@ -413,6 +417,7 @@ public class AltosConfig implements ActionListener { pad_orientation = new int_ref(-1); storage_size = new int_ref(-1); storage_erase_unit = new int_ref(-1); + stored_flight = new int_ref(-1); callsign = new string_ref("N0CALL"); version = new string_ref("unknown"); product = new string_ref("unknown"); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 63e0ba78..69afd691 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -573,6 +573,10 @@ public class AltosConfigUI flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max)); } + public void set_flight_log_max_enabled(boolean enable) { + flight_log_max_value.setEnabled(enable); + } + public int flight_log_max() { return Integer.parseInt(flight_log_max_value.getSelectedItem().toString()); } -- cgit v1.2.3 From 6823ad5e48fc0a19791d96f886b5689f88c4311b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 18 Aug 2011 18:02:02 -0700 Subject: altos/altosui: Add ability to disable telemetry/rdf completely This turns off the telemetry system so that it never transmits telemetry or RDF tones. In idle mode, it will still accept packet mode connections. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 8 ++++++ altosui/AltosConfigUI.java | 65 +++++++++++++++++++++++++++++++++++++--------- src/ao.h | 3 ++- src/ao_config.c | 25 ++++++++++++++++-- src/ao_telemetry.c | 2 ++ 5 files changed, 88 insertions(+), 15 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 84c8a4a3..b1e6bc12 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -79,6 +79,7 @@ public class AltosConfig implements ActionListener { int_ref storage_size; int_ref storage_erase_unit; int_ref stored_flight; + int_ref radio_enable; string_ref version; string_ref product; string_ref callsign; @@ -148,6 +149,7 @@ public class AltosConfig implements ActionListener { config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_radio_frequency(frequency()); config_ui.set_flight_log_max_enabled(stored_flight.get() < 0); + config_ui.set_radio_enable(radio_enable.get()); config_ui.set_flight_log_max_limit(log_limit()); config_ui.set_flight_log_max(flight_log_max.get()); config_ui.set_ignite_mode(ignite_mode.get()); @@ -177,6 +179,7 @@ public class AltosConfig implements ActionListener { get_int(line, "Ignite mode:", ignite_mode); get_int(line, "Pad orientation:", pad_orientation); get_int(line, "Radio setting:", radio_setting); + get_int(line, "Radio enable:", radio_enable); get_int(line, "Storage size:", storage_size); get_int(line, "Storage erase unit:", storage_erase_unit); get_int(line, "flight", stored_flight); @@ -255,6 +258,8 @@ public class AltosConfig implements ActionListener { serial_line.printf("c c %s\n", callsign.get()); if (flight_log_max.get() != 0) serial_line.printf("c l %d\n", flight_log_max.get()); + if (radio_enable.get() >= 0) + serial_line.printf("c e %d\n", radio_enable.get()); if (ignite_mode.get() >= 0) serial_line.printf("c i %d\n", ignite_mode.get()); if (pad_orientation.get() >= 0) @@ -373,6 +378,8 @@ public class AltosConfig implements ActionListener { radio_calibration.set(config_ui.radio_calibration()); set_frequency(config_ui.radio_frequency()); flight_log_max.set(config_ui.flight_log_max()); + if (radio_enable.get() >= 0) + radio_enable.set(config_ui.radio_enable()); if (ignite_mode.get() >= 0) ignite_mode.set(config_ui.ignite_mode()); if (pad_orientation.get() >= 0) @@ -412,6 +419,7 @@ public class AltosConfig implements ActionListener { radio_channel = new int_ref(0); radio_setting = new int_ref(0); radio_calibration = new int_ref(1186611); + radio_enable = new int_ref(-1); flight_log_max = new int_ref(0); ignite_mode = new int_ref(-1); pad_orientation = new int_ref(-1); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 69afd691..bb9e1cd2 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -46,6 +46,7 @@ public class AltosConfigUI JLabel frequency_label; JLabel radio_calibration_label; JLabel radio_frequency_label; + JLabel radio_enable_label; JLabel flight_log_max_label; JLabel ignite_mode_label; JLabel pad_orientation_label; @@ -61,6 +62,7 @@ public class AltosConfigUI JComboBox apogee_delay_value; AltosFreqList radio_frequency_value; JTextField radio_calibration_value; + JRadioButton radio_enable_value; JComboBox flight_log_max_value; JComboBox ignite_mode_value; JComboBox pad_orientation_value; @@ -287,7 +289,7 @@ public class AltosConfigUI radio_calibration_value.setEnabled(false); pane.add(radio_calibration_value, c); - /* Callsign */ + /* Radio Enable */ c = new GridBagConstraints(); c.gridx = 0; c.gridy = 7; c.gridwidth = 4; @@ -295,11 +297,34 @@ public class AltosConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = il; c.ipady = 5; + radio_enable_label = new JLabel("Telemetry/RDF Enable:"); + pane.add(radio_enable_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 7; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + radio_enable_value = new JRadioButton("Enabled"); + radio_enable_value.addItemListener(this); + pane.add(radio_enable_value, c); + + /* Callsign */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 8; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; callsign_label = new JLabel("Callsign:"); pane.add(callsign_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 7; + c.gridx = 4; c.gridy = 8; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -312,7 +337,7 @@ public class AltosConfigUI /* Flight log max */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 8; + c.gridx = 0; c.gridy = 9; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -322,7 +347,7 @@ public class AltosConfigUI pane.add(flight_log_max_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 8; + c.gridx = 4; c.gridy = 9; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -336,7 +361,7 @@ public class AltosConfigUI /* Ignite mode */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 9; + c.gridx = 0; c.gridy = 10; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -346,7 +371,7 @@ public class AltosConfigUI pane.add(ignite_mode_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 9; + c.gridx = 4; c.gridy = 10; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -360,7 +385,7 @@ public class AltosConfigUI /* Pad orientation */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 10; + c.gridx = 0; c.gridy = 11; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -370,7 +395,7 @@ public class AltosConfigUI pane.add(pad_orientation_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 10; + c.gridx = 4; c.gridy = 11; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -384,7 +409,7 @@ public class AltosConfigUI /* Buttons */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 11; + c.gridx = 0; c.gridy = 12; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -395,7 +420,7 @@ public class AltosConfigUI save.setActionCommand("Save"); c = new GridBagConstraints(); - c.gridx = 2; c.gridy = 11; + c.gridx = 2; c.gridy = 12; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -406,7 +431,7 @@ public class AltosConfigUI reset.setActionCommand("Reset"); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 11; + c.gridx = 4; c.gridy = 12; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -417,7 +442,7 @@ public class AltosConfigUI reboot.setActionCommand("Reboot"); c = new GridBagConstraints(); - c.gridx = 6; c.gridy = 11; + c.gridx = 6; c.gridy = 12; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_END; @@ -559,6 +584,22 @@ public class AltosConfigUI return Integer.parseInt(radio_calibration_value.getText()); } + public void set_radio_enable(int new_radio_enable) { + if (new_radio_enable >= 0) + radio_enable_value.setSelected(new_radio_enable > 0); + else { + radio_enable_value.setSelected(true); + radio_enable_value.setEnabled(false); + } + } + + public int radio_enable() { + if (radio_enable_value.isEnabled()) + return radio_enable_value.isSelected() ? 1 : 0; + else + return -1; + } + public void set_callsign(String new_callsign) { callsign_value.setText(new_callsign); } diff --git a/src/ao.h b/src/ao.h index 79452862..8ac9ac3d 100644 --- a/src/ao.h +++ b/src/ao.h @@ -1415,7 +1415,7 @@ ao_igniter_init(void); */ #define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 7 +#define AO_CONFIG_MINOR 8 struct ao_config { uint8_t major; @@ -1431,6 +1431,7 @@ struct ao_config { uint8_t ignite_mode; /* minor version 5 */ uint8_t pad_orientation; /* minor version 6 */ uint32_t radio_setting; /* minor version 7 */ + uint8_t radio_enable; /* minor version 8 */ }; #define AO_IGNITE_MODE_DUAL 0 diff --git a/src/ao_config.c b/src/ao_config.c index e0eae78e..eb1eea3f 100644 --- a/src/ao_config.c +++ b/src/ao_config.c @@ -99,6 +99,8 @@ _ao_config_get(void) ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION; if (ao_config.minor < 7) ao_config.radio_setting = ao_config.radio_cal; + if (ao_config.minor < 8) + ao_config.radio_enable = TRUE; ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; } @@ -392,6 +394,23 @@ ao_config_radio_setting_set(void) __reentrant ao_radio_recv_abort(); } +void +ao_config_radio_enable_show(void) __reentrant +{ + printf("Radio enable: %d\n", ao_config.radio_enable); +} + +void +ao_config_radio_enable_set(void) __reentrant +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.radio_enable = ao_cmd_lex_i; + _ao_config_edit_finish(); +} + struct ao_config_var { __code char *str; void (*set)(void) __reentrant; @@ -418,6 +437,10 @@ __code struct ao_config_var ao_config_vars[] = { ao_config_radio_channel_set, ao_config_radio_channel_show }, { "c \0Callsign (8 char max)", ao_config_callsign_set, ao_config_callsign_show }, + { "R \0Radio freq control (freq = 434.550 * setting/cal)", + ao_config_radio_setting_set, ao_config_radio_setting_show }, + { "e <0 disable, 1 enable>\0Enable telemetry and RDF", + ao_config_radio_enable_set, ao_config_radio_enable_show }, #if HAS_ACCEL { "a <+g> <-g>\0Accel calib (0 for auto)", ao_config_accel_calibrate_set,ao_config_accel_calibrate_show }, @@ -436,8 +459,6 @@ __code struct ao_config_var ao_config_vars[] = { { "o <0 antenna up, 1 antenna down>\0Set pad orientation", ao_config_pad_orientation_set,ao_config_pad_orientation_show }, #endif - { "R \0Radio freq control (freq = 434.550 * setting/cal)", - ao_config_radio_setting_set, ao_config_radio_setting_show }, { "s\0Show", ao_config_show, 0 }, #if HAS_EEPROM diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c index 8a18ba07..c7338a58 100644 --- a/src/ao_telemetry.c +++ b/src/ao_telemetry.c @@ -180,6 +180,8 @@ ao_telemetry(void) int16_t delay; ao_config_get(); + if (!ao_config.radio_enable) + ao_exit(); while (!ao_flight_number) ao_sleep(&ao_flight_number); -- cgit v1.2.3 From 55be3db2e31fe97e7f351e3c490b8bc4cf7192b2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 21 Aug 2011 19:18:54 -0700 Subject: altosui: Clean up command line processing. Add --graph Make the command line processing a bit less ad-hoc, track 'mode' of processing and deal with all files on the command line. Signed-off-by: Keith Packard --- altosui/AltosUI.java | 188 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 123 insertions(+), 65 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 62e612ed..b2c5107e 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -364,93 +364,151 @@ public class AltosUI extends JFrame { } } + static final int process_none = 0; static final int process_csv = 1; static final int process_kml = 2; + static final int process_graph = 3; + static final int process_replay = 4; - static void process_file(String input, int process) { + static void process_csv(String input) { AltosRecordIterable iterable = open_logfile(input); if (iterable == null) return; - if (process == 0) - process = process_csv; - if ((process & process_csv) != 0) { - String output = Altos.replace_extension(input,".csv"); - System.out.printf("Processing \"%s\" to \"%s\"\n", input, output); - if (input.equals(output)) { - System.out.printf("Not processing '%s'\n", input); - } else { - AltosWriter writer = open_csv("/dev/stdout"); - if (writer != null) { - writer.write(iterable); - writer.close(); - } - } + + String output = Altos.replace_extension(input,".csv"); + System.out.printf("Processing \"%s\" to \"%s\"\n", input, output); + if (input.equals(output)) { + System.out.printf("Not processing '%s'\n", input); + } else { + AltosWriter writer = open_csv(output); + if (writer == null) + return; + writer.write(iterable); + writer.close(); } - if ((process & process_kml) != 0) { - String output = Altos.replace_extension(input,".kml"); - System.out.printf("Processing \"%s\" to \"%s\"\n", input, output); - if (input.equals(output)) { - System.out.printf("Not processing '%s'\n", input); - } else { - AltosWriter writer = open_kml(output); - if (writer == null) - return; - writer.write(iterable); - writer.close(); - } + } + + static void process_kml(String input) { + AltosRecordIterable iterable = open_logfile(input); + if (iterable == null) + return; + + String output = Altos.replace_extension(input,".kml"); + System.out.printf("Processing \"%s\" to \"%s\"\n", input, output); + if (input.equals(output)) { + System.out.printf("Not processing '%s'\n", input); + } else { + AltosWriter writer = open_kml(output); + if (writer == null) + return; + writer.write(iterable); + writer.close(); } } - public static void main(final String[] args) { - int process = 0; - /* Handle batch-mode */ - if (args.length == 1 && args[0].equals("--help")) { + static void process_replay(String filename) { + FileInputStream in; + try { + in = new FileInputStream(filename); + } catch (Exception e) { + System.out.printf("Failed to open file '%s'\n", filename); + return; + } + AltosRecordIterable recs; + AltosReplayReader reader; + if (filename.endsWith("eeprom")) { + recs = new AltosEepromIterable(in); + } else { + recs = new AltosTelemetryIterable(in); + } + reader = new AltosReplayReader(recs.iterator(), new File(filename)); + AltosFlightUI flight_ui = new AltosFlightUI(new AltosVoice(), reader); + flight_ui.set_exit_on_close(); + } + + static void process_graph(String filename) { + FileInputStream in; + try { + in = new FileInputStream(filename); + } catch (Exception e) { + System.out.printf("Failed to open file '%s'\n", filename); + return; + } + AltosRecordIterable recs; + if (filename.endsWith("eeprom")) { + recs = new AltosEepromIterable(in); + } else { + recs = new AltosTelemetryIterable(in); + } + try { + new AltosGraphUI(recs); + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + } + + public static void help(int code) { System.out.printf("Usage: altosui [OPTION]... [FILE]...\n"); System.out.printf(" Options:\n"); System.out.printf(" --fetchmaps \tpre-fetch maps for site map view\n"); System.out.printf(" --replay \t\trelive the glory of past flights \n"); + System.out.printf(" --graph \t\tgraph a flight\n"); System.out.printf(" --csv\tgenerate comma separated output for spreadsheets, etc\n"); System.out.printf(" --kml\tgenerate KML output for use with Google Earth\n"); - } else if (args.length == 3 && args[0].equals("--fetchmaps")) { - double lat = Double.parseDouble(args[1]); - double lon = Double.parseDouble(args[2]); - AltosSiteMap.prefetchMaps(lat, lon, 5, 5); - } else if (args.length == 2 && args[0].equals("--replay")) { - String filename = args[1]; - FileInputStream in; - try { - in = new FileInputStream(filename); - } catch (Exception e) { - System.out.printf("Failed to open file '%s'\n", filename); - return; - } - AltosRecordIterable recs; - AltosReplayReader reader; - if (filename.endsWith("eeprom")) { - recs = new AltosEepromIterable(in); - } else { - recs = new AltosTelemetryIterable(in); - } - reader = new AltosReplayReader(recs.iterator(), new File(filename)); - AltosFlightUI flight_ui = new AltosFlightUI(new AltosVoice(), reader); - flight_ui.set_exit_on_close(); - return; - } else if (args.length > 0) { - for (int i = 0; i < args.length; i++) { - if (args[i].equals("--kml")) - process |= process_kml; - else if (args[i].equals("--csv")) - process |= process_csv; - else - process_file(args[i], process); - } - } else { + System.exit(code); + } + + public static void main(final String[] args) { + /* Handle batch-mode */ + if (args.length == 0) { AltosUI altosui = new AltosUI(); altosui.setVisible(true); java.util.List devices = AltosUSBDevice.list(Altos.product_basestation); for (AltosDevice device : devices) altosui.telemetry_window(device); + } else { + int process = process_none; + for (int i = 0; i < args.length; i++) { + if (args[i].equals("--help")) + help(0); + else if (args[i].equals("--fetchmaps")) { + if (args.length < i + 3) { + help(1); + } else { + double lat = Double.parseDouble(args[i+1]); + double lon = Double.parseDouble(args[i+2]); + AltosSiteMap.prefetchMaps(lat, lon, 5, 5); + i += 2; + } + } else if (args[i].equals("--replay")) + process = process_replay; + else if (args[i].equals("--kml")) + process = process_kml; + else if (args[i].equals("--csv")) + process = process_csv; + else if (args[i].equals("--graph")) + process = process_graph; + else if (args[i].startsWith("--")) + help(1); + else { + switch (process) { + case process_none: + case process_graph: + process_graph(args[i]); + break; + case process_replay: + process_replay(args[i]); + break; + case process_kml: + process_kml(args[i]); + break; + case process_csv: + process_csv(args[i]); + break; + } + } + } } } } -- cgit v1.2.3 From 2353d83be15b398754c2564f95374c6ea0f8de92 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 21 Aug 2011 22:12:04 -0700 Subject: altos-fat/windows: Check and install Java 1.6 as needed Signed-off-by: Keith Packard --- altosui/altos-windows.nsi | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index 7c9b7a28..70dc03ca 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -1,4 +1,8 @@ !addplugindir Instdrv/NSIS/Plugins +; Definitions for Java 1.6 Detection +!define JRE_VERSION "1.6" +!define JRE_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=18714&/jre-6u5-windows-i586-p.exe" +!define PRODUCT_NAME "Altus Metrum Windows Software" Name "Altus Metrum Installer" @@ -18,6 +22,31 @@ ShowInstDetails Show ComponentText "Altus Metrum Software and Driver Installer" +Function GetJRE + MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION}, 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 + + Call GetJRE + + done: +FunctionEnd + ; Pages to present Page license @@ -51,6 +80,8 @@ Section "Install Driver" InstDriver SectionEnd Section "AltosUI Application" + Call DetectJRE + SetOutPath $INSTDIR File "altosui-fat.jar" @@ -68,7 +99,7 @@ Section "AltosUI Application" File "../icon/*.ico" - CreateShortCut "$SMPROGRAMS\AltusMetrum.lnk" "$INSTDIR\altosui-fat.jar" "" "$INSTDIR\altus-metrum.ico" + CreateShortCut "$SMPROGRAMS\AltusMetrum.lnk" "$SYSDIR\javaw.exe" "-jar altosui-fat.jar" "$INSTDIR\altus-metrum.ico" SectionEnd Section "AltosUI Desktop Shortcut" @@ -99,12 +130,12 @@ 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"' -- cgit v1.2.3 From d5bd40847b17c32405dfba864a2a5a3b19aa7e85 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 21 Aug 2011 22:12:53 -0700 Subject: altosui/windows: Fix a bunch of windows compiler warnings. Some of these may have actually been serious -- a write length was getting stored in a signed char... Signed-off-by: Keith Packard --- altosui/libaltos/libaltos.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'altosui') diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index f2c8bd8d..21e94ca0 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -882,7 +882,7 @@ altos_list_start(void) list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_ALLCLASSES|DIGCF_PRESENT); if (list->dev_info == INVALID_HANDLE_VALUE) { - printf("SetupDiGetClassDevs failed %d\n", GetLastError()); + printf("SetupDiGetClassDevs failed %ld\n", GetLastError()); free(list); return NULL; } @@ -894,13 +894,13 @@ PUBLIC int altos_list_next(struct altos_list *list, struct altos_device *device) { SP_DEVINFO_DATA dev_info_data; - char port[128]; + BYTE port[128]; DWORD port_len; char friendlyname[256]; - char symbolic[256]; + BYTE symbolic[256]; DWORD symbolic_len; HKEY dev_key; - int vid, pid; + unsigned int vid, pid; int serial; HRESULT result; DWORD friendlyname_type; @@ -931,11 +931,11 @@ altos_list_next(struct altos_list *list, struct altos_device *device) continue; } vid = pid = serial = 0; - sscanf(symbolic + sizeof("\\??\\USB#VID_") - 1, + sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1, "%04X", &vid); - sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1, + sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1, "%04X", &pid); - sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1, + sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1, "%d", &serial); if (!USB_IS_ALTUSMETRUM(vid, pid)) { RegCloseKey(dev_key); @@ -971,12 +971,12 @@ altos_list_next(struct altos_list *list, struct altos_device *device) device->serial = serial; strcpy(device->name, friendlyname); - strcpy(device->path, port); + strcpy(device->path, (char *) port); return 1; } result = GetLastError(); if (result != ERROR_NO_MORE_ITEMS) - printf ("SetupDiEnumDeviceInfo failed error %d\n", result); + printf ("SetupDiEnumDeviceInfo failed error %d\n", (int) result); return 0; } @@ -1059,10 +1059,10 @@ altos_fill(struct altos_file *file, int timeout) PUBLIC int altos_flush(struct altos_file *file) { - DWORD put; - char *data = file->out_data; - char used = file->out_used; - DWORD ret; + 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)) { @@ -1150,7 +1150,7 @@ altos_free(struct altos_file *file) free(file); } -int +PUBLIC int altos_putchar(struct altos_file *file, char c) { int ret; @@ -1166,7 +1166,7 @@ altos_putchar(struct altos_file *file, char c) return LIBALTOS_SUCCESS; } -int +PUBLIC int altos_getchar(struct altos_file *file, int timeout) { int ret; -- cgit v1.2.3 From 393d231b9689cd1c358600ee76e0e808f89670c8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 21 Aug 2011 22:52:45 -0700 Subject: altosui: Attempt to make both 32- and 64-bit windows DLLs We'll see if they work... Signed-off-by: Keith Packard --- altosui/Altos.java | 8 +++++++- altosui/Makefile.am | 18 ++++++++++++++++-- altosui/libaltos/Makefile.am | 15 ++++++++++++++- altosui/libaltos/altos.dll | Bin 31765 -> 91605 bytes 4 files changed, 37 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index d3f8fa67..ddf1005a 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -366,7 +366,13 @@ public class Altos { libaltos.altos_init(); loaded_library = true; } catch (UnsatisfiedLinkError e) { - loaded_library = false; + try { + System.loadLibrary("altos64"); + libaltos.altos_init(); + loaded_library = true; + } catch (UnsatisfiedLinkError e2) { + loaded_library = false; + } } initialized = true; } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index e4986ba5..f626d3fa 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -191,7 +191,7 @@ LINUX_EXTRA=altosui-fat MACOSX_FILES=$(FAT_FILES) libaltos.dylib MACOSX_EXTRA=$(FIRMWARE) -WINDOWS_FILES=$(FAT_FILES) altos.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON) +WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON) all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb @@ -282,10 +282,24 @@ libaltos.dylib: -rm -f "$@" $(LN_S) libaltos/"$@" . -altos.dll: +altos.dll: libaltos/altos.dll -rm -f "$@" $(LN_S) libaltos/"$@" . +altos64.dll: libaltos/altos64.dll + -rm -f "$@" + $(LN_S) libaltos/"$@" . + +libaltos/altos.dll: build-altos-dll + +libaltos/altos64.dll: build-altos64-dll + +build-altos-dll: + +cd libaltos && make altos.dll + +build-altos64-dll: + +cd libaltos && make altos64.dll + $(FREETTS_CLASS): -rm -f "$@" $(LN_S) "$(FREETTS)"/"$@" . diff --git a/altosui/libaltos/Makefile.am b/altosui/libaltos/Makefile.am index 3f5f3ee2..b5ab1ddb 100644 --- a/altosui/libaltos/Makefile.am +++ b/altosui/libaltos/Makefile.am @@ -37,5 +37,18 @@ classlibaltos.stamp: $(SWIG_FILE) $(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 + -rm -rf libaltosJNI *.class *.java classlibaltos.stamp $(SWIG_FILE) libaltos_wrap.c altos.dll altos64.dll diff --git a/altosui/libaltos/altos.dll b/altosui/libaltos/altos.dll index 28e9b4ad..a96d3129 100755 Binary files a/altosui/libaltos/altos.dll and b/altosui/libaltos/altos.dll differ -- cgit v1.2.3 From 5ef731bd87c6d2a71a4edcc69a218eaf1aa7c465 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 18:21:35 -0700 Subject: altosui: Add a few simple unit conversions Signed-off-by: Keith Packard --- altosui/AltosConvert.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosConvert.java b/altosui/AltosConvert.java index 207470a5..db7039ec 100644 --- a/altosui/AltosConvert.java +++ b/altosui/AltosConvert.java @@ -234,6 +234,18 @@ public class AltosConvert { return array; } + static double meters_to_feet(double meters) { + return meters * (100 / (2.54 * 12)); + } + + static double meters_to_mach(double meters) { + return meters / 343; /* something close to mach at usual rocket sites */ + } + + static double meters_to_g(double meters) { + return meters / 9.80665; + } + static int checksum(int[] data, int start, int length) { int csum = 0x5a; for (int i = 0; i < length; i++) -- cgit v1.2.3 From b4c71ba56c471720c72853057d0a527825a78fa0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 18:22:21 -0700 Subject: altosui: Capture date/time/serial/flight in AltosFlightStats Time is the time when boost was detected. Signed-off-by: Keith Packard --- altosui/AltosFlightStats.java | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index 19471e9f..2067951e 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -38,6 +38,10 @@ public class AltosFlightStats { int[] state_count = new int[Altos.ao_flight_invalid + 1]; double[] state_start = new double[Altos.ao_flight_invalid + 1]; double[] state_end = new double[Altos.ao_flight_invalid + 1]; + int serial; + int flight; + int year, month, day; + int hour, minute, second; public AltosFlightStats(AltosFlightReader reader) throws InterruptedException, IOException { AltosState state = null; @@ -45,19 +49,37 @@ public class AltosFlightStats { double boost_time = -1; double start_time; + year = month = day = -1; + hour = minute = second = -1; + serial = flight = -1; for (;;) { try { AltosRecord record = reader.read(); if (record == null) break; + if (serial < 0) + serial = record.serial; + if ((record.seen & AltosRecord.seen_flight) != 0 && flight < 0) + flight = record.flight; new_state = new AltosState(record, state); if (state == null) { start_time = new_state.time; } state = new_state; if (0 <= state.state && state.state < Altos.ao_flight_invalid) { - if (boost_time == -1 && state.state >= Altos.ao_flight_boost) - boost_time = state.time; + if (state.state >= Altos.ao_flight_boost) { + if (boost_time == -1) + boost_time = state.time; + if (state.gps != null && state.gps.locked && + year < 0) { + year = state.gps.year; + month = state.gps.month; + day = state.gps.day; + hour = state.gps.hour; + minute = state.gps.minute; + second = state.gps.second; + } + } state_accel[state.state] += state.acceleration; state_speed[state.state] += state.speed; state_baro_speed[state.state] += state.baro_speed; -- cgit v1.2.3 From f4ea46dc205454411c224ada7805f813989efd4a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 18:23:41 -0700 Subject: altosui: Add date/time/serial/flight to flight stats tab And switch to using the AltosConvert units conversions functions. Signed-off-by: Keith Packard --- altosui/AltosFlightStatsTable.java | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index e2c0dd46..3fecf921 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -70,29 +70,37 @@ public class AltosFlightStatsTable extends JComponent { setLayout(layout); int y = 0; + new FlightStat(layout, y++, "Serial", String.format("%d", stats.serial)); + new FlightStat(layout, y++, "Flight", String.format("%d", stats.flight)); + if (stats.year > 0) + new FlightStat(layout, y++, "Date", + String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day)); + if (stats.hour > 0) + new FlightStat(layout, y++, "Time", + String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second)); new FlightStat(layout, y++, "Maximum height", String.format("%5.0f m", stats.max_height), - String.format("%5.0f ft", stats.max_height * 100 / 2.54 / 12)); + String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height))); new FlightStat(layout, y++, "Maximum speed", String.format("%5.0f m/s", stats.max_speed), - String.format("%5.0f ft/s", stats.max_speed * 100 / 2.54 / 12), - String.format("Mach %5.3f", stats.max_speed / 343.0)); + String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.max_speed)), + String.format("Mach %5.3f", AltosConvert.meters_to_mach(stats.max_speed))); if (stats.max_acceleration != AltosRecord.MISSING) { new FlightStat(layout, y++, "Maximum acceleration", String.format("%5.0f m/s²", stats.max_acceleration), - String.format("%5.0f ft/s²", stats.max_acceleration * 100 / 2.54 /12), - String.format("%5.2f G", stats.max_acceleration / 9.80665)); + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), + String.format("%5.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); new FlightStat(layout, y++, "Average boost acceleration", String.format("%5.0f m/s²", stats.state_accel[Altos.ao_flight_boost]), - String.format("%5.0f ft/s²", stats.state_accel[Altos.ao_flight_boost] * 100 / 2.54 /12), - String.format("%5.2f G", stats.state_accel[Altos.ao_flight_boost] / 9.80665)); + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[Altos.ao_flight_boost])), + String.format("%5.2f G", AltosConvert.meters_to_g(stats.state_accel[Altos.ao_flight_boost]))); } new FlightStat(layout, y++, "Drogue descent rate", String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_drogue]), - String.format("%5.0f ft/s", stats.state_baro_speed[Altos.ao_flight_drogue] * 100 / 2.54 / 12)); + String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_drogue]))); new FlightStat(layout, y++, "Main descent rate", String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_main]), - String.format("%5.0f ft/s", stats.state_baro_speed[Altos.ao_flight_main] * 100 / 2.54 / 12)); + String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main]))); for (int s = Altos.ao_flight_boost; s <= Altos.ao_flight_main; s++) { new FlightStat(layout, y++, String.format("%s time", Altos.state_to_string_capital[s]), String.format("%6.2f s", stats.state_end[s] - stats.state_start[s])); -- cgit v1.2.3 From 4e2fd7ae76c23aa8da1390ebcbd8f45276cd7a32 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 18:24:54 -0700 Subject: altosui: Show filename in AltosGraph window Makes it easier to tell multiple windows apart Signed-off-by: Keith Packard --- altosui/AltosGraphUI.java | 4 ++-- altosui/AltosLanded.java | 2 +- altosui/AltosUI.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 16b0fd48..be52bd4e 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -178,8 +178,8 @@ public class AltosGraphUI extends JFrame } } - public AltosGraphUI(AltosRecordIterable records) throws InterruptedException, IOException { - super("Altos Graph"); + public AltosGraphUI(AltosRecordIterable records, String name) throws InterruptedException, IOException { + super(String.format("Altos Graph %s", name)); AltosDataPointReader reader = new AltosDataPointReader (records); if (reader == null) diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 47aca29d..71c10663 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -240,7 +240,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio throw new FileNotFoundException(); } try { - new AltosGraphUI(records); + new AltosGraphUI(records, filename); } catch (InterruptedException ie) { } catch (IOException ie) { } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index b2c5107e..0317f569 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -311,7 +311,7 @@ public class AltosUI extends JFrame { if (record_reader == null) return; try { - new AltosGraphUI(record_reader); + new AltosGraphUI(record_reader, chooser.filename()); } catch (InterruptedException ie) { } catch (IOException ie) { } -- cgit v1.2.3 From afe6aba9cb91e93234ffee2a22eee40f848ddedd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 18:25:34 -0700 Subject: altosui: Add --summary option to dump flight stats to stdout useful for quickly capturing sense of a flight. Signed-off-by: Keith Packard --- altosui/AltosUI.java | 80 ++++++++++++++++++++++++++++++++++++--------- altosui/libaltos/altos.dll | Bin 91605 -> 0 bytes 2 files changed, 64 insertions(+), 16 deletions(-) delete mode 100755 altosui/libaltos/altos.dll (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 0317f569..13cda637 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -369,6 +369,7 @@ public class AltosUI extends JFrame { static final int process_kml = 2; static final int process_graph = 3; static final int process_replay = 4; + static final int process_summary = 5; static void process_csv(String input) { AltosRecordIterable iterable = open_logfile(input); @@ -406,13 +407,13 @@ public class AltosUI extends JFrame { } } - static void process_replay(String filename) { + static AltosRecordIterable record_iterable_file(String filename) { FileInputStream in; try { in = new FileInputStream(filename); } catch (Exception e) { System.out.printf("Failed to open file '%s'\n", filename); - return; + return null; } AltosRecordIterable recs; AltosReplayReader reader; @@ -421,32 +422,74 @@ public class AltosUI extends JFrame { } else { recs = new AltosTelemetryIterable(in); } - reader = new AltosReplayReader(recs.iterator(), new File(filename)); + return recs; + } + + static AltosReplayReader replay_file(String filename) { + AltosRecordIterable recs = record_iterable_file(filename); + if (recs == null) + return null; + return new AltosReplayReader(recs.iterator(), new File(filename)); + } + + static void process_replay(String filename) { + AltosReplayReader reader = replay_file(filename); AltosFlightUI flight_ui = new AltosFlightUI(new AltosVoice(), reader); flight_ui.set_exit_on_close(); } static void process_graph(String filename) { - FileInputStream in; - try { - in = new FileInputStream(filename); - } catch (Exception e) { - System.out.printf("Failed to open file '%s'\n", filename); + AltosRecordIterable recs = record_iterable_file(filename); + if (recs == null) return; - } - AltosRecordIterable recs; - if (filename.endsWith("eeprom")) { - recs = new AltosEepromIterable(in); - } else { - recs = new AltosTelemetryIterable(in); - } try { - new AltosGraphUI(recs); + new AltosGraphUI(recs, filename); } catch (InterruptedException ie) { } catch (IOException ie) { } } + static void process_summary(String filename) { + AltosReplayReader reader = replay_file(filename); + try { + AltosFlightStats stats = new AltosFlightStats(reader); + if (stats.serial > 0) + System.out.printf("Serial: %5d\n", stats.serial); + if (stats.flight > 0) + System.out.printf("Flight: %5d\n", stats.flight); + if (stats.year > 0) + System.out.printf("Date: %04d-%02d-%02d\n", + stats.year, stats.month, stats.day); + if (stats.hour > 0) + System.out.printf("Time: %02d:%02d:%02d UTC\n", + stats.hour, stats.minute, stats.second); + System.out.printf("Max height: %6.0f m %6.0f ft\n", + stats.max_height, + AltosConvert.meters_to_feet(stats.max_height)); + System.out.printf("Max speed: %6.0f m/s %6.0f ft/s %6.4f Mach\n", + stats.max_speed, + AltosConvert.meters_to_feet(stats.max_speed), + AltosConvert.meters_to_mach(stats.max_speed)); + if (stats.max_acceleration != AltosRecord.MISSING) { + System.out.printf("Max accel: %6.0f m/s² %6.0f ft/s² %6.2f g\n", + stats.max_acceleration, + AltosConvert.meters_to_feet(stats.max_acceleration), + AltosConvert.meters_to_g(stats.max_acceleration)); + } + System.out.printf("Drogue rate: %6.0f m/s %6.0f ft/s\n", + stats.state_baro_speed[Altos.ao_flight_drogue], + AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_drogue])); + System.out.printf("Main rate: %6.0f m/s %6.0f ft/s\n", + stats.state_baro_speed[Altos.ao_flight_main], + AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main])); + System.out.printf("Flight time: %6.0f s\n", + stats.state_end[Altos.ao_flight_main] - + stats.state_start[Altos.ao_flight_boost]); + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + } + public static void help(int code) { System.out.printf("Usage: altosui [OPTION]... [FILE]...\n"); System.out.printf(" Options:\n"); @@ -489,6 +532,8 @@ public class AltosUI extends JFrame { process = process_csv; else if (args[i].equals("--graph")) process = process_graph; + else if (args[i].equals("--summary")) + process = process_summary; else if (args[i].startsWith("--")) help(1); else { @@ -506,6 +551,9 @@ public class AltosUI extends JFrame { case process_csv: process_csv(args[i]); break; + case process_summary: + process_summary(args[i]); + break; } } } diff --git a/altosui/libaltos/altos.dll b/altosui/libaltos/altos.dll deleted file mode 100755 index a96d3129..00000000 Binary files a/altosui/libaltos/altos.dll and /dev/null differ -- cgit v1.2.3 From 3a84e8e0cc86481c301f4335843a0e1a94bad5c0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 23:12:30 -0700 Subject: altosui: Make monitor-idle display correct 'On-board data logging' status Count number of stored flights and see if there's space for another one. Signed-off-by: Keith Packard --- altosui/AltosConfigData.java | 23 ++++++++++++++++++++++- altosui/AltosIdleMonitorUI.java | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 272dd402..c14dc5a1 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -54,6 +54,7 @@ public class AltosConfigData implements Iterable { int radio_calibration; int flight_log_max; int ignite_mode; + int stored_flight; int storage_size; int storage_erase_unit; @@ -84,10 +85,29 @@ public class AltosConfigData implements Iterable { return lines.iterator(); } + public int log_available() { + switch (log_format) { + case Altos.AO_LOG_FORMAT_TINY: + if (stored_flight == 0) + return 1; + return 0; + default: + if (flight_log_max <= 0) + return 1; + int log_space = storage_size - storage_erase_unit; + int log_used = stored_flight * flight_log_max; + + if (log_used >= log_space) + return 0; + return (log_space - log_used) / flight_log_max; + } + } + public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { - serial_line.printf("c s\nf\nv\n"); + serial_line.printf("c s\nf\nl\nv\n"); lines = new LinkedList(); radio_setting = 0; + stored_flight = 0; for (;;) { String line = serial_line.get_reply(); if (line == null) @@ -117,6 +137,7 @@ public class AltosConfigData implements Iterable { try { version = get_string(line,"software-version"); } catch (Exception e) {} try { product = get_string(line,"product"); } catch (Exception e) {} + try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 0370efa9..142f0278 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -193,7 +193,7 @@ class AltosIdleMonitor extends Thread { record.version = 0; record.callsign = config_data.callsign; record.serial = config_data.serial; - record.flight = 0; + record.flight = config_data.log_available() > 0 ? 255 : 0; record.rssi = 0; record.status = 0; record.state = Altos.ao_flight_idle; -- cgit v1.2.3 From 4aebe65b089e4b825a5ae238b81e2181bd88175a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 23:31:54 -0700 Subject: altosui: Can't configure flight log max on TeleMini It's only got space for one flight. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index b1e6bc12..f1743608 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -148,7 +148,17 @@ public class AltosConfig implements ActionListener { config_ui.set_apogee_delay(apogee_delay.get()); config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_radio_frequency(frequency()); - config_ui.set_flight_log_max_enabled(stored_flight.get() < 0); + boolean max_enabled = true; + switch (log_format.get()) { + case Altos.AO_LOG_FORMAT_TINY: + max_enabled = false; + break; + default: + if (stored_flight.get() >= 0) + max_enabled = false; + break; + } + config_ui.set_flight_log_max_enabled(max_enabled); config_ui.set_radio_enable(radio_enable.get()); config_ui.set_flight_log_max_limit(log_limit()); config_ui.set_flight_log_max(flight_log_max.get()); -- cgit v1.2.3 From e9254c3472e42d93181674b2c3cd80fe6eea696e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 23:32:36 -0700 Subject: altosui: fix 'magic' string to signal end of config data Was using "done", which happens to be displayed by the 'l' command. Switch to 'all finished' which doesn't appear in the config data output. Yes, this method is a kludge. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index f1743608..7cd8cb8b 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -174,7 +174,7 @@ public class AltosConfig implements ActionListener { abort(); return; } - if (line.equals("done")) { + if (line.equals("all finished")) { if (serial_line != null) update_ui(); return; @@ -244,7 +244,7 @@ public class AltosConfig implements ActionListener { } catch (InterruptedException ie) { } } - callback("done"); + callback("all finished"); } void save_data() { -- cgit v1.2.3 From d249da3fb064754753bd20cd2ca1e5ffcce294ca Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 23:33:52 -0700 Subject: altosui: Only 'show' config dialog once Otherwise, the dialog jumps back to the initial position each time the data is updated. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 7cd8cb8b..45521665 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -85,6 +85,7 @@ public class AltosConfig implements ActionListener { string_ref callsign; AltosConfigUI config_ui; boolean serial_started; + boolean made_visible; boolean get_int(String line, String label, int_ref x) { if (line.startsWith(label)) { @@ -166,7 +167,10 @@ public class AltosConfig implements ActionListener { config_ui.set_pad_orientation(pad_orientation.get()); config_ui.set_callsign(callsign.get()); config_ui.set_clean(); - config_ui.make_visible(); + if (!made_visible) { + made_visible = true; + config_ui.make_visible(); + } } void process_line(String line) { -- cgit v1.2.3 From 955989147f90a4fd22c1375d1b41425dae4e7dd1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 23:34:55 -0700 Subject: altosui: Reset all config data on 'reset' command This lets you switch altimeters without getting any stale data. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 45521665..122ebecc 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -223,10 +223,31 @@ public class AltosConfig implements ActionListener { SwingUtilities.invokeLater(r); } + void reset_data() { + serial.set(0); + log_format.set(Altos.AO_LOG_FORMAT_UNKNOWN); + main_deploy.set(250); + apogee_delay.set(0); + radio_channel.set(0); + radio_setting.set(0); + radio_calibration.set(1186611); + radio_enable.set(-1); + flight_log_max.set(0); + ignite_mode.set(-1); + pad_orientation.set(-1); + storage_size.set(-1); + storage_erase_unit.set(-1); + stored_flight.set(-1); + callsign.set("N0CALL"); + version.set("unknown"); + product.set("unknown"); + } + void get_data() { try { config.start_serial(); - stored_flight.set(-1); + reset_data(); + config.serial_line.printf("c s\nf\nl\nv\n"); for (;;) { try { -- cgit v1.2.3 From fa6df3fa21e8f09e70371e6c6cc7827a533b4fe6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Aug 2011 23:35:28 -0700 Subject: altosui: Update mac os X library This has been tested on 32-bit OS X and it works; dunno about 64-bit. Signed-off-by: Keith Packard --- altosui/libaltos/libaltos.dylib | Bin 54176 -> 41648 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'altosui') diff --git a/altosui/libaltos/libaltos.dylib b/altosui/libaltos/libaltos.dylib index 89aa12e7..1038817d 100755 Binary files a/altosui/libaltos/libaltos.dylib and b/altosui/libaltos/libaltos.dylib differ -- cgit v1.2.3 From 754b9591574c12ddd6e4ab590c6a5f3806b80213 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 23 Aug 2011 13:29:23 -0700 Subject: libaltos: fix Mac OS X function signatures altos_list_start was declared to take a (int time) parameter for some reason. Signed-off-by: Keith Packard --- altosui/libaltos/libaltos.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 21e94ca0..d1f445bd 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -794,8 +794,8 @@ get_number(io_object_t object, CFStringRef entry, int *result) return 0; } -struct altos_list * -altos_list_start(int time) +PUBLIC struct altos_list * +altos_list_start(void) { struct altos_list *list = calloc (sizeof (struct altos_list), 1); CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice"); @@ -810,7 +810,7 @@ altos_list_start(int time) return list; } -int +PUBLIC int altos_list_next(struct altos_list *list, struct altos_device *device) { io_object_t object; @@ -837,7 +837,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device) } } -void +PUBLIC void altos_list_finish(struct altos_list *list) { IOObjectRelease (list->iterator); -- cgit v1.2.3 From 998adccc1c4f8f6c44833bbf4a52d9441748b996 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 23 Aug 2011 18:56:07 -0700 Subject: altosui: add tool-tips to the button box. Signed-off-by: Keith Packard --- altosui/AltosUI.java | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 13cda637..36c08882 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -123,50 +123,56 @@ public class AltosUI extends JFrame { ConnectToDevice(); } }); + b.setToolTipText("Connect to TeleDongle and monitor telemetry"); b = addButton(1, 0, "Save Flight Data"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SaveFlightData(); } }); + b.setToolTipText("Download and/or delete flight data from an altimeter"); b = addButton(2, 0, "Replay Flight"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Replay(); } }); + b.setToolTipText("Watch an old flight in real-time"); b = addButton(3, 0, "Graph Data"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { GraphData(); } }); + b.setToolTipText("Present flight data in a graph and table of statistics"); b = addButton(4, 0, "Export Data"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ExportData(); } }); + b.setToolTipText("Convert flight data for a spreadsheet or GoogleEarth"); b = addButton(0, 1, "Configure Altimeter"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ConfigureTeleMetrum(); } }); - + b.setToolTipText("Set flight, storage and communication parameters"); b = addButton(1, 1, "Configure AltosUI"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ConfigureAltosUI(); } }); - + b.setToolTipText("Global AltosUI settings"); b = addButton(2, 1, "Flash Image"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { FlashImage(); } }); + b.setToolTipText("Replace the firmware in any AltusMetrum product"); b = addButton(3, 1, "Fire Igniter"); b.addActionListener(new ActionListener() { @@ -174,35 +180,35 @@ public class AltosUI extends JFrame { FireIgniter(); } }); - + b.setToolTipText("Remote control of igniters for deployment testing"); b = addButton(4, 1, "Quit"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); - - + b.setToolTipText("Close all active windows and terminate AltosUI"); b = addButton(0, 2, "Scan Channels"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ScanChannels(); } }); - + b.setToolTipText("Find what channel an altimeter is sending telemetry on"); b = addButton(1, 2, "Load Maps"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { LoadMaps(); } }); - + b.setToolTipText("Download satellite images for off-line flight monitoring"); b = addButton(2, 2, "Monitor Idle"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { IdleMonitor(); } }); + b.setToolTipText("Check flight readiness of altimeter in idle mode"); setTitle("AltOS"); -- cgit v1.2.3 From 186dfc7c72aa7eba281f29f917088e49e44c2ddc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 23 Aug 2011 22:51:57 -0700 Subject: altosui: Use system look&feel Turn on the 'be less ugly bit' Signed-off-by: Keith Packard --- altosui/AltosUI.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 36c08882..27c41838 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -508,6 +508,10 @@ public class AltosUI extends JFrame { } public static void main(final String[] args) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + } /* Handle batch-mode */ if (args.length == 0) { AltosUI altosui = new AltosUI(); -- cgit v1.2.3 From 2165e82327faaada23f0503b8e49b80f938b746c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 24 Aug 2011 00:09:51 -0700 Subject: altosui: Add tool-tips to config dialogs Provides more information about the various settings, and, when they're disabled, tells the user why. Signed-off-by: Keith Packard --- altosui/AltosConfigUI.java | 78 +++++++++++++++++++++++++++++++++++++++++-- altosui/AltosConfigureUI.java | 6 ++++ 2 files changed, 82 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index bb9e1cd2..d20dd073 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -116,6 +116,63 @@ public class AltosConfigUI } } + boolean is_telemini() { + String product = product_value.getText(); + return product != null && product.startsWith("TeleMini"); + } + + boolean is_telemetrum() { + String product = product_value.getText(); + return product != null && product.startsWith("TeleMetrum"); + } + + void set_radio_calibration_tool_tip() { + if (radio_calibration_value.isEnabled()) + radio_calibration_value.setToolTipText("Tune radio output to match desired frequency"); + else + radio_calibration_value.setToolTipText("Cannot tune radio while connected over packet mode"); + } + + void set_radio_enable_tool_tip() { + if (radio_enable_value.isEnabled()) + radio_enable_value.setToolTipText("Enable/Disable telemetry and RDF transmissions"); + else + radio_enable_value.setToolTipText("Firmware version does not support disabling radio"); + } + + void set_flight_log_max_tool_tip() { + if (flight_log_max_value.isEnabled()) + flight_log_max_value.setToolTipText("Size reserved for each flight log (in kB)"); + else { + if (is_telemetrum()) + flight_log_max_value.setToolTipText("Cannot set max value with flight logs in memory"); + else if (is_telemini()) + flight_log_max_value.setToolTipText("TeleMini stores only one flight"); + else + flight_log_max_value.setToolTipText("Cannot set max flight log value"); + } + } + + void set_ignite_mode_tool_tip() { + if (ignite_mode_value.isEnabled()) + ignite_mode_value.setToolTipText("Select when igniters will be fired"); + else + ignite_mode_value.setToolTipText("Older firmware could not select ignite mode"); + } + + void set_pad_orientation_tool_tip() { + if (pad_orientation_value.isEnabled()) + pad_orientation_value.setToolTipText("How will TeleMetrum be mounted in the airframe"); + else { + if (is_telemetrum()) + pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward"); + else if (is_telemini()) + pad_orientation_value.setToolTipText("TeleMini doesn't care how it is mounted"); + else + pad_orientation_value.setToolTipText("Can't select orientation"); + } + } + /* Build the UI using a grid bag */ public AltosConfigUI(JFrame in_owner, boolean remote) { super (in_owner, "Configure TeleMetrum", false); @@ -216,6 +273,7 @@ public class AltosConfigUI main_deploy_value.setEditable(true); main_deploy_value.addItemListener(this); pane.add(main_deploy_value, c); + main_deploy_value.setToolTipText("Height above pad altitude to fire main charge"); /* Apogee delay */ c = new GridBagConstraints(); @@ -240,6 +298,7 @@ public class AltosConfigUI apogee_delay_value.setEditable(true); apogee_delay_value.addItemListener(this); pane.add(apogee_delay_value, c); + apogee_delay_value.setToolTipText("Delay after apogee before charge fires"); /* Frequency */ c = new GridBagConstraints(); @@ -263,6 +322,7 @@ public class AltosConfigUI radio_frequency_value = new AltosFreqList(); radio_frequency_value.addItemListener(this); pane.add(radio_frequency_value, c); + radio_frequency_value.setToolTipText("Telemetry, RDF and packet frequency"); /* Radio Calibration */ c = new GridBagConstraints(); @@ -288,6 +348,7 @@ public class AltosConfigUI if (remote) radio_calibration_value.setEnabled(false); pane.add(radio_calibration_value, c); + set_radio_calibration_tool_tip(); /* Radio Enable */ c = new GridBagConstraints(); @@ -311,6 +372,7 @@ public class AltosConfigUI radio_enable_value = new JRadioButton("Enabled"); radio_enable_value.addItemListener(this); pane.add(radio_enable_value, c); + set_radio_enable_tool_tip(); /* Callsign */ c = new GridBagConstraints(); @@ -334,6 +396,7 @@ public class AltosConfigUI callsign_value = new JTextField(AltosPreferences.callsign()); callsign_value.getDocument().addDocumentListener(this); pane.add(callsign_value, c); + callsign_value.setToolTipText("Callsign reported in telemetry data"); /* Flight log max */ c = new GridBagConstraints(); @@ -358,6 +421,7 @@ public class AltosConfigUI flight_log_max_value.setEditable(true); flight_log_max_value.addItemListener(this); pane.add(flight_log_max_value, c); + set_flight_log_max_tool_tip(); /* Ignite mode */ c = new GridBagConstraints(); @@ -382,6 +446,7 @@ public class AltosConfigUI ignite_mode_value.setEditable(false); ignite_mode_value.addItemListener(this); pane.add(ignite_mode_value, c); + set_ignite_mode_tool_tip(); /* Pad orientation */ c = new GridBagConstraints(); @@ -406,6 +471,7 @@ public class AltosConfigUI pad_orientation_value.setEditable(false); pad_orientation_value.addItemListener(this); pane.add(pad_orientation_value, c); + set_pad_orientation_tool_tip(); /* Buttons */ c = new GridBagConstraints(); @@ -521,6 +587,8 @@ public class AltosConfigUI public void set_product(String product) { radio_frequency_value.set_product(product); product_value.setText(product); + set_pad_orientation_tool_tip(); + set_flight_log_max_tool_tip(); } public void set_version(String version) { @@ -585,12 +653,14 @@ public class AltosConfigUI } public void set_radio_enable(int new_radio_enable) { - if (new_radio_enable >= 0) + if (new_radio_enable >= 0) { radio_enable_value.setSelected(new_radio_enable > 0); - else { + radio_enable_value.setEnabled(true); + } else { radio_enable_value.setSelected(true); radio_enable_value.setEnabled(false); } + set_radio_enable_tool_tip(); } public int radio_enable() { @@ -612,10 +682,12 @@ public class AltosConfigUI if (new_flight_log_max == 0) flight_log_max_value.setEnabled(false); flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max)); + set_flight_log_max_tool_tip(); } public void set_flight_log_max_enabled(boolean enable) { flight_log_max_value.setEnabled(enable); + set_flight_log_max_tool_tip(); } public int flight_log_max() { @@ -642,6 +714,7 @@ public class AltosConfigUI ignite_mode_value.setEnabled(true); } ignite_mode_value.setSelectedIndex(new_ignite_mode); + set_ignite_mode_tool_tip(); } public int ignite_mode() { @@ -660,6 +733,7 @@ public class AltosConfigUI pad_orientation_value.setEnabled(true); } pad_orientation_value.setSelectedIndex(new_pad_orientation); + set_pad_orientation_tool_tip(); } public int pad_orientation() { diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index abb54c74..0c865d0e 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -125,6 +125,7 @@ public class AltosConfigureUI c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; pane.add(enable_voice, c); + enable_voice.setToolTipText("Enable/Disable all audio in-flight announcements"); c.gridx = 2; c.gridy = 2; @@ -139,6 +140,7 @@ public class AltosConfigureUI } }); pane.add(test_voice, c); + test_voice.setToolTipText("Play a stock audio clip to check volume"); /* Log directory settings */ c.gridx = 0; @@ -161,6 +163,7 @@ public class AltosConfigureUI c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.WEST; pane.add(configure_log, c); + configure_log.setToolTipText("Which directory flight logs are stored in"); /* Callsign setting */ c.gridx = 0; @@ -178,6 +181,7 @@ public class AltosConfigureUI c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.WEST; pane.add(callsign_value, c); + callsign_value.setToolTipText("Callsign sent in packet mode"); /* Serial debug setting */ c.gridx = 0; @@ -195,6 +199,7 @@ public class AltosConfigureUI AltosPreferences.set_serial_debug(enabled); } }); + serial_debug.setToolTipText("Enable/Disable USB I/O getting sent to the console"); c.gridx = 1; c.gridy = 5; @@ -223,6 +228,7 @@ public class AltosConfigureUI AltosConfigFreqUI.show(owner); } }); + manage_frequencies.setToolTipText("Configure which values are shown in frequency menus"); // BLUETOOTH // c.gridx = 2; c.gridx = 1; -- cgit v1.2.3 From 3b0a9a1c87390747492bfef435ac8e0829ec748f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 24 Aug 2011 00:29:36 -0700 Subject: altosui: Try to get dialogs to look a little better grid bag constraints are not my friend. Signed-off-by: Keith Packard --- altosui/AltosFlightUI.java | 7 +++++++ altosui/AltosIgniteUI.java | 5 ++--- altosui/AltosScanUI.java | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 51768046..abe08a18 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -172,7 +172,10 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { }); c.gridx = 0; c.gridy = 0; + c.weightx = 0; + c.weighty = 0; c.insets = new Insets(3, 3, 3, 3); + c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; bag.add (frequencies, c); @@ -186,6 +189,8 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { telemetry = Altos.ao_telemetry_standard; telemetries.setSelectedIndex(telemetry - 1); telemetries.setMaximumRowCount(Altos.ao_telemetry_max); + telemetries.setPreferredSize(null); + telemetries.revalidate(); telemetries.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int telemetry = telemetries.getSelectedIndex() + 1; @@ -195,6 +200,8 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { }); c.gridx = 1; c.gridy = 0; + c.weightx = 0; + c.weighty = 0; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; bag.add (telemetries, c); diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 806b87b9..c11a8614 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -341,8 +341,8 @@ public class AltosIgniteUI c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; c.insets = i; - c.weightx = 1; - c.weighty = 1; + c.weightx = 0; + c.weighty = 0; c.gridx = 0; c.gridy = 0; @@ -412,7 +412,6 @@ public class AltosIgniteUI close.addActionListener(this); close.setActionCommand("close"); - pack(); setLocationRelativeTo(owner); diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index dd6672aa..bce4b32c 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -386,7 +386,7 @@ public class AltosScanUI set_label(); - c.fill = GridBagConstraints.NONE; + c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.insets = i; c.weightx = 1; -- cgit v1.2.3 From 9849883a754a73b861dd7be530753ff5c2abb499 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 24 Aug 2011 01:48:28 -0700 Subject: altosui: Don't trust companion telemetry record 'channels' count It can be bogus, allowing the code to walk off the end of the allocated data array. Signed-off-by: Keith Packard --- altosui/AltosTelemetryRecordCompanion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosTelemetryRecordCompanion.java b/altosui/AltosTelemetryRecordCompanion.java index 11b349e1..52d7f4cf 100644 --- a/altosui/AltosTelemetryRecordCompanion.java +++ b/altosui/AltosTelemetryRecordCompanion.java @@ -36,7 +36,7 @@ public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { companion.tick = tick; companion.board_id = uint8(5); companion.update_period = uint8(6+off); - for (int i = 0; i < channels; i++) + for (int i = 0; i < companion.companion_data.length; i++) companion.companion_data[i] = uint16(8 + off + i * 2); } -- cgit v1.2.3 From cbfbaabb39f9f7709d00cf3dc63cc1bc7563062e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 24 Aug 2011 19:13:03 -0700 Subject: altosui: Make flight monitor font size configurable Tiny netbooks aren't tall enough for the 'usual' font size, so provide a smaller option. Then provide a bigger option, just because. Signed-off-by: Keith Packard --- altosui/Altos.java | 42 ++++++++++++++++++++++++++-- altosui/AltosAscent.java | 30 +++++++++++++++++++- altosui/AltosCompanionInfo.java | 15 +++++----- altosui/AltosConfigureUI.java | 61 +++++++++++++++++++++++++++++++---------- altosui/AltosDescent.java | 28 +++++++++++++++++++ altosui/AltosFlightDisplay.java | 2 ++ altosui/AltosFlightStatus.java | 14 ++++++++++ altosui/AltosFlightUI.java | 21 +++++++++++++- altosui/AltosFontListener.java | 22 +++++++++++++++ altosui/AltosIdleMonitorUI.java | 5 ++++ altosui/AltosInfoTable.java | 12 ++++---- altosui/AltosLanded.java | 23 ++++++++++++---- altosui/AltosPad.java | 22 +++++++++++++++ altosui/AltosPreferences.java | 42 ++++++++++++++++++++++++++++ altosui/AltosSiteMap.java | 4 +++ altosui/Makefile.am | 1 + doc/altusmetrum.xsl | 7 +++++ 17 files changed, 314 insertions(+), 37 deletions(-) create mode 100644 altosui/AltosFontListener.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index ddf1005a..e4f974f9 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -97,9 +97,45 @@ public class Altos { static final int tab_elt_pad = 5; - static final Font label_font = new Font("Dialog", Font.PLAIN, 22); - static final Font value_font = new Font("Monospaced", Font.PLAIN, 22); - static final Font status_font = new Font("SansSerif", Font.BOLD, 24); + static Font label_font; + static Font value_font; + static Font status_font; + static Font table_label_font; + static Font table_value_font; + + final static int font_size_small = 1; + final static int font_size_medium = 2; + final 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; diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index d607b0c5..c8e5f3af 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -30,6 +30,7 @@ import java.util.concurrent.LinkedBlockingQueue; public class AltosAscent extends JComponent implements AltosFlightDisplay { GridBagLayout layout; + JLabel cur, max; public class AscentStatus { JLabel label; @@ -54,6 +55,11 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { lights.set(false); } + void set_font() { + label.setFont(Altos.label_font); + value.setFont(Altos.value_font); + } + public AscentStatus (GridBagLayout layout, int y, String text) { GridBagConstraints c = new GridBagConstraints(); c.weighty = 1; @@ -109,6 +115,11 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { label.setVisible(false); value.setVisible(false); } + void set_font() { + label.setFont(Altos.label_font); + value.setFont(Altos.value_font); + } + public AscentValue (GridBagLayout layout, int y, String text) { GridBagConstraints c = new GridBagConstraints(); c.weighty = 1; @@ -151,6 +162,12 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { max = AltosRecord.MISSING; } + void set_font() { + label.setFont(Altos.label_font); + value.setFont(Altos.value_font); + max_value.setFont(Altos.value_font); + } + void show(String format, double v) { if (v == AltosRecord.MISSING) { value.setText("Missing"); @@ -314,6 +331,18 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { accel.reset(); } + public void set_font() { + cur.setFont(Altos.label_font); + max.setFont(Altos.label_font); + lat.set_font(); + lon.set_font(); + main.set_font(); + apogee.set_font(); + height.set_font(); + speed.set_font(); + accel.set_font(); + } + public void show(AltosState state, int crc_errors) { if (state.gps != null && state.gps.connected) { lat.show(state, crc_errors); @@ -337,7 +366,6 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { public void labels(GridBagLayout layout, int y) { GridBagConstraints c; - JLabel cur, max; cur = new JLabel("Current"); cur.setFont(Altos.label_font); diff --git a/altosui/AltosCompanionInfo.java b/altosui/AltosCompanionInfo.java index f287a8ea..82bde623 100644 --- a/altosui/AltosCompanionInfo.java +++ b/altosui/AltosCompanionInfo.java @@ -31,25 +31,26 @@ import java.util.concurrent.LinkedBlockingQueue; public class AltosCompanionInfo extends JTable { private AltosFlightInfoTableModel model; - private Font infoLabelFont = new Font("SansSerif", Font.PLAIN, 14); - private Font infoValueFont = new Font("Monospaced", Font.PLAIN, 14); - static final int info_columns = 2; static final int info_rows = 17; int desired_row_height() { - FontMetrics infoValueMetrics = getFontMetrics(infoValueFont); + FontMetrics infoValueMetrics = getFontMetrics(Altos.table_value_font); return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10; } + public void set_font() { + setFont(Altos.table_value_font); + setRowHeight(desired_row_height()); + doLayout(); + } + public AltosCompanionInfo() { super(new AltosFlightInfoTableModel(info_rows, info_columns)); model = (AltosFlightInfoTableModel) getModel(); - setFont(infoValueFont); setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS); setShowGrid(true); - setRowHeight(desired_row_height()); - doLayout(); + set_font(); } public Dimension getPreferredScrollableViewportSize() { diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index 0c865d0e..bcb9636b 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -47,12 +47,17 @@ public class AltosConfigureUI JLabel callsign_label; JTextField callsign_value; + JLabel font_size_label; + JComboBox font_size_value; + JRadioButton serial_debug; // BLUETOOTH // JButton manage_bluetooth; JButton manage_frequencies; + final static String[] font_size_names = { "Small", "Medium", "Large" }; + /* DocumentListener interface methods */ public void changedUpdate(DocumentEvent e) { AltosPreferences.set_callsign(callsign_value.getText()); @@ -73,6 +78,8 @@ public class AltosConfigureUI Insets insets = new Insets(4, 4, 4, 4); + int row = 0; + owner = in_owner; voice = in_voice; pane = getContentPane(); @@ -85,14 +92,14 @@ public class AltosConfigureUI /* Nice label at the top */ c.gridx = 0; - c.gridy = 0; + c.gridy = row++; c.gridwidth = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; pane.add(new JLabel ("Configure AltOS UI"), c); c.gridx = 0; - c.gridy = 1; + c.gridy = row++; c.gridwidth = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -100,7 +107,7 @@ public class AltosConfigureUI /* Voice settings */ c.gridx = 0; - c.gridy = 2; + c.gridy = row; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -119,7 +126,7 @@ public class AltosConfigureUI } }); c.gridx = 1; - c.gridy = 2; + c.gridy = row; c.gridwidth = 1; c.weightx = 1; c.fill = GridBagConstraints.NONE; @@ -128,7 +135,7 @@ public class AltosConfigureUI enable_voice.setToolTipText("Enable/Disable all audio in-flight announcements"); c.gridx = 2; - c.gridy = 2; + c.gridy = row++; c.gridwidth = 1; c.weightx = 1; c.fill = GridBagConstraints.NONE; @@ -144,7 +151,7 @@ public class AltosConfigureUI /* Log directory settings */ c.gridx = 0; - c.gridy = 3; + c.gridy = row; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -158,7 +165,7 @@ public class AltosConfigureUI } }); c.gridx = 1; - c.gridy = 3; + c.gridy = row++; c.gridwidth = 2; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.WEST; @@ -167,7 +174,7 @@ public class AltosConfigureUI /* Callsign setting */ c.gridx = 0; - c.gridy = 4; + c.gridy = row; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -176,16 +183,42 @@ public class AltosConfigureUI callsign_value = new JTextField(AltosPreferences.callsign()); callsign_value.getDocument().addDocumentListener(this); c.gridx = 1; - c.gridy = 4; + 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"); + /* 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 = AltosPreferences.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; + + AltosPreferences.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"); + /* Serial debug setting */ c.gridx = 0; - c.gridy = 5; + c.gridy = row; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -202,7 +235,7 @@ public class AltosConfigureUI serial_debug.setToolTipText("Enable/Disable USB I/O getting sent to the console"); c.gridx = 1; - c.gridy = 5; + c.gridy = row++; c.gridwidth = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -216,7 +249,7 @@ public class AltosConfigureUI // } // }); // c.gridx = 0; -// c.gridy = 6; +// c.gridy = row++; // c.gridwidth = 2; // c.fill = GridBagConstraints.NONE; // c.anchor = GridBagConstraints.WEST; @@ -232,7 +265,7 @@ public class AltosConfigureUI // BLUETOOTH // c.gridx = 2; c.gridx = 1; - c.gridy = 6; + c.gridy = row++; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; @@ -246,7 +279,7 @@ public class AltosConfigureUI } }); c.gridx = 0; - c.gridy = 7; + c.gridy = row++; c.gridwidth = 3; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 2a9e7eef..0fcd690b 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -55,6 +55,11 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { lights.set(false); } + void set_font() { + label.setFont(Altos.label_font); + value.setFont(Altos.value_font); + } + public DescentStatus (GridBagLayout layout, int y, String text) { GridBagConstraints c = new GridBagConstraints(); c.weighty = 1; @@ -121,6 +126,11 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { value.setText(v); } + void set_font() { + label.setFont(Altos.label_font); + value.setFont(Altos.value_font); + } + public DescentValue (GridBagLayout layout, int x, int y, String text) { GridBagConstraints c = new GridBagConstraints(); c.weighty = 1; @@ -169,6 +179,12 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { value2.setVisible(false); } + void set_font() { + label.setFont(Altos.label_font); + value1.setFont(Altos.value_font); + value2.setFont(Altos.value_font); + } + abstract void show(AltosState state, int crc_errors); void show(String v1, String v2) { @@ -361,6 +377,18 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { apogee.reset(); } + public void set_font() { + lat.set_font(); + lon.set_font(); + height.set_font(); + speed.set_font(); + bearing.set_font(); + range.set_font(); + elevation.set_font(); + main.set_font(); + apogee.set_font(); + } + public void show(AltosState state, int crc_errors) { height.show(state, crc_errors); speed.show(state, crc_errors); diff --git a/altosui/AltosFlightDisplay.java b/altosui/AltosFlightDisplay.java index d18d1d1f..f633c8e6 100644 --- a/altosui/AltosFlightDisplay.java +++ b/altosui/AltosFlightDisplay.java @@ -21,4 +21,6 @@ public interface AltosFlightDisplay { void reset(); void show(AltosState state, int crc_errors); + + void set_font(); } diff --git a/altosui/AltosFlightStatus.java b/altosui/AltosFlightStatus.java index 59c9e9db..ed273384 100644 --- a/altosui/AltosFlightStatus.java +++ b/altosui/AltosFlightStatus.java @@ -40,6 +40,12 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay void reset() { value.setText(""); } + + void set_font() { + label.setFont(Altos.status_font); + value.setFont(Altos.status_font); + } + public FlightValue (GridBagLayout layout, int x, String text) { GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(5, 5, 5, 5); @@ -127,6 +133,14 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay rssi.reset(); } + public void set_font () { + call.set_font(); + serial.set_font(); + flight.set_font(); + flight_state.set_font(); + rssi.set_font(); + } + public void show (AltosState state, int crc_errors) { call.show(state, crc_errors); serial.show(state, crc_errors); diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index abe08a18..b44b9d43 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -28,7 +28,7 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; -public class AltosFlightUI extends JFrame implements AltosFlightDisplay { +public class AltosFlightUI extends JFrame implements AltosFlightDisplay, AltosFontListener { AltosVoice voice; AltosFlightReader reader; AltosDisplayThread thread; @@ -83,6 +83,21 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { sitemap.reset(); } + public void set_font() { + pad.set_font(); + ascent.set_font(); + descent.set_font(); + landed.set_font(); + flightStatus.set_font(); + flightInfo.set_font(); + sitemap.set_font(); + companion.set_font(); + } + + public void font_size_changed(int font_size) { + set_font(); + } + public void show(AltosState state, int crc_errors) { JComponent tab = which_tab(state); try { @@ -254,12 +269,16 @@ public class AltosFlightUI extends JFrame implements AltosFlightDisplay { bag.add(pane, c); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + + AltosPreferences.register_font_listener(this); + addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { disconnect(); setVisible(false); dispose(); + AltosPreferences.unregister_font_listener(AltosFlightUI.this); if (exit_on_close) System.exit(0); } diff --git a/altosui/AltosFontListener.java b/altosui/AltosFontListener.java new file mode 100644 index 00000000..0dda0f29 --- /dev/null +++ b/altosui/AltosFontListener.java @@ -0,0 +1,22 @@ +/* + * 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 altosui; + +public interface AltosFontListener { + void font_size_changed(int font_size); +} diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 142f0278..988a797c 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -284,6 +284,11 @@ public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { flightInfo.clear(); } + public void set_font() { + pad.set_font(); + flightInfo.set_font(); + } + public void show(AltosState state, int crc_errors) { try { pad.show(state, crc_errors); diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java index 8ebeaba1..c023369e 100644 --- a/altosui/AltosInfoTable.java +++ b/altosui/AltosInfoTable.java @@ -31,27 +31,29 @@ import java.util.concurrent.LinkedBlockingQueue; public class AltosInfoTable extends JTable { private AltosFlightInfoTableModel model; - private Font infoLabelFont = new Font("SansSerif", Font.PLAIN, 14); - private Font infoValueFont = new Font("Monospaced", Font.PLAIN, 14); - static final int info_columns = 3; static final int info_rows = 17; int desired_row_height() { - FontMetrics infoValueMetrics = getFontMetrics(infoValueFont); + FontMetrics infoValueMetrics = getFontMetrics(Altos.table_value_font); return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10; } public AltosInfoTable() { super(new AltosFlightInfoTableModel(info_rows, info_columns)); model = (AltosFlightInfoTableModel) getModel(); - setFont(infoValueFont); + setFont(Altos.table_value_font); setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS); setShowGrid(true); setRowHeight(desired_row_height()); doLayout(); } + public void set_font() { + setFont(Altos.table_value_font); + doLayout(); + } + public Dimension getPreferredScrollableViewportSize() { return getPreferredSize(); } diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 71c10663..50e6b542 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -30,8 +30,6 @@ import java.util.concurrent.LinkedBlockingQueue; public class AltosLanded extends JComponent implements AltosFlightDisplay, ActionListener { GridBagLayout layout; - Font label_font; - Font value_font; public class LandedValue { JLabel label; @@ -47,6 +45,11 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio value.setVisible(true); } + public void set_font() { + label.setFont(Altos.label_font); + value.setFont(Altos.value_font); + } + void hide() { label.setVisible(false); value.setVisible(false); @@ -63,7 +66,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio c.weighty = 1; label = new JLabel(text); - label.setFont(label_font); + label.setFont(Altos.label_font); label.setHorizontalAlignment(SwingConstants.LEFT); c.gridx = 0; c.gridy = y; c.insets = new Insets(10, 10, 10, 10); @@ -74,7 +77,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio add(label); value = new JTextField(Altos.text_width); - value.setFont(value_font); + value.setFont(Altos.value_font); value.setHorizontalAlignment(SwingConstants.RIGHT); c.gridx = 1; c.gridy = y; c.anchor = GridBagConstraints.WEST; @@ -199,6 +202,16 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio accel.reset(); } + public void set_font() { + lat.set_font(); + lon.set_font(); + bearing.set_font(); + distance.set_font(); + height.set_font(); + speed.set_font(); + accel.set_font(); + } + public void show(AltosState state, int crc_errors) { if (state.gps != null && state.gps.connected) { bearing.show(state, crc_errors); @@ -259,8 +272,6 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio reader = in_reader; - label_font = new Font("Dialog", Font.PLAIN, 22); - value_font = new Font("Monospaced", Font.PLAIN, 22); setLayout(layout); /* Elements in descent display */ diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index 3a8d04fe..6ef66f7a 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -54,6 +54,11 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { lights.setVisible(false); } + public void set_font() { + label.setFont(Altos.label_font); + value.setFont(Altos.value_font); + } + public LaunchStatus (GridBagLayout layout, int y, String text) { GridBagConstraints c = new GridBagConstraints(); c.weighty = 1; @@ -105,6 +110,11 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { value.setVisible(false); } + public void set_font() { + label.setFont(Altos.label_font); + value.setFont(Altos.value_font); + } + void reset() { value.setText(""); } @@ -282,6 +292,18 @@ public class AltosPad extends JComponent implements AltosFlightDisplay { pad_alt.reset(); } + public void set_font() { + battery.set_font(); + apogee.set_font(); + main.set_font(); + logging_ready.set_font(); + gps_locked.set_font(); + gps_ready.set_font(); + pad_lat.set_font(); + pad_lon.set_font(); + pad_alt.set_font(); + } + public void show(AltosState state, int crc_errors) { battery.show(state, crc_errors); if (state.drogue_sense == AltosRecord.MISSING) diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index de926b38..716559ab 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -55,6 +55,9 @@ class AltosPreferences { /* scanning telemetry preferences name */ final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; + /* font size preferences name */ + final static String fontSizePreference = "FONT-SIZE"; + /* Default logdir is ~/TeleMetrum */ final static String logdirName = "TeleMetrum"; @@ -88,6 +91,10 @@ class AltosPreferences { /* Scanning telemetry */ static int scanning_telemetry; + static LinkedList font_listeners; + + static int font_size = Altos.font_size_medium; + /* List of frequencies */ final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; static AltosFrequency[] common_frequencies; @@ -164,6 +171,11 @@ class AltosPreferences { scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << Altos.ao_telemetry_standard)); + font_listeners = new LinkedList(); + + font_size = preferences.getInt(fontSizePreference, Altos.font_size_medium); + Altos.set_fonts(font_size); + String firmwaredir_string = preferences.get(firmwaredirPreference, null); if (firmwaredir_string != null) firmwaredir = new File(firmwaredir_string); @@ -335,6 +347,36 @@ class AltosPreferences { return firmwaredir; } + public static int font_size() { + return font_size; + } + + static void set_fonts() { + } + + public static void set_font_size(int new_font_size) { + font_size = new_font_size; + synchronized (preferences) { + preferences.putInt(fontSizePreference, font_size); + flush_preferences(); + Altos.set_fonts(font_size); + for (AltosFontListener l : font_listeners) + l.font_size_changed(font_size); + } + } + + public static void register_font_listener(AltosFontListener l) { + synchronized (preferences) { + font_listeners.add(l); + } + } + + public static void unregister_font_listener(AltosFontListener l) { + synchronized (preferences) { + font_listeners.remove(l); + } + } + public static void set_serial_debug(boolean new_serial_debug) { serial_debug = new_serial_debug; AltosSerial.set_debug(serial_debug); diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index b3fb3c54..c258b3e5 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -146,6 +146,10 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { // nothing } + public void set_font() { + // nothing + } + private void loadMap(final AltosSiteMapTile tile, File pngfile, String pngurl) { diff --git a/altosui/Makefile.am b/altosui/Makefile.am index f626d3fa..ba1c830c 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -57,6 +57,7 @@ altosui_JAVA = \ AltosFlightStatsTable.java \ AltosFlightStatus.java \ AltosFlightUI.java \ + AltosFontListener.java \ AltosFrequency.java \ AltosFreqList.java \ AltosGPS.java \ diff --git a/doc/altusmetrum.xsl b/doc/altusmetrum.xsl index 601b62eb..df1e6635 100644 --- a/doc/altusmetrum.xsl +++ b/doc/altusmetrum.xsl @@ -1537,6 +1537,13 @@ NAR #88757, TRA #12200 your local radio regulations. +
+ Font Size + + Selects the set of fonts used in the flight monitor + window. Choose between the small, medium and large sets. + +
Serial Debug -- cgit v1.2.3 From 5a9972d41a87d4204c6c93cacf14e2962cc1c59c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 24 Aug 2011 20:22:29 -0700 Subject: altos/windows: Get latest JRE 1.6 version (Version 6 update 27) No reason to download stale java bits. Signed-off-by: Keith Packard --- altosui/altos-windows.nsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index 70dc03ca..cbcb389d 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -1,7 +1,7 @@ !addplugindir Instdrv/NSIS/Plugins ; Definitions for Java 1.6 Detection !define JRE_VERSION "1.6" -!define JRE_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=18714&/jre-6u5-windows-i586-p.exe" +!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 Installer" @@ -23,7 +23,7 @@ ShowInstDetails Show ComponentText "Altus Metrum Software and Driver Installer" Function GetJRE - MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION}, it will now \ + 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" -- cgit v1.2.3 From 4568bc796a6c362ebf7f72ee9a5fa4a9a3c4ba6a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Aug 2011 17:08:24 -0700 Subject: altosui: Add primitive UI for TeleLaunch Display status along with arm and fire buttons. Signed-off-by: Keith Packard --- altosui/AltosLaunch.java | 201 ++++++++++++++++ altosui/AltosLaunchUI.java | 518 ++++++++++++++++++++++++++++++++++++++++++ altosui/AltosPreferences.java | 39 ++++ altosui/Makefile.am | 2 + src/ao_radio_cmac.c | 140 ++++++++---- 5 files changed, 854 insertions(+), 46 deletions(-) create mode 100644 altosui/AltosLaunch.java create mode 100644 altosui/AltosLaunchUI.java (limited to 'altosui') diff --git a/altosui/AltosLaunch.java b/altosui/AltosLaunch.java new file mode 100644 index 00000000..77f681b8 --- /dev/null +++ b/altosui/AltosLaunch.java @@ -0,0 +1,201 @@ +/* + * 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 altosui; + +import java.io.*; +import java.util.concurrent.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; + +public class AltosLaunch { + AltosDevice device; + AltosSerial serial; + boolean serial_started; + int launcher_serial; + int launcher_channel; + int rssi; + + final static int Unknown = -1; + final static int Good = 0; + final static int Bad = 1; + + int armed; + int igniter; + + private void start_serial() throws InterruptedException { + serial_started = true; + } + + private void stop_serial() throws InterruptedException { + if (!serial_started) + return; + serial_started = false; + if (serial == null) + return; + } + + class string_ref { + String value; + + public String get() { + return value; + } + public void set(String i) { + value = i; + } + public string_ref() { + value = null; + } + } + + private boolean get_string(String line, String label, string_ref s) { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + s.set(quoted); + return true; + } else { + return false; + } + } + + public boolean status() throws InterruptedException, TimeoutException { + boolean ok = false; + if (serial == null) + return false; + string_ref status_name = new string_ref(); + start_serial(); + serial.printf("l %d %d\n", launcher_serial, launcher_channel); + for (;;) { + String line = serial.get_reply(20000); + if (line == null) + throw new TimeoutException(); + if (get_string(line, "Rssi: ", status_name)) { + try { + rssi = Altos.fromdec(status_name.get()); + } catch (NumberFormatException ne) { + } + break; + } else if (get_string(line, "Armed: ", status_name)) { + armed = Good; + String status = status_name.get(); + if (status.startsWith("igniter good")) + igniter = Good; + else if (status.startsWith("igniter bad")) + igniter = Bad; + else + igniter = Unknown; + ok = true; + } else if (get_string(line, "Disarmed: ", status_name)) { + armed = Bad; + if (status_name.get().startsWith("igniter good")) + igniter = Good; + else if (status_name.get().startsWith("igniter bad")) + igniter = Bad; + else + igniter = Unknown; + ok = true; + } else if (get_string(line, "Error ", status_name)) { + armed = Unknown; + igniter = Unknown; + ok = false; + break; + } + } + stop_serial(); + if (!ok) { + armed = Unknown; + igniter = Unknown; + } + return ok; + } + + public static String status_string(int status) { + switch (status) { + case Good: + return "good"; + case Bad: + return "open"; + } + return "unknown"; + } + + public void arm() { + if (serial == null) + return; + try { + start_serial(); + serial.printf("a %d %d\n", launcher_serial, launcher_channel); + serial.flush_output(); + } catch (InterruptedException ie) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + } + + public void fire() { + if (serial == null) + return; + try { + start_serial(); + serial.printf("i %d %d\n", launcher_serial, launcher_channel); + serial.flush_output(); + } catch (InterruptedException ie) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + } + + public void close() { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + serial.close(); + serial = null; + } + + public void set_frame(Frame frame) { + serial.set_frame(frame); + } + + public void set_remote(int in_serial, int in_channel) { + launcher_serial = in_serial; + launcher_channel = in_channel; + } + + public AltosLaunch(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { + + device = in_device; + serial = new AltosSerial(device); + } +} \ No newline at end of file diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java new file mode 100644 index 00000000..4e630afb --- /dev/null +++ b/altosui/AltosLaunchUI.java @@ -0,0 +1,518 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class FireButton extends JButton { + protected void processMouseEvent(MouseEvent e) { + super.processMouseEvent(e); + switch (e.getID()) { + case MouseEvent.MOUSE_PRESSED: + if (actionListener != null) + actionListener.actionPerformed(new ActionEvent(this, e.getID(), "fire_down")); + break; + case MouseEvent.MOUSE_RELEASED: + if (actionListener != null) + actionListener.actionPerformed(new ActionEvent(this, e.getID(), "fire_up")); + break; + } + } + + public FireButton(String s) { + super(s); + } +} + +public class AltosLaunchUI + extends JDialog + implements ActionListener +{ + AltosDevice device; + JFrame owner; + JLabel label; + + int radio_channel; + JLabel radio_channel_label; + JTextField radio_channel_text; + + int launcher_serial; + JLabel launcher_serial_label; + JTextField launcher_serial_text; + + int launcher_channel; + JLabel launcher_channel_label; + JTextField launcher_channel_text; + + JLabel armed_label; + JLabel armed_status_label; + JLabel igniter; + JLabel igniter_status_label; + JToggleButton arm; + FireButton fire; + javax.swing.Timer arm_timer; + javax.swing.Timer fire_timer; + + boolean firing; + boolean armed; + int armed_status; + int igniter_status; + int rssi; + + final static int arm_timeout = 1 * 1000; + final static int fire_timeout = 250; + + int armed_count; + + LinkedBlockingQueue command_queue; + + class LaunchHandler implements Runnable { + AltosLaunch launch; + JFrame owner; + + void send_exception(Exception e) { + final Exception f_e = e; + Runnable r = new Runnable() { + public void run() { + launch_exception(f_e); + } + }; + SwingUtilities.invokeLater(r); + } + + public void run () { + try { + launch = new AltosLaunch(device); + } catch (Exception e) { + send_exception(e); + return; + } + launch.set_frame(owner); + launch.set_remote(launcher_serial, launcher_channel); + + for (;;) { + Runnable r; + + try { + String command = command_queue.take(); + String reply = null; + + if (command.equals("get_status")) { + launch.status(); + reply = "status"; + armed_status = launch.armed; + igniter_status = launch.igniter; + rssi = launch.rssi; + } else if (command.equals("set_remote")) { + launch.set_remote(launcher_serial, launcher_channel); + reply = "remote set"; + } else if (command.equals("arm")) { + launch.arm(); + reply = "armed"; + } else if (command.equals("fire")) { + launch.fire(); + reply = "fired"; + } else if (command.equals("quit")) { + launch.close(); + break; + } else { + throw new ParseException(String.format("invalid command %s", command), 0); + } + final String f_reply = reply; + r = new Runnable() { + public void run() { + launch_reply(f_reply); + } + }; + SwingUtilities.invokeLater(r); + } catch (Exception e) { + send_exception(e); + } + } + } + + public LaunchHandler(JFrame in_owner) { + owner = in_owner; + } + } + + void launch_exception(Exception e) { + if (e instanceof FileNotFoundException) { + JOptionPane.showMessageDialog(owner, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } else if (e instanceof AltosSerialInUseException) { + JOptionPane.showMessageDialog(owner, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } else if (e instanceof IOException) { + IOException ee = (IOException) e; + JOptionPane.showMessageDialog(owner, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } else { + JOptionPane.showMessageDialog(owner, + String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); + } + close(); + } + + void launch_reply(String reply) { + if (reply == null) + return; + if (reply.equals("remote set")) + poll_launch_status(); + if (reply.equals("status")) { + set_launch_status(); + } + } + + void set_arm_text() { + if (arm.isSelected()) + arm.setText(String.format("%d", armed_count)); + else + arm.setText("Arm"); + } + + void start_arm_timer() { + armed_count = 30; + set_arm_text(); + } + + void stop_arm_timer() { + armed_count = 0; + armed = false; + arm.setSelected(false); + fire.setEnabled(false); + set_arm_text(); + } + + void cancel () { + fire.setEnabled(false); + firing = false; + stop_arm_timer(); + } + + void send_command(String command) { + try { + command_queue.put(command); + } catch (Exception ex) { + launch_exception(ex); + } + } + + boolean getting_status = false; + + void set_launch_status() { + getting_status = false; + armed_status_label.setText(String.format("\"%s\"", AltosLaunch.status_string(armed_status))); + igniter_status_label.setText(String.format("\"%s\"", AltosLaunch.status_string(igniter_status))); + } + + void poll_launch_status() { + if (!getting_status && !firing && !armed) { + getting_status = true; + send_command("get_status"); + } + } + + void fired() { + firing = false; + cancel(); + } + + void close() { + send_command("quit"); + arm_timer.stop(); + setVisible(false); + dispose(); + } + + void tick_arm_timer() { + if (armed_count > 0) { + --armed_count; + if (armed_count <= 0) { + armed_count = 0; + cancel(); + } else { + if (!firing) { + send_command("arm"); + set_arm_text(); + } + } + } + poll_launch_status(); + } + + void arm() { + if (arm.isSelected()) { + fire.setEnabled(true); + start_arm_timer(); + if (!firing) + send_command("arm"); + armed = true; + } else + cancel(); + } + + void fire_more() { + if (firing) + send_command("fire"); + } + + void fire_down() { + if (arm.isEnabled() && arm.isSelected() && armed_count > 0) { + firing = true; + fire_more(); + fire_timer.restart(); + } + } + + void fire_up() { + firing = false; + fire_timer.stop(); + } + + void set_radio() { + try { + radio_channel = Integer.parseInt(radio_channel_text.getText()); + } catch (NumberFormatException ne) { + radio_channel_text.setText(String.format("%d", radio_channel)); + } + } + + void set_serial() { + try { + launcher_serial = Integer.parseInt(launcher_serial_text.getText()); + AltosPreferences.set_launcher_serial(launcher_serial); + send_command("set_remote"); + } catch (NumberFormatException ne) { + launcher_serial_text.setText(String.format("%d", launcher_serial)); + } + } + + void set_channel() { + try { + launcher_channel = Integer.parseInt(launcher_channel_text.getText()); + AltosPreferences.set_launcher_serial(launcher_channel); + send_command("set_remote"); + } catch (NumberFormatException ne) { + launcher_channel_text.setText(String.format("%d", launcher_channel)); + } + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + System.out.printf("cmd %s\n", cmd); + if (cmd.equals("armed") || cmd.equals("igniter")) { + stop_arm_timer(); + } + + if (cmd.equals("arm")) + arm(); + if (cmd.equals("tick_arm")) + tick_arm_timer(); + if (cmd.equals("close")) + close(); + if (cmd.equals("fire_down")) + fire_down(); + if (cmd.equals("fire_up")) + fire_up(); + if (cmd.equals("tick_fire")) + fire_more(); + if (cmd.equals("new_serial")) + set_serial(); + if (cmd.equals("new_channel")) + set_channel(); + } + + /* A window listener to catch closing events and tell the config code */ + class ConfigListener extends WindowAdapter { + AltosLaunchUI ui; + + public ConfigListener(AltosLaunchUI this_ui) { + ui = this_ui; + } + + public void windowClosing(WindowEvent e) { + ui.actionPerformed(new ActionEvent(e.getSource(), + ActionEvent.ACTION_PERFORMED, + "close")); + } + } + + private boolean open() { + command_queue = new LinkedBlockingQueue(); + + device = AltosDeviceDialog.show(owner, Altos.product_any); + if (device != null) { + LaunchHandler handler = new LaunchHandler(owner); + Thread t = new Thread(handler); + t.start(); + return true; + } + return false; + } + + public AltosLaunchUI(JFrame in_owner) { + + launcher_channel = AltosPreferences.launcher_channel(); + launcher_serial = AltosPreferences.launcher_serial(); + owner = in_owner; + armed_status = AltosLaunch.Unknown; + igniter_status = AltosLaunch.Unknown; + + if (!open()) + return; + + Container pane = getContentPane(); + GridBagConstraints c = new GridBagConstraints(); + Insets i = new Insets(4,4,4,4); + + arm_timer = new javax.swing.Timer(arm_timeout, this); + arm_timer.setActionCommand("tick_arm"); + arm_timer.restart(); + + fire_timer = new javax.swing.Timer(fire_timeout, this); + fire_timer.setActionCommand("tick_fire"); + + owner = in_owner; + + pane.setLayout(new GridBagLayout()); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = i; + c.weightx = 1; + c.weighty = 1; + + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 2; + c.anchor = GridBagConstraints.CENTER; + label = new JLabel ("Launch Controller"); + pane.add(label, c); + + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + launcher_serial_label = new JLabel("Launcher Serial"); + pane.add(launcher_serial_label, c); + + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + launcher_serial_text = new JTextField(7); + launcher_serial_text.setText(String.format("%d", launcher_serial)); + launcher_serial_text.setActionCommand("new_serial"); + launcher_serial_text.addActionListener(this); + pane.add(launcher_serial_text, c); + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + launcher_channel_label = new JLabel("Launcher Channel"); + pane.add(launcher_channel_label, c); + + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + launcher_channel_text = new JTextField(7); + launcher_channel_text.setText(String.format("%d", launcher_channel)); + launcher_channel_text.setActionCommand("new_channel"); + launcher_channel_text.addActionListener(this); + pane.add(launcher_channel_text, c); + + c.gridx = 0; + c.gridy = 3; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + armed_label = new JLabel ("Armed"); + pane.add(armed_label, c); + + c.gridx = 1; + c.gridy = 3; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + armed_status_label = new JLabel(); + pane.add(armed_status_label, c); + + c.gridx = 0; + c.gridy = 4; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + igniter = new JLabel ("Igniter"); + pane.add(igniter, c); + + c.gridx = 1; + c.gridy = 4; + c.gridwidth = 1; + c.anchor = GridBagConstraints.WEST; + igniter_status_label = new JLabel(); + pane.add(igniter_status_label, c); + + c.gridx = 0; + c.gridy = 5; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + arm = new JToggleButton ("Arm"); + pane.add(arm, c); + arm.addActionListener(this); + arm.setActionCommand("arm"); + arm.setEnabled(true); + + c.gridx = 1; + c.gridy = 5; + c.gridwidth = 1; + c.anchor = GridBagConstraints.CENTER; + fire = new FireButton ("Fire"); + fire.setEnabled(false); + pane.add(fire, c); + fire.addActionListener(this); + fire.setActionCommand("fire"); + + pack(); + setLocationRelativeTo(owner); + + addWindowListener(new ConfigListener(this)); + + setVisible(true); + } +} \ No newline at end of file diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index 716559ab..48aed441 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -58,6 +58,12 @@ class AltosPreferences { /* font size preferences name */ final static String fontSizePreference = "FONT-SIZE"; + /* Launcher serial preference name */ + final static String launcherSerialPreference = "LAUNCHER-SERIAL"; + + /* Launcher channel prefernce name */ + final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; + /* Default logdir is ~/TeleMetrum */ final static String logdirName = "TeleMetrum"; @@ -143,6 +149,9 @@ class AltosPreferences { node.put(String.format(description_format, i), frequencies[i].description); } } + static int launcher_serial; + + static int launcher_channel; public static void init() { preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); @@ -176,6 +185,10 @@ class AltosPreferences { font_size = preferences.getInt(fontSizePreference, Altos.font_size_medium); Altos.set_fonts(font_size); + launcher_serial = preferences.getInt(launcherSerialPreference, 0); + + launcher_channel = preferences.getInt(launcherChannelPreference, 0); + String firmwaredir_string = preferences.get(firmwaredirPreference, null); if (firmwaredir_string != null) firmwaredir = new File(firmwaredir_string); @@ -390,6 +403,32 @@ class AltosPreferences { return serial_debug; } + public static void set_launcher_serial(int new_launcher_serial) { + launcher_serial = new_launcher_serial; + System.out.printf("set launcher serial to %d\n", new_launcher_serial); + synchronized (preferences) { + preferences.putInt(launcherSerialPreference, launcher_serial); + flush_preferences(); + } + } + + public static int launcher_serial() { + return launcher_serial; + } + + public static void set_launcher_channel(int new_launcher_channel) { + launcher_channel = new_launcher_channel; + System.out.printf("set launcher channel to %d\n", new_launcher_channel); + synchronized (preferences) { + preferences.putInt(launcherChannelPreference, launcher_channel); + flush_preferences(); + } + } + + public static int launcher_channel() { + return launcher_channel; + } + public static Preferences bt_devices() { return preferences.node("bt_devices"); } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index ba1c830c..e2e42d84 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -68,6 +68,8 @@ altosui_JAVA = \ AltosIdleMonitorUI.java \ AltosIgnite.java \ AltosIgniteUI.java \ + AltosLaunch.java \ + AltosLaunchUI.java \ AltosInfoTable.java \ AltosKML.java \ AltosLanded.java \ diff --git a/src/ao_radio_cmac.c b/src/ao_radio_cmac.c index c2757b16..41fbbe1f 100644 --- a/src/ao_radio_cmac.c +++ b/src/ao_radio_cmac.c @@ -21,6 +21,7 @@ #define AO_CMAC_MAX_LEN (128 - AO_CMAC_KEY_LEN) static __xdata uint8_t ao_radio_cmac_mutex; +__pdata int16_t ao_radio_cmac_rssi; static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN]; static __pdata uint8_t ao_radio_cmac_len; @@ -114,9 +115,12 @@ radio_cmac_recv(uint8_t len, uint16_t timeout) __reentrant i = ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2); ao_clear_alarm(); - if (!i) + if (!i) { + ao_radio_cmac_rssi = 0; return AO_RADIO_CMAC_TIMEOUT; + } + ao_radio_cmac_rssi = (int16_t) (((int8_t) cmac_data[len + AO_CMAC_KEY_LEN]) >> 1) - 74; if (!(cmac_data[len + AO_CMAC_KEY_LEN +1] & PKT_APPEND_STATUS_1_CRC_OK)) return AO_RADIO_CMAC_CRC_ERROR; @@ -221,33 +225,46 @@ radio_cmac_recv_cmd(void) __reentrant printf ("PACKET "); for (i = 0; i < len; i++) printf("%02x", cmac_data[i]); - printf ("\n"); + printf (" %d\n", ao_radio_cmac_rssi); } else - printf ("ERROR %d\n", i); + printf ("ERROR %d %d\n", i, ao_radio_cmac_rssi); ao_mutex_put(&ao_radio_cmac_mutex); } static __xdata struct ao_launch_command command; static __xdata struct ao_launch_query query; +static pdata uint16_t launch_serial; +static pdata uint8_t launch_channel; +static pdata uint16_t tick_offset; +static void +launch_args(void) __reentrant +{ + ao_cmd_decimal(); + launch_serial = ao_cmd_lex_i; + ao_cmd_decimal(); + launch_channel = ao_cmd_lex_i; +} static int8_t -launch_query(uint16_t serial, uint8_t channel) +launch_query(void) { uint8_t i; int8_t r = AO_RADIO_CMAC_OK; + tick_offset = ao_time(); for (i = 0; i < 10; i++) { printf ("."); flush(); command.tick = ao_time(); - command.serial = serial; + command.serial = launch_serial; command.cmd = AO_LAUNCH_QUERY; - command.channel = channel; + command.channel = launch_channel; ao_radio_cmac_send(&command, sizeof (command)); r = ao_radio_cmac_recv(&query, sizeof (query), AO_MS_TO_TICKS(500)); if (r == AO_RADIO_CMAC_OK) break; } + tick_offset -= query.tick; printf("\n"); flush(); return r; } @@ -255,17 +272,12 @@ launch_query(uint16_t serial, uint8_t channel) static void launch_report_cmd(void) __reentrant { - uint8_t channel; - uint16_t serial; int8_t r; - ao_cmd_decimal(); - serial = ao_cmd_lex_i; - ao_cmd_decimal(); - channel = ao_cmd_lex_i; + launch_args(); if (ao_cmd_status != ao_cmd_success) return; - r = launch_query(serial, channel); + r = launch_query(); switch (r) { case AO_RADIO_CMAC_OK: if (query.valid) { @@ -273,24 +285,25 @@ launch_report_cmd(void) __reentrant case ao_igniter_ready: case ao_igniter_active: printf ("Armed: "); - switch (query.igniter_status) { - default: - printf("unknown status\n"); - break; - case ao_igniter_ready: - printf("igniter good\n"); - break; - case ao_igniter_open: - printf("igniter bad\n"); - break; - } break; default: - printf("Disarmed\n"); + printf("Disarmed: "); + } + switch (query.igniter_status) { + default: + printf("unknown\n"); + break; + case ao_igniter_ready: + printf("igniter good\n"); + break; + case ao_igniter_open: + printf("igniter bad\n"); + break; } } else { - printf("Invalid channel %d\n", channel); + printf("Invalid channel %d\n", launch_channel); } + printf("Rssi: %d\n", ao_radio_cmac_rssi); break; default: printf("Error %d\n", r); @@ -298,56 +311,91 @@ launch_report_cmd(void) __reentrant } } +static void +launch_arm(void) __reentrant +{ + command.tick = ao_time() - tick_offset; + command.serial = launch_serial; + command.cmd = AO_LAUNCH_ARM; + command.channel = launch_channel; + ao_radio_cmac_send(&command, sizeof (command)); +} + +static void +launch_ignite(void) __reentrant +{ + command.tick = ao_time() - tick_offset; + command.serial = launch_serial; + command.cmd = AO_LAUNCH_FIRE; + command.channel = 0; + ao_radio_cmac_send(&command, sizeof (command)); +} + static void launch_fire_cmd(void) __reentrant { static __xdata struct ao_launch_command command; - uint8_t channel; - uint16_t serial; uint8_t secs; uint8_t i; int8_t r; - uint16_t tick_offset; - ao_cmd_decimal(); - serial = ao_cmd_lex_i; - ao_cmd_decimal(); - channel = ao_cmd_lex_i; + launch_args(); ao_cmd_decimal(); secs = ao_cmd_lex_i; if (ao_cmd_status != ao_cmd_success) return; - tick_offset = ao_time(); - r = launch_query(serial, channel); - tick_offset -= query.tick; + r = launch_query(); + if (r != AO_RADIO_CMAC_OK) { + printf("query failed %d\n", r); + return; + } for (i = 0; i < 4; i++) { printf("arm %d\n", i); flush(); - command.tick = ao_time() - tick_offset; - command.serial = serial; - command.cmd = AO_LAUNCH_ARM; - command.channel = channel; - ao_radio_cmac_send(&command, sizeof (command)); + launch_arm(); } + secs = secs * 10 - 5; if (secs > 100) secs = 100; for (i = 0; i < secs; i++) { printf("fire %d\n", i); flush(); - command.tick = ao_time() - tick_offset; - command.serial = serial; - command.cmd = AO_LAUNCH_FIRE; - command.channel = 0; - ao_radio_cmac_send(&command, sizeof (command)); + launch_ignite(); ao_delay(AO_MS_TO_TICKS(100)); } } +static void +launch_arm_cmd(void) __reentrant +{ + uint8_t i; + int8_t r; + launch_args(); + r = launch_query(); + if (r != AO_RADIO_CMAC_OK) { + printf("query failed %d\n", r); + return; + } + for (i = 0; i < 4; i++) + launch_arm(); +} + +static void +launch_ignite_cmd(void) __reentrant +{ + uint8_t i; + launch_args(); + for (i = 0; i < 4; i++) + launch_ignite(); +} + static __code struct ao_cmds ao_radio_cmac_cmds[] = { { radio_cmac_send_cmd, "s \0Send AES-CMAC packet. Bytes to send follow on next line" }, { radio_cmac_recv_cmd, "S \0Receive AES-CMAC packet. Timeout in ms" }, { launch_report_cmd, "l \0Get remote launch status" }, { launch_fire_cmd, "f \0Fire remote igniter" }, + { launch_arm_cmd, "a \0Arm remote igniter" }, + { launch_ignite_cmd, "i \0Pulse remote igniter" }, { 0, NULL }, }; -- cgit v1.2.3 From 02df2141e5a67afc16acd01a6c60f3cc61052b93 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 1 Aug 2011 22:45:43 -0700 Subject: altosui: Hook up the launch controller UI from the main button box Provide a button to start the launch controller UI. Signed-off-by: Keith Packard --- altosui/AltosUI.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 27c41838..8399b7c8 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -210,6 +210,13 @@ public class AltosUI extends JFrame { }); b.setToolTipText("Check flight readiness of altimeter in idle mode"); + b = addButton(2, 2, "Launch Controller"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + LaunchController(); + } + }); + setTitle("AltOS"); pane.doLayout(); @@ -272,6 +279,10 @@ public class AltosUI extends JFrame { new AltosSiteMapPreload(AltosUI.this); } + void LaunchController() { + new AltosLaunchUI(AltosUI.this); + } + /* * Replay a flight from telemetry data */ -- cgit v1.2.3 From 7e2b5e2957ddcb808723081ca7e046a28b7e70e5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 27 Aug 2011 13:30:34 -0700 Subject: altosui: launch controller button needs to move over monitor idle was inserted into position 2,2 Signed-off-by: Keith Packard --- altosui/AltosUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 8399b7c8..60adfc7c 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -210,7 +210,7 @@ public class AltosUI extends JFrame { }); b.setToolTipText("Check flight readiness of altimeter in idle mode"); - b = addButton(2, 2, "Launch Controller"); + b = addButton(3, 2, "Launch Controller"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { LaunchController(); -- cgit v1.2.3 From cf72c2f5a69a736c28a9b63e124d510ef41a9f5d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 28 Aug 2011 15:50:01 -0700 Subject: altosui: Add bluetooth bits back in Stub out functions on mac/windows for now. Signed-off-by: Keith Packard --- altosui/Altos.java | 2 +- altosui/AltosConfigureUI.java | 33 ++++++++---------- altosui/AltosDeviceDialog.java | 36 ++++++++----------- altosui/Makefile.am | 3 +- altosui/libaltos/libaltos.c | 78 ++++++++++++++++++++++++++++++++++++++++-- altosui/libaltos/libaltos.h | 5 --- 6 files changed, 109 insertions(+), 48 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index e4f974f9..aa2fd77a 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -498,5 +498,5 @@ public class Altos { public final static String bt_product_telebt = bt_product_telebt(); -// public static AltosBTKnown bt_known = new AltosBTKnown(); + public static AltosBTKnown bt_known = new AltosBTKnown(); } diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index bcb9636b..980068c0 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -52,8 +52,7 @@ public class AltosConfigureUI JRadioButton serial_debug; -// BLUETOOTH -// JButton manage_bluetooth; + JButton manage_bluetooth; JButton manage_frequencies; final static String[] font_size_names = { "Small", "Medium", "Large" }; @@ -241,19 +240,18 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.WEST; pane.add(serial_debug, c); -// BLUETOOTH -// manage_bluetooth = new JButton("Manage Bluetooth"); -// manage_bluetooth.addActionListener(new ActionListener() { -// public void actionPerformed(ActionEvent e) { -// AltosBTManage.show(owner, Altos.bt_known); -// } -// }); -// c.gridx = 0; -// c.gridy = row++; -// c.gridwidth = 2; -// c.fill = GridBagConstraints.NONE; -// c.anchor = GridBagConstraints.WEST; -// pane.add(manage_bluetooth, c); + manage_bluetooth = new JButton("Manage Bluetooth"); + manage_bluetooth.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + AltosBTManage.show(owner, Altos.bt_known); + } + }); + c.gridx = 0; + c.gridy = row; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + pane.add(manage_bluetooth, c); manage_frequencies = new JButton("Manage Frequencies"); manage_frequencies.addActionListener(new ActionListener() { @@ -262,9 +260,8 @@ public class AltosConfigureUI } }); manage_frequencies.setToolTipText("Configure which values are shown in frequency menus"); -// BLUETOOTH -// c.gridx = 2; - c.gridx = 1; + c.gridx = 2; + c.gridx = 2; c.gridy = row++; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index fa9587bc..610bb73e 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -30,8 +30,7 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { private JList list; private JButton cancel_button; private JButton select_button; -// BLUETOOTH -// private JButton manage_bluetooth_button; + private JButton manage_bluetooth_button; private Frame frame; private int product; @@ -42,17 +41,15 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { private AltosDevice[] devices() { java.util.List usb_devices = AltosUSBDevice.list(product); int num_devices = usb_devices.size(); -// BLUETOOTH -// java.util.List bt_devices = Altos.bt_known.list(product); -// num_devices += bt_devices.size(); + java.util.List bt_devices = Altos.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); -// BLUETOOTH -// int off = usb_devices.size(); -// for (int j = 0; j < bt_devices.size(); j++) -// devices[off + j] = bt_devices.get(j); + int off = usb_devices.size(); + for (int j = 0; j < bt_devices.size(); j++) + devices[off + j] = bt_devices.get(j); return devices; } @@ -75,10 +72,9 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { cancel_button.setActionCommand("cancel"); cancel_button.addActionListener(this); -// BLUETOOTH -// manage_bluetooth_button = new JButton("Manage Bluetooth"); -// manage_bluetooth_button.setActionCommand("manage"); -// manage_bluetooth_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"); @@ -152,8 +148,7 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { buttonPane.add(Box.createHorizontalGlue()); buttonPane.add(cancel_button); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); -// BLUETOOTH -// buttonPane.add(manage_bluetooth_button); + buttonPane.add(manage_bluetooth_button); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); buttonPane.add(select_button); @@ -173,12 +168,11 @@ public class AltosDeviceDialog extends JDialog implements ActionListener { public void actionPerformed(ActionEvent e) { if ("select".equals(e.getActionCommand())) value = (AltosDevice)(list.getSelectedValue()); -// BLUETOOTH -// if ("manage".equals(e.getActionCommand())) { -// AltosBTManage.show(frame, Altos.bt_known); -// update_devices(); -// return; -// } + if ("manage".equals(e.getActionCommand())) { + AltosBTManage.show(frame, Altos.bt_known); + update_devices(); + return; + } setVisible(false); } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index e2e42d84..c4d1e611 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -118,7 +118,8 @@ altosui_JAVA = \ AltosGraphUI.java \ AltosDataChooser.java \ AltosVersion.java \ - AltosVoice.java + AltosVoice.java \ + $(altosui_BT) JFREECHART_CLASS= \ jfreechart.jar diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index d1f445bd..a3796ee3 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -598,7 +598,6 @@ altos_list_finish(struct altos_list *usbdevs) free(usbdevs); } -#if HAS_BLUETOOTH struct altos_bt_list { inquiry_info *ii; int sock; @@ -730,7 +729,6 @@ no_sock: no_file: return NULL; } -#endif /* HAS_BLUETOOTH */ #endif @@ -844,6 +842,48 @@ altos_list_finish(struct altos_list *list) 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 @@ -1180,4 +1220,38 @@ altos_getchar(struct altos_file *file, int timeout) 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.h b/altosui/libaltos/libaltos.h index 363a84fd..a05bed4c 100644 --- a/altosui/libaltos/libaltos.h +++ b/altosui/libaltos/libaltos.h @@ -93,9 +93,6 @@ altos_flush(struct altos_file *file); PUBLIC int altos_getchar(struct altos_file *file, int timeout); -// #define HAS_BLUETOOTH 1 -#if HAS_BLUETOOTH - PUBLIC struct altos_bt_list * altos_bt_list_start(int inquiry_time); @@ -111,6 +108,4 @@ 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 - #endif /* _LIBALTOS_H_ */ -- cgit v1.2.3 From 31e3255b6cbfaf95c0e97e2d1ec8de72f845994c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 28 Aug 2011 15:50:30 -0700 Subject: altosui: Report error message back from libaltos This includes changing all of the error dialogs to show the error message rather than just the file name. Signed-off-by: Keith Packard --- altosui/AltosBTDevice.java | 7 +++ altosui/AltosCSVUI.java | 2 +- altosui/AltosConfig.java | 3 +- altosui/AltosDataChooser.java | 2 +- altosui/AltosDevice.java | 1 + altosui/AltosEepromDownload.java | 12 +++-- altosui/AltosEepromManage.java | 3 +- altosui/AltosFlashUI.java | 4 +- altosui/AltosIgniteUI.java | 3 +- altosui/AltosLanded.java | 4 +- altosui/AltosLaunchUI.java | 3 +- altosui/AltosScanUI.java | 6 +-- altosui/AltosSerial.java | 4 +- altosui/AltosUI.java | 9 ++-- altosui/AltosUSBDevice.java | 7 +++ altosui/libaltos/libaltos.c | 97 +++++++++++++++++++++++++++++++++------- altosui/libaltos/libaltos.h | 8 ++++ 17 files changed, 131 insertions(+), 44 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index 7a876c25..55b8f8fc 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -42,6 +42,13 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { return getAddr(); } + 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 int getSerial() { String name = getName(); if (name == null) diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java index e1b6002d..a212409e 100644 --- a/altosui/AltosCSVUI.java +++ b/altosui/AltosCSVUI.java @@ -99,7 +99,7 @@ public class AltosCSVUI writer.close(); } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(frame, - file.getName(), + ee.getMessage(), "Cannot open file", JOptionPane.ERROR_MESSAGE); } diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 122ebecc..93def70d 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -480,8 +480,7 @@ public class AltosConfig implements ActionListener { } } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(owner, - String.format("Cannot open device \"%s\"", - device.toShortString()), + ee.getMessage(), "Cannot open target device", JOptionPane.ERROR_MESSAGE); } catch (AltosSerialInUseException si) { diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index 15de05c2..d81ca6d1 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -61,7 +61,7 @@ public class AltosDataChooser extends JFileChooser { } } catch (FileNotFoundException fe) { JOptionPane.showMessageDialog(frame, - filename, + fe.getMessage(), "Cannot open file", JOptionPane.ERROR_MESSAGE); } diff --git a/altosui/AltosDevice.java b/altosui/AltosDevice.java index 3357c550..1b5c1a91 100644 --- a/altosui/AltosDevice.java +++ b/altosui/AltosDevice.java @@ -26,5 +26,6 @@ public interface AltosDevice { public abstract int getSerial(); public abstract String getPath(); public abstract boolean matchProduct(int product); + public abstract String getErrorString(); public SWIGTYPE_p_altos_file open(); } diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 358ad337..e7e52466 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -248,6 +248,10 @@ public class AltosEepromDownload implements Runnable { done = true; } + void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException { + + } + void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException { int block, state_block = 0; int log_format = flights.config_data.log_format; @@ -300,10 +304,10 @@ public class AltosEepromDownload implements Runnable { extension = "eeprom"; CaptureTiny(eechunk); break; -// case Altos.AO_LOG_FORMAT_TELEMETRY: -// extension = "telem"; -// CaptureTelemetry(eechunk); -// break; + case Altos.AO_LOG_FORMAT_TELEMETRY: + extension = "telem"; + CaptureTelemetry(eechunk); + break; case Altos.AO_LOG_FORMAT_TELESCIENCE: extension = "science"; CaptureTeleScience(eechunk); diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index 2e520628..083c7372 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -219,8 +219,7 @@ public class AltosEepromManage implements ActionListener { t.start(); } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(frame, - String.format("Cannot open device \"%s\"", - device.toShortString()), + ee.getMessage(), "Cannot open target device", JOptionPane.ERROR_MESSAGE); } catch (AltosSerialInUseException si) { diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 3874b500..3956ff20 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -200,8 +200,8 @@ public class AltosFlashUI void exception (Exception e) { if (e instanceof FileNotFoundException) { JOptionPane.showMessageDialog(frame, - "Cannot open image", - file.toString(), + ((FileNotFoundException) e).getMessage(), + "Cannot open file", JOptionPane.ERROR_MESSAGE); } else if (e instanceof AltosSerialInUseException) { JOptionPane.showMessageDialog(frame, diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index c11a8614..b215c228 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -122,8 +122,7 @@ public class AltosIgniteUI void ignite_exception(Exception e) { if (e instanceof FileNotFoundException) { JOptionPane.showMessageDialog(owner, - String.format("Cannot open device \"%s\"", - device.toShortString()), + ((FileNotFoundException) e).getMessage(), "Cannot open target device", JOptionPane.ERROR_MESSAGE); } else if (e instanceof AltosSerialInUseException) { diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 50e6b542..4dd9a2dd 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -250,7 +250,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio FileInputStream in = new FileInputStream(file); records = new AltosTelemetryIterable(in); } else { - throw new FileNotFoundException(); + throw new FileNotFoundException(filename); } try { new AltosGraphUI(records, filename); @@ -259,7 +259,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio } } catch (FileNotFoundException fe) { JOptionPane.showMessageDialog(null, - filename, + fe.getMessage(), "Cannot open file", JOptionPane.ERROR_MESSAGE); } diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index 4e630afb..47365e03 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -164,8 +164,7 @@ public class AltosLaunchUI void launch_exception(Exception e) { if (e instanceof FileNotFoundException) { JOptionPane.showMessageDialog(owner, - String.format("Cannot open device \"%s\"", - device.toShortString()), + ((FileNotFoundException) e).getMessage(), "Cannot open target device", JOptionPane.ERROR_MESSAGE); } else if (e instanceof AltosSerialInUseException) { diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index bce4b32c..df5c51d4 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -130,8 +130,7 @@ public class AltosScanUI void scan_exception(Exception e) { if (e instanceof FileNotFoundException) { JOptionPane.showMessageDialog(owner, - String.format("Cannot open device \"%s\"", - device.toShortString()), + ((FileNotFoundException) e).getMessage(), "Cannot open target device", JOptionPane.ERROR_MESSAGE); } else if (e instanceof AltosSerialInUseException) { @@ -326,8 +325,7 @@ public class AltosScanUI return true; } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(owner, - String.format("Cannot open device \"%s\"", - device.toShortString()), + ee.getMessage(), "Cannot open target device", JOptionPane.ERROR_MESSAGE); } catch (AltosSerialInUseException si) { diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 0a531aa9..4cf306d0 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -323,8 +323,10 @@ public class AltosSerial implements Runnable { } altos = device.open(); if (altos == null) { + final String message = device.getErrorString(); close(); - throw new FileNotFoundException(device.toShortString()); + throw new FileNotFoundException(String.format("%s (%s)", + device.toShortString(), message)); } if (debug) System.out.printf("Open %s\n", device.getPath()); diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 60adfc7c..3e5bcf43 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -52,8 +52,7 @@ public class AltosUI extends JFrame { new AltosFlightUI(voice, reader, device.getSerial()); } catch (FileNotFoundException ee) { JOptionPane.showMessageDialog(AltosUI.this, - String.format("Cannot open device \"%s\"", - device.toShortString()), + ee.getMessage(), "Cannot open target device", JOptionPane.ERROR_MESSAGE); } catch (AltosSerialInUseException si) { @@ -356,7 +355,7 @@ public class AltosUI extends JFrame { else return new AltosTelemetryIterable(in); } catch (FileNotFoundException fe) { - System.out.printf("Cannot open '%s'\n", filename); + System.out.printf("%s\n", fe.getMessage()); return null; } } @@ -366,7 +365,7 @@ public class AltosUI extends JFrame { try { return new AltosCSV(file); } catch (FileNotFoundException fe) { - System.out.printf("Cannot open '%s'\n", filename); + System.out.printf("%s\n", fe.getMessage()); return null; } } @@ -376,7 +375,7 @@ public class AltosUI extends JFrame { try { return new AltosKML(file); } catch (FileNotFoundException fe) { - System.out.printf("Cannot open '%s'\n", filename); + System.out.printf("%s\n", fe.getMessage()); return null; } } diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java index dc746a64..b11a3934 100644 --- a/altosui/AltosUSBDevice.java +++ b/altosui/AltosUSBDevice.java @@ -39,6 +39,13 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { } + 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); } diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index a3796ee3..48e00a44 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -49,6 +49,22 @@ 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 @@ -96,6 +112,12 @@ struct altos_file { 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) { @@ -103,12 +125,18 @@ altos_open(struct altos_device *device) int ret; struct termios term; - if (!file) + 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) { - perror(device->path); + altos_set_last_posix_error(); free(file); return NULL; } @@ -117,7 +145,7 @@ altos_open(struct altos_device *device) #else file->out_fd = open(device->path, O_RDWR | O_NOCTTY); if (file->out_fd < 0) { - perror(device->path); + altos_set_last_posix_error(); close(file->fd); free(file); return NULL; @@ -125,7 +153,7 @@ altos_open(struct altos_device *device) #endif ret = tcgetattr(file->fd, &term); if (ret < 0) { - perror("tcgetattr"); + altos_set_last_posix_error(); close(file->fd); #ifndef USE_POLL close(file->out_fd); @@ -143,7 +171,7 @@ altos_open(struct altos_device *device) #endif ret = tcsetattr(file->fd, TCSAFLUSH, &term); if (ret < 0) { - perror("tcsetattr"); + altos_set_last_posix_error(); close(file->fd); #ifndef USE_POLL close(file->out_fd); @@ -195,8 +223,10 @@ altos_flush(struct altos_file *file) #else ret = write (file->out_fd, file->out_data, file->out_used); #endif - if (ret < 0) + if (ret < 0) { + altos_set_last_posix_error(); return -errno; + } if (ret) { memmove(file->out_data, file->out_data + ret, file->out_used - ret); @@ -248,7 +278,7 @@ altos_fill(struct altos_file *file, int timeout) fd[1].events = POLLIN; ret = poll(fd, 2, timeout); if (ret < 0) { - perror("altos_getchar"); + altos_set_last_posix_error(); return LIBALTOS_ERROR; } if (ret == 0) @@ -261,7 +291,7 @@ altos_fill(struct altos_file *file, int timeout) { ret = read(file->fd, file->in_data, USB_BUF_SIZE); if (ret < 0) { - perror("altos_getchar"); + altos_set_last_posix_error(); return LIBALTOS_ERROR; } file->in_read = 0; @@ -700,8 +730,10 @@ altos_bt_open(struct altos_bt_device *device) if (!file) goto no_file; file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (file->fd < 0) + if (file->fd < 0) { + altos_set_last_posix_error(); goto no_sock; + } addr.rc_family = AF_BLUETOOTH; addr.rc_channel = 1; @@ -711,7 +743,7 @@ altos_bt_open(struct altos_bt_device *device) (struct sockaddr *)&addr, sizeof(addr)); if (status < 0) { - perror("connect"); + altos_set_last_posix_error(); goto no_link; } sleep(1); @@ -912,6 +944,21 @@ struct altos_file { OVERLAPPED ov_write; }; +static void +altos_set_last_windows_error(void) +{ + DWORD error = GetLastError(); + TCHAR message[1024]; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + 0, + error, + 0, + message, + sizeof (message) / sizeof (TCHAR), + NULL); + altos_set_last_error(error, message); +} + PUBLIC struct altos_list * altos_list_start(void) { @@ -922,7 +969,7 @@ altos_list_start(void) list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_ALLCLASSES|DIGCF_PRESENT); if (list->dev_info == INVALID_HANDLE_VALUE) { - printf("SetupDiGetClassDevs failed %ld\n", GetLastError()); + altos_set_last_windows_error(); free(list); return NULL; } @@ -956,6 +1003,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device) 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; } @@ -966,6 +1014,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device) 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; @@ -988,6 +1037,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device) port, &port_len); RegCloseKey(dev_key); if (result != 0) { + altos_set_last_windows_error(); printf("failed to get PortName\n"); continue; } @@ -1003,6 +1053,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device) sizeof(friendlyname), &friendlyname_len)) { + altos_set_last_windows_error(); printf("Failed to get friendlyname\n"); continue; } @@ -1015,8 +1066,10 @@ altos_list_next(struct altos_list *list, struct altos_device *device) return 1; } result = GetLastError(); - if (result != ERROR_NO_MORE_ITEMS) + if (result != ERROR_NO_MORE_ITEMS) { + altos_set_last_windows_error(); printf ("SetupDiEnumDeviceInfo failed error %d\n", (int) result); + } return 0; } @@ -1035,8 +1088,10 @@ altos_queue_read(struct altos_file *file) return LIBALTOS_SUCCESS; if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) { - if (GetLastError() != ERROR_IO_PENDING) + if (GetLastError() != ERROR_IO_PENDING) { + altos_set_last_windows_error(); return LIBALTOS_ERROR; + } file->pend_read = TRUE; } else { file->pend_read = FALSE; @@ -1061,8 +1116,10 @@ altos_wait_read(struct altos_file *file, int timeout) ret = WaitForSingleObject(file->ov_read.hEvent, timeout); switch (ret) { case WAIT_OBJECT_0: - if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE)) + 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; @@ -1106,15 +1163,20 @@ altos_flush(struct altos_file *file) while (used) { if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) { - if (GetLastError() != ERROR_IO_PENDING) + if (GetLastError() != ERROR_IO_PENDING) { + altos_set_last_windows_error(); 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)) + if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE)) { + altos_set_last_windows_error(); return LIBALTOS_ERROR; + } break; default: + altos_set_last_windows_error(); return LIBALTOS_ERROR; } } @@ -1142,6 +1204,7 @@ altos_open(struct altos_device *device) 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (file->handle == INVALID_HANDLE_VALUE) { + altos_set_last_windows_error(); free(file); return NULL; } @@ -1157,6 +1220,7 @@ altos_open(struct altos_device *device) dcbSerialParams.DCBlength = sizeof(dcbSerialParams); if (!GetCommState(file->handle, &dcbSerialParams)) { + altos_set_last_windows_error(); CloseHandle(file->handle); free(file); return NULL; @@ -1166,6 +1230,7 @@ altos_open(struct altos_device *device) dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; if (!SetCommState(file->handle, &dcbSerialParams)) { + altos_set_last_windows_error(); CloseHandle(file->handle); free(file); return NULL; diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h index a05bed4c..f90fbb87 100644 --- a/altosui/libaltos/libaltos.h +++ b/altosui/libaltos/libaltos.h @@ -51,6 +51,11 @@ struct altos_bt_device { //%mutable; }; +struct altos_error { + int code; + char string[1024]; +}; + #define LIBALTOS_SUCCESS 0 #define LIBALTOS_ERROR -1 #define LIBALTOS_TIMEOUT -2 @@ -62,6 +67,9 @@ 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); -- cgit v1.2.3 From f9b0b7423c0640f729d61a91de6ff96ffe4b486e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 8 Oct 2011 11:43:37 -0600 Subject: altosui: Max acceleration across boost instead of all ascent This ignores ejection bumps, making the max acceleration far more useful. Signed-off-by: Keith Packard --- altosui/AltosFlightStatsTable.java | 2 +- altosui/AltosState.java | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index 3fecf921..2d34c6e2 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -86,7 +86,7 @@ public class AltosFlightStatsTable extends JComponent { String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.max_speed)), String.format("Mach %5.3f", AltosConvert.meters_to_mach(stats.max_speed))); if (stats.max_acceleration != AltosRecord.MISSING) { - new FlightStat(layout, y++, "Maximum acceleration", + new FlightStat(layout, y++, "Maximum boost acceleration", String.format("%5.0f m/s²", stats.max_acceleration), String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), String.format("%5.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); diff --git a/altosui/AltosState.java b/altosui/AltosState.java index 072cb790..3d8e5e12 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -35,6 +35,7 @@ public class AltosState { int state; boolean landed; boolean ascent; /* going up? */ + boolean boost; /* under power */ double ground_altitude; double height; @@ -166,13 +167,14 @@ public class AltosState { ascent = (Altos.ao_flight_boost <= state && state <= Altos.ao_flight_coast); + boost = (Altos.ao_flight_boost == state); - /* Only look at accelerometer data on the way up */ - if (ascent && acceleration > max_acceleration) + /* Only look at accelerometer data under boost */ + if (boost && acceleration > max_acceleration) max_acceleration = acceleration; - if (ascent && speed > max_speed) + if (boost && speed > max_speed) max_speed = speed; - if (ascent && baro_speed > max_baro_speed) + if (boost && baro_speed > max_baro_speed) max_baro_speed = baro_speed; if (height > max_height) -- cgit v1.2.3 From cbf5a649c8b7101bef9d57e48e42ac775e758c79 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 8 Oct 2011 11:46:38 -0600 Subject: altosui: Allow for multiple instances of each state in the graph With the new boost re-detect code, we can get multiple instances of boost/fast/coast, so make sure each are displayed in the graph. Signed-off-by: Keith Packard --- altosui/AltosGraphTime.java | 31 +++++++++++++++++-------------- altosui/AltosGraphUI.java | 6 ++++-- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosGraphTime.java b/altosui/AltosGraphTime.java index ada6ef13..6a084b2c 100644 --- a/altosui/AltosGraphTime.java +++ b/altosui/AltosGraphTime.java @@ -4,6 +4,11 @@ package altosui; +import java.lang.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import java.text.*; import java.awt.Color; import java.util.ArrayList; import java.util.HashMap; @@ -98,9 +103,10 @@ class AltosGraphTime extends AltosGraph { } static class StateMarker implements Element { - private double val = Double.NaN; + private LinkedList times = new LinkedList(); private String name; private int state; + private int prev_state = Altos.ao_flight_startup; StateMarker(int state, String name) { this.state = state; @@ -109,22 +115,19 @@ class AltosGraphTime extends AltosGraph { public void attachGraph(AltosGraphTime g) { return; } public void gotTimeData(double time, AltosDataPoint d) { - if (Double.isNaN(val) || time < val) { - if (d.state() == state) { - val = time; - } - } + if (prev_state != state && d.state() == state) + times.add(time); + prev_state = d.state(); } public void addToPlot(AltosGraphTime g, XYPlot plot) { - if (Double.isNaN(val)) - return; - - ValueMarker m = new ValueMarker(val); - m.setLabel(name); - m.setLabelAnchor(RectangleAnchor.TOP_RIGHT); - m.setLabelTextAnchor(TextAnchor.TOP_LEFT); - plot.addDomainMarker(m); + for (double time : times) { + ValueMarker m = new ValueMarker(time); + m.setLabel(name); + m.setLabelAnchor(RectangleAnchor.TOP_RIGHT); + m.setLabelTextAnchor(TextAnchor.TOP_LEFT); + plot.addDomainMarker(m); + } } } diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index be52bd4e..030bbc25 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -109,6 +109,8 @@ public class AltosGraphUI extends JFrame protected AltosGraphTime myAltosGraphTime(String suffix) { return (new AltosGraphTime("Overall " + suffix)) .addElement(e_boost) + .addElement(e_fast) + .addElement(e_coast) .addElement(e_drogue) .addElement(e_main) .addElement(e_landed); @@ -238,8 +240,8 @@ public class AltosGraphUI extends JFrame { ArrayList graph = new ArrayList(); graph.addAll((new OverallGraphs()).graphs()); - graph.addAll((new AscentGraphs()).graphs()); - graph.addAll((new DescentGraphs()).graphs()); +// graph.addAll((new AscentGraphs()).graphs()); +// graph.addAll((new DescentGraphs()).graphs()); if (which > 0) { if (which >= graph.size()) { -- cgit v1.2.3 From aad03e3cab4c328e53d3df47b6dac1d3f7a49229 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 8 Oct 2011 16:07:57 -0600 Subject: altosui: Remove igniter voltages from chart. These are just annoying; when we add the ability to turn stuff on/off on the fly, we can add them to the list of available items. Signed-off-by: Keith Packard --- altosui/AltosGraphUI.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 030bbc25..59e92499 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -122,9 +122,7 @@ public class AltosGraphUI extends JFrame graphs.add( myAltosGraphTime("Summary") .addElement(height) .addElement(speed) - .addElement(acceleration) - .addElement(drogue_voltage) - .addElement(main_voltage) ); + .addElement(acceleration) ); graphs.add( myAltosGraphTime("Summary") .addElement(height) -- cgit v1.2.3 From 5c82b07471f017171c58a6968adf79901f46a987 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Oct 2011 10:55:04 -0600 Subject: altosui: Deal with telem data that goes backwards in time The new telemetry stuff can send packets with older timestamps, so sort telem packets read from disk to create an in-order record of the flight. Signed-off-by: Keith Packard --- altosui/AltosRecord.java | 6 +++++- altosui/AltosTelemetryIterable.java | 8 ++++---- altosui/AltosTelemetryRecordRaw.java | 6 ++---- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index ce6d86ab..486c96b2 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -22,7 +22,7 @@ import java.text.*; import java.util.HashMap; import java.io.*; -public class AltosRecord { +public class AltosRecord implements Comparable { final static int MISSING = 0x7fffffff; static final int seen_flight = 1; @@ -243,6 +243,10 @@ public class AltosRecord { return null; } + public int compareTo(AltosRecord o) { + return tick - o.tick; + } + public AltosRecord(AltosRecord old) { version = old.version; seen = old.seen; diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java index 1a31b365..278cbfb7 100644 --- a/altosui/AltosTelemetryIterable.java +++ b/altosui/AltosTelemetryIterable.java @@ -22,7 +22,7 @@ import java.util.*; import java.text.*; public class AltosTelemetryIterable extends AltosRecordIterable { - LinkedList records; + TreeSet records; public Iterator iterator () { return records.iterator(); @@ -41,7 +41,7 @@ public class AltosTelemetryIterable extends AltosRecordIterable { int boost_tick = 0; AltosRecord previous = null; - records = new LinkedList (); + records = new TreeSet (); try { for (;;) { @@ -56,8 +56,8 @@ public class AltosTelemetryIterable extends AltosRecordIterable { if (records.isEmpty()) { current_tick = record.tick; } else { - int tick = record.tick | (current_tick & ~ 0xffff); - if (tick < current_tick - 0x1000) + int tick = record.tick; + while (tick < current_tick - 0x1000) tick += 0x10000; current_tick = tick; record.tick = current_tick; diff --git a/altosui/AltosTelemetryRecordRaw.java b/altosui/AltosTelemetryRecordRaw.java index 39b2ba07..fb2b495c 100644 --- a/altosui/AltosTelemetryRecordRaw.java +++ b/altosui/AltosTelemetryRecordRaw.java @@ -143,11 +143,9 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { public AltosRecord update_state(AltosRecord previous) { AltosRecord next; - if (previous != null) { + if (previous != null) next = new AltosRecord(previous); - while (tick < previous.tick) - tick += 65536; - } else + else next = new AltosRecord(); next.serial = serial; next.tick = tick; -- cgit v1.2.3 From 5d1361c95f94125cda244b4cc5e55c2fb77b680b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Oct 2011 11:09:25 -0600 Subject: altosui: Deal with missing state transitions in FlightStats window Any missing start/end times are pinned to the end of the flight. Signed-off-by: Keith Packard --- altosui/AltosFlightStats.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index 2067951e..72d12600 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -47,7 +47,7 @@ public class AltosFlightStats { AltosState state = null; AltosState new_state = null; double boost_time = -1; - double start_time; + double end_time = 0; year = month = day = -1; hour = minute = second = -1; @@ -62,9 +62,7 @@ public class AltosFlightStats { if ((record.seen & AltosRecord.seen_flight) != 0 && flight < 0) flight = record.flight; new_state = new AltosState(record, state); - if (state == null) { - start_time = new_state.time; - } + end_time = new_state.time; state = new_state; if (0 <= state.state && state.state < Altos.ao_flight_invalid) { if (state.state >= Altos.ao_flight_boost) { @@ -107,6 +105,10 @@ public class AltosFlightStats { state_baro_speed[s] /= state_count[s]; state_accel[s] /= state_count[s]; } + if (state_start[s] == 0) + state_start[s] = end_time; + if (state_end[s] == 0) + state_end[s] = end_time; } } -- cgit v1.2.3 From 0669f0d74fc24c4f1925a45a9975b7a49a65b692 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 27 Oct 2011 00:49:23 -0700 Subject: altosui: Only update GPS data when new GPS information arrives Track which telemetry packets are actually producing new GPS information and only update the GPS average position and count of stable GPS reports with new GPS info, instead of on every telemetry packet. Signed-off-by: Keith Packard --- altosui/AltosEepromIterable.java | 1 + altosui/AltosRecord.java | 3 +++ altosui/AltosState.java | 2 +- altosui/AltosTelemetryRecordLegacy.java | 6 +++++- altosui/AltosTelemetryRecordLocation.java | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index 812e5fc6..d8205816 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -177,6 +177,7 @@ public class AltosEepromIterable extends AltosRecordIterable { state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0; state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT; + state.new_gps = true; has_gps = true; break; case Altos.AO_LOG_GPS_LAT: diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index 486c96b2..4dfa98be 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -65,6 +65,7 @@ public class AltosRecord implements Comparable { int flight_pres; AltosGPS gps; + boolean new_gps; double time; /* seconds since boost */ @@ -274,6 +275,7 @@ public class AltosRecord implements Comparable { speed = old.speed; height = old.height; gps = new AltosGPS(old.gps); + new_gps = false; companion = old.companion; } @@ -304,6 +306,7 @@ public class AltosRecord implements Comparable { speed = MISSING; height = MISSING; gps = new AltosGPS(); + new_gps = false; companion = null; } } diff --git a/altosui/AltosState.java b/altosui/AltosState.java index 3d8e5e12..da498bc1 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -135,7 +135,7 @@ public class AltosState { time = tick / 100.0; - if (state == Altos.ao_flight_pad || state == Altos.ao_flight_idle) { + if (cur.new_gps && (state == Altos.ao_flight_pad || state == Altos.ao_flight_idle)) { /* Track consecutive 'good' gps reports, waiting for 10 of them */ if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) diff --git a/altosui/AltosTelemetryRecordLegacy.java b/altosui/AltosTelemetryRecordLegacy.java index f59027ab..f2f63358 100644 --- a/altosui/AltosTelemetryRecordLegacy.java +++ b/altosui/AltosTelemetryRecordLegacy.java @@ -265,8 +265,10 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, MISSING); flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, MISSING); - if (map.has(AO_TELEM_GPS_STATE)) + if (map.has(AO_TELEM_GPS_STATE)) { gps = new AltosGPS(map); + new_gps = true; + } else gps = null; } @@ -355,6 +357,7 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele } gps = new AltosGPS(words, i, version); + new_gps = true; } public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { @@ -467,6 +470,7 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { gps = new AltosGPS(); + new_gps = true; seen |= seen_gps_time | seen_gps_lat | seen_gps_lon; gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); diff --git a/altosui/AltosTelemetryRecordLocation.java b/altosui/AltosTelemetryRecordLocation.java index 76bd106e..80db454d 100644 --- a/altosui/AltosTelemetryRecordLocation.java +++ b/altosui/AltosTelemetryRecordLocation.java @@ -85,6 +85,7 @@ public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { next.gps.hdop = hdop; next.gps.vdop = vdop; next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon; + next.new_gps = true; } return next; -- cgit v1.2.3 From 7ecde50fbebe68a2e2200a2f8d081fd37074f840 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2011 22:24:22 -0800 Subject: altosui: Make UI Look&Feel configurable Saves the preferred style and uses that for all current and new windows. Signed-off-by: Keith Packard --- altosui/AltosBTManage.java | 2 +- altosui/AltosCSVUI.java | 2 +- altosui/AltosConfigFreqUI.java | 4 +- altosui/AltosConfigUI.java | 2 +- altosui/AltosConfigureUI.java | 102 ++++++++++++++++++++++++++++++++++++++- altosui/AltosDeviceDialog.java | 2 +- altosui/AltosDialog.java | 62 ++++++++++++++++++++++++ altosui/AltosEepromMonitor.java | 2 +- altosui/AltosEepromSelect.java | 2 +- altosui/AltosFlashUI.java | 2 +- altosui/AltosFlightUI.java | 2 +- altosui/AltosFrame.java | 56 +++++++++++++++++++++ altosui/AltosGraphUI.java | 2 +- altosui/AltosIdleMonitorUI.java | 10 +++- altosui/AltosIgniteUI.java | 2 +- altosui/AltosLaunchUI.java | 2 +- altosui/AltosPreferences.java | 42 +++++++++++++++- altosui/AltosRomconfigUI.java | 2 +- altosui/AltosScanUI.java | 2 +- altosui/AltosSiteMapPreload.java | 2 +- altosui/AltosUI.java | 4 +- altosui/AltosUIListener.java | 22 +++++++++ altosui/Makefile.am | 3 ++ 23 files changed, 312 insertions(+), 21 deletions(-) create mode 100644 altosui/AltosDialog.java create mode 100644 altosui/AltosFrame.java create mode 100644 altosui/AltosUIListener.java (limited to 'altosui') diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index 10fdab3b..6d460701 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -32,7 +32,7 @@ import java.util.concurrent.*; import libaltosJNI.*; -public class AltosBTManage extends JDialog implements ActionListener, Iterable { +public class AltosBTManage extends AltosDialog implements ActionListener, Iterable { LinkedBlockingQueue found_devices; Frame frame; LinkedList listeners; diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java index a212409e..6d3e9065 100644 --- a/altosui/AltosCSVUI.java +++ b/altosui/AltosCSVUI.java @@ -29,7 +29,7 @@ import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; public class AltosCSVUI - extends JDialog + extends AltosDialog implements ActionListener { JFileChooser csv_chooser; diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java index 063d21b4..c6eabc53 100644 --- a/altosui/AltosConfigFreqUI.java +++ b/altosui/AltosConfigFreqUI.java @@ -30,7 +30,7 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; -class AltosEditFreqUI extends JDialog implements ActionListener { +class AltosEditFreqUI extends AltosDialog implements ActionListener { Frame frame; JTextField frequency; JTextField description; @@ -165,7 +165,7 @@ class AltosEditFreqUI extends JDialog implements ActionListener { } } -public class AltosConfigFreqUI extends JDialog implements ActionListener { +public class AltosConfigFreqUI extends AltosDialog implements ActionListener { Frame frame; LinkedList listeners; diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index d20dd073..9fef8e3b 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -32,7 +32,7 @@ import java.util.concurrent.LinkedBlockingQueue; import libaltosJNI.*; public class AltosConfigUI - extends JDialog + extends AltosDialog implements ActionListener, ItemListener, DocumentListener { diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index 980068c0..06b5745c 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -19,6 +19,7 @@ package altosui; import java.awt.*; import java.awt.event.*; +import java.beans.*; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.*; @@ -28,9 +29,51 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import javax.swing.plaf.basic.*; + +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 AltosConfigureUI - extends JDialog + extends AltosDialog implements DocumentListener { JFrame owner; @@ -50,6 +93,9 @@ public class AltosConfigureUI JLabel font_size_label; JComboBox font_size_value; + JLabel look_and_feel_label; + JComboBox look_and_feel_value; + JRadioButton serial_debug; JButton manage_bluetooth; @@ -215,6 +261,60 @@ public class AltosConfigureUI 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(); + + System.out.printf("look_and_feels %d\n", look_and_feels.length); + look_and_feel_value = new JComboBox(look_and_feels); + + DelegatingRenderer.install(look_and_feel_value); + + String look_and_feel = AltosPreferences.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(); + + AltosPreferences.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; diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index 610bb73e..e53e75c1 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -24,7 +24,7 @@ import java.awt.*; import java.awt.event.*; import libaltosJNI.*; -public class AltosDeviceDialog extends JDialog implements ActionListener { +public class AltosDeviceDialog extends AltosDialog implements ActionListener { private AltosDevice value; private JList list; diff --git a/altosui/AltosDialog.java b/altosui/AltosDialog.java new file mode 100644 index 00000000..c30b5757 --- /dev/null +++ b/altosui/AltosDialog.java @@ -0,0 +1,62 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +class AltosDialogListener extends WindowAdapter { + public void windowClosing (WindowEvent e) { + AltosPreferences.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() { + AltosPreferences.register_ui_listener(this); + addWindowListener(new AltosDialogListener()); + } + + public AltosDialog(Frame frame, String label, boolean modal) { + super(frame, label, modal); + AltosPreferences.register_ui_listener(this); + addWindowListener(new AltosDialogListener()); + } + + public AltosDialog(Frame frame, boolean modal) { + super(frame, modal); + AltosPreferences.register_ui_listener(this); + addWindowListener(new AltosDialogListener()); + } +} diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java index b9d913fa..34f5b891 100644 --- a/altosui/AltosEepromMonitor.java +++ b/altosui/AltosEepromMonitor.java @@ -28,7 +28,7 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; -public class AltosEepromMonitor extends JDialog { +public class AltosEepromMonitor extends AltosDialog { Container pane; Box box; diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index 0a6eec17..ebafc4c8 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -62,7 +62,7 @@ class AltosEepromItem implements ActionListener { } } -public class AltosEepromSelect extends JDialog implements ActionListener { +public class AltosEepromSelect extends AltosDialog implements ActionListener { private JList list; private JFrame frame; JButton ok; diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 3956ff20..39151641 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -29,7 +29,7 @@ import java.util.prefs.*; import java.util.concurrent.*; public class AltosFlashUI - extends JDialog + extends AltosDialog implements ActionListener { Container pane; diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index b44b9d43..d166c9ae 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -28,7 +28,7 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; -public class AltosFlightUI extends JFrame implements AltosFlightDisplay, AltosFontListener { +public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { AltosVoice voice; AltosFlightReader reader; AltosDisplayThread thread; diff --git a/altosui/AltosFrame.java b/altosui/AltosFrame.java new file mode 100644 index 00000000..f8cc4f52 --- /dev/null +++ b/altosui/AltosFrame.java @@ -0,0 +1,56 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +class AltosFrameListener extends WindowAdapter { + public void windowClosing (WindowEvent e) { + AltosPreferences.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(); + } + + public AltosFrame() { + AltosPreferences.register_ui_listener(this); + addWindowListener(new AltosFrameListener()); + } + + public AltosFrame(String name) { + super(name); + AltosPreferences.register_ui_listener(this); + addWindowListener(new AltosFrameListener()); + } +} diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 59e92499..c30dc476 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -20,7 +20,7 @@ import org.jfree.chart.axis.AxisLocation; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RefineryUtilities; -public class AltosGraphUI extends JFrame +public class AltosGraphUI extends AltosFrame { JTabbedPane pane; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 988a797c..a5f41e25 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -255,7 +255,7 @@ class AltosIdleMonitor extends Thread { } } -public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { +public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { AltosDevice device; JTabbedPane pane; AltosPad pad; @@ -289,6 +289,10 @@ public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { flightInfo.set_font(); } + public void font_size_changed(int font_size) { + set_font(); + } + public void show(AltosState state, int crc_errors) { try { pad.show(state, crc_errors); @@ -377,12 +381,16 @@ public class AltosIdleMonitorUI extends JFrame implements AltosFlightDisplay { bag.add(pane, c); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + + AltosPreferences.register_font_listener(this); + addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { disconnect(); setVisible(false); dispose(); + AltosPreferences.unregister_font_listener(AltosIdleMonitorUI.this); } }); diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index b215c228..8623cbef 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -30,7 +30,7 @@ import java.util.prefs.*; import java.util.concurrent.*; public class AltosIgniteUI - extends JDialog + extends AltosDialog implements ActionListener { AltosDevice device; diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index 47365e03..73fae16b 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -50,7 +50,7 @@ class FireButton extends JButton { } public class AltosLaunchUI - extends JDialog + extends AltosDialog implements ActionListener { AltosDevice device; diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index 48aed441..cc2b1a95 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -61,9 +61,12 @@ class AltosPreferences { /* Launcher serial preference name */ final static String launcherSerialPreference = "LAUNCHER-SERIAL"; - /* Launcher channel prefernce name */ + /* Launcher channel preference name */ final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; + /* Look&Feel preference name */ + final static String lookAndFeelPreference = "LOOK-AND-FEEL"; + /* Default logdir is ~/TeleMetrum */ final static String logdirName = "TeleMetrum"; @@ -101,6 +104,10 @@ class AltosPreferences { static int font_size = Altos.font_size_medium; + static LinkedList ui_listeners; + + static String look_and_feel = null; + /* List of frequencies */ final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; static AltosFrequency[] common_frequencies; @@ -199,6 +206,10 @@ class AltosPreferences { AltosSerial.set_debug(serial_debug); common_frequencies = load_common_frequencies(); + + look_and_feel = preferences.get(lookAndFeelPreference, UIManager.getSystemLookAndFeelClassName()); + + ui_listeners = new LinkedList(); } static { init(); } @@ -390,6 +401,35 @@ class AltosPreferences { } } + public static void set_look_and_feel(String new_look_and_feel) { + look_and_feel = new_look_and_feel; + try { + UIManager.setLookAndFeel(look_and_feel); + } catch (Exception e) { + } + synchronized(preferences) { + preferences.put(lookAndFeelPreference, look_and_feel); + flush_preferences(); + for (AltosUIListener l : ui_listeners) + l.ui_changed(look_and_feel); + } + } + + public static String look_and_feel() { + return look_and_feel; + } + + public static void register_ui_listener(AltosUIListener l) { + synchronized(preferences) { + ui_listeners.add(l); + } + } + + public static void unregister_ui_listener(AltosUIListener l) { + synchronized (preferences) { + ui_listeners.remove(l); + } + } public static void set_serial_debug(boolean new_serial_debug) { serial_debug = new_serial_debug; AltosSerial.set_debug(serial_debug); diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java index 7e21735c..e4e38c9c 100644 --- a/altosui/AltosRomconfigUI.java +++ b/altosui/AltosRomconfigUI.java @@ -29,7 +29,7 @@ import java.text.*; import java.util.prefs.*; public class AltosRomconfigUI - extends JDialog + extends AltosDialog implements ActionListener { Container pane; diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index df5c51d4..e188834e 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -102,7 +102,7 @@ class AltosScanResults extends LinkedList implements ListModel } public class AltosScanUI - extends JDialog + extends AltosDialog implements ActionListener { AltosUI owner; diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index aa07bebc..5de7a05e 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -212,7 +212,7 @@ class AltosSites extends Thread { } } -public class AltosSiteMapPreload extends JDialog implements ActionListener, ItemListener { +public class AltosSiteMapPreload extends AltosDialog implements ActionListener, ItemListener { AltosUI owner; AltosSiteMap map; diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 3e5bcf43..8799d560 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -30,7 +30,7 @@ import java.util.concurrent.*; import libaltosJNI.*; -public class AltosUI extends JFrame { +public class AltosUI extends AltosFrame { public AltosVoice voice = new AltosVoice(); public static boolean load_library(Frame frame) { @@ -519,7 +519,7 @@ public class AltosUI extends JFrame { public static void main(final String[] args) { try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + UIManager.setLookAndFeel(AltosPreferences.look_and_feel()); } catch (Exception e) { } /* Handle batch-mode */ diff --git a/altosui/AltosUIListener.java b/altosui/AltosUIListener.java new file mode 100644 index 00000000..7ee62afc --- /dev/null +++ b/altosui/AltosUIListener.java @@ -0,0 +1,22 @@ +/* + * 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 altosui; + +public interface AltosUIListener { + public void ui_changed(String look_and_feel); +} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index c4d1e611..7cd383ac 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -110,6 +110,9 @@ altosui_JAVA = \ AltosTelemetry.java \ AltosTelemetryIterable.java \ AltosUI.java \ + AltosUIListener.java \ + AltosFrame.java \ + AltosDialog.java \ AltosWriter.java \ AltosDataPointReader.java \ AltosDataPoint.java \ -- cgit v1.2.3 From f6db11c3c87725c809c518f5f19b07325faf9c84 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 12 Nov 2011 18:10:18 -0800 Subject: altosui: Deal with serial port exceptions a bit better This catches a few exceptions and tries to make sure the serial port is closed afterwards. Signed-off-by: Keith Packard --- altosui/AltosDebug.java | 13 +++++++++++-- altosui/AltosFlashUI.java | 23 ++++++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosDebug.java b/altosui/AltosDebug.java index d18de80d..ce1cf5dd 100644 --- a/altosui/AltosDebug.java +++ b/altosui/AltosDebug.java @@ -163,7 +163,11 @@ public class AltosDebug extends AltosSerial { int i = 0; byte[] data = new byte[length]; while (i < length) { - String line = get_reply().trim(); + String line = get_reply(); + + if (line == null) + throw new IOException("Timeout in read_bytes"); + line = line.trim(); String tokens[] = line.split("\\s+"); for (int j = 0; j < tokens.length; j++) { if (!Altos.ishex(tokens[j]) || @@ -172,7 +176,12 @@ public class AltosDebug extends AltosSerial { String.format ("Invalid read_bytes reply \"%s\"", line)); try { - data[i + j] = (byte) Integer.parseInt(tokens[j], 16); + if (i + j >= length) + throw new IOException( + String.format + ("Invalid read_bytes reply \"%s\"", line)); + else + data[i + j] = (byte) Integer.parseInt(tokens[j], 16); } catch (NumberFormatException ne) { throw new IOException( String.format diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 39151641..704ce35c 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -247,7 +247,7 @@ public class AltosFlashUI flash.set_romconfig(ui.rom_config); flash.flash(); } - } catch (Exception ee) { + } catch (InterruptedException ee) { final Exception e = ee; System.out.printf("exception %s\n", e.toString()); SwingUtilities.invokeLater(new Runnable() { @@ -255,9 +255,26 @@ public class AltosFlashUI ui.exception(e); } }); + } catch (IOException ee) { + final Exception e = ee; + System.out.printf("exception %s\n", e.toString()); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + ui.exception(e); + } + }); + } catch (AltosSerialInUseException ee) { + final Exception e = ee; + System.out.printf("exception %s\n", e.toString()); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + ui.exception(e); + } + }); + } finally { + if (flash != null) + flash.close(); } - if (flash != null) - flash.close(); } public flash_task(AltosFlashUI in_ui) { -- cgit v1.2.3 From 6baf6f41040f7b074d8cc84ef75e254c5d2b466b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 17 Dec 2011 16:58:04 -0800 Subject: altosui: googleearth doesn't accept spaces between coordinates anymore it got pickier for some reason; let's not put spaces in now. Signed-off-by: Keith Packard --- altosui/AltosKML.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosKML.java b/altosui/AltosKML.java index d586033f..6bdbecca 100644 --- a/altosui/AltosKML.java +++ b/altosui/AltosKML.java @@ -73,7 +73,7 @@ public class AltosKML implements AltosWriter { " \n"; static final String kml_coord_fmt = - " %12.7f, %12.7f, %12.7f \n"; + " %.7f,%.7f,%.7f \n"; static final String kml_placemark_end = " \n" + -- cgit v1.2.3 From eff8611e3eb19853b06acfcd7e978c9046cd5f78 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 17 Dec 2011 17:05:06 -0800 Subject: altos: Create TeleMetrum v1.2 directory The hardware is software-compatible with v1.1, but it's nice to have the right version number in all of the files. Signed-off-by: Keith Packard --- altosui/Makefile.am | 3 ++- altosui/altos-windows.nsi | 1 + doc/altusmetrum.xsl | 8 ++++---- src/Makefile | 2 +- src/cc1111/ao_pins.h | 37 +++++++++++++++++++++++++++++++++++++ src/core/ao_telemetry.c | 2 +- src/telemetrum-v1.2/.gitignore | 2 ++ src/telemetrum-v1.2/.sdcdbrc | 1 + src/telemetrum-v1.2/Makefile | 16 ++++++++++++++++ 9 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 src/telemetrum-v1.2/.gitignore create mode 100644 src/telemetrum-v1.2/.sdcdbrc create mode 100644 src/telemetrum-v1.2/Makefile (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 7cd383ac..fc024fff 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -171,7 +171,8 @@ FIRMWARE_TD=$(FIRMWARE_TD_0_2) FIRMWARE_TM_1_0=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx FIRMWARE_TM_1_1=$(top_srcdir)/src/telemetrum-v1.1-$(VERSION).ihx -FIRMWARE_TM=$(FIRMWARE_TM_1_0) $(FIRMWARE_TM_1_1) +FIRMWARE_TM_1_2=$(top_srcdir)/src/telemetrum-v1.2-$(VERSION).ihx +FIRMWARE_TM=$(FIRMWARE_TM_1_0) $(FIRMWARE_TM_1_1) $(FIRMWARE_TM_1_2) FIRMWARE_TELEMINI_1_0=$(top_srcdir)/src/telemini-v1.0-$(VERSION).ihx FIRMWARE_TELEMINI=$(FIRMWARE_TELEMINI_1_0) diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index cbcb389d..e5e01d79 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -112,6 +112,7 @@ Section "TeleMetrum and TeleDongle Firmware" File "../src/telemetrum-v1.0/telemetrum-v1.0-${VERSION}.ihx" File "../src/telemetrum-v1.1/telemetrum-v1.1-${VERSION}.ihx" + File "../src/telemetrum-v1.2/telemetrum-v1.2-${VERSION}.ihx" File "../src/telemini-v1.0/telemini-v1.0-${VERSION}.ihx" File "../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx" diff --git a/doc/altusmetrum.xsl b/doc/altusmetrum.xsl index 606c8b99..5c18fec3 100644 --- a/doc/altusmetrum.xsl +++ b/doc/altusmetrum.xsl @@ -586,7 +586,7 @@ NAR #88757, TRA #12200
Maximum Flight Log - TeleMetrum version 1.1 has 2MB of on-board flash storage, + TeleMetrum version 1.1 and 1.2 have 2MB of on-board flash storage, enough to hold over 40 minutes of data at full data rate (100 samples/second). TeleMetrum 1.0 has 1MB of on-board storage. As data are stored at a reduced rate during descent @@ -602,7 +602,7 @@ NAR #88757, TRA #12200 All of the configuration data is also stored in the flash - memory, which consumes 64kB on TeleMetrum v1.1 and 256B on + memory, which consumes 64kB on TeleMetrum v1.1/v1.2 and 256B on TeleMetrum v1.0. This configuration space is not available for storing flight log data. @@ -619,7 +619,7 @@ NAR #88757, TRA #12200 The default size, 192kB, allows for 10 flights of storage on - TeleMetrum v1.1 and 5 flights on TeleMetrum v1.0. This + TeleMetrum v1.1/v1.2 and 5 flights on TeleMetrum v1.0. This ensures that you won't need to erase the memory before flying each time while still allowing more than sufficient storage for each flight. @@ -1842,7 +1842,7 @@ NAR #88757, TRA #12200 Select the image you want put on the TeleMetrum, which should have a - name in the form telemetrum-v1.1-1.0.0.ihx. It should be visible + name in the form telemetrum-v1.2-1.0.0.ihx. It should be visible in the default directory, if not you may have to poke around your system to find it. diff --git a/src/Makefile b/src/Makefile index 61b1a835..d3173254 100644 --- a/src/Makefile +++ b/src/Makefile @@ -13,7 +13,7 @@ vpath matrix.5c kalman include Version SUBDIRS=\ - telemetrum-v1.1 telemetrum-v1.0 \ + telemetrum-v1.2 telemetrum-v1.1 telemetrum-v1.0 \ teledongle-v0.2 teledongle-v0.1 \ telemini-v1.0 telenano-v0.1 \ telebt-v0.0 telebt-v0.1 \ diff --git a/src/cc1111/ao_pins.h b/src/cc1111/ao_pins.h index ca85c39f..a18c74c8 100644 --- a/src/cc1111/ao_pins.h +++ b/src/cc1111/ao_pins.h @@ -89,6 +89,43 @@ #define HAS_MONITOR 0 #endif +#if defined(TELEMETRUM_V_1_2) + #define HAS_FLIGHT 1 + #define HAS_USB 1 + #define HAS_BEEP 1 + #define HAS_GPS 1 + #define HAS_SERIAL_1 1 + #define USE_SERIAL_STDIN 0 + #define HAS_ADC 1 + #define HAS_EEPROM 1 + #define HAS_LOG 1 + #define USE_INTERNAL_FLASH 0 + #define HAS_DBG 1 + #define DBG_ON_P1 1 + #define DBG_ON_P0 0 + #define IGNITE_ON_P2 1 + #define IGNITE_ON_P0 0 + #define PACKET_HAS_MASTER 0 + #define PACKET_HAS_SLAVE 1 + + #define HAS_COMPANION 1 + #define COMPANION_CS_ON_P1 1 + #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */ + #define COMPANION_CS P1_2 + + #define AO_LED_RED 1 + #define LEDS_AVAILABLE (AO_LED_RED) + #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 1 + #define SPI_CS_ON_P1 1 + #define SPI_CS_ON_P0 0 + #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ + #define M25_MAX_CHIPS 1 + #define HAS_ACCEL 1 + #define HAS_IGNITE 1 + #define HAS_MONITOR 0 +#endif + #if defined(TELEDONGLE_V_0_2) #define HAS_FLIGHT 0 #define HAS_USB 1 diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c index c68f1589..eb614b0f 100644 --- a/src/core/ao_telemetry.c +++ b/src/core/ao_telemetry.c @@ -35,7 +35,7 @@ static __pdata uint16_t ao_rdf_time; #define AO_RDF_INTERVAL_TICKS AO_SEC_TO_TICKS(5) #define AO_RDF_LENGTH_MS 500 -#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1) || defined(TELEBALLOON_V_1_1) +#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1) || defined(TELEBALLOON_V_1_1) || defined(TELEMETRUM_V_1_2) #define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMETRUM #endif diff --git a/src/telemetrum-v1.2/.gitignore b/src/telemetrum-v1.2/.gitignore new file mode 100644 index 00000000..c2212151 --- /dev/null +++ b/src/telemetrum-v1.2/.gitignore @@ -0,0 +1,2 @@ +telemetrum-* +ao_product.h diff --git a/src/telemetrum-v1.2/.sdcdbrc b/src/telemetrum-v1.2/.sdcdbrc new file mode 100644 index 00000000..710b4a2f --- /dev/null +++ b/src/telemetrum-v1.2/.sdcdbrc @@ -0,0 +1 @@ +--directory=.. diff --git a/src/telemetrum-v1.2/Makefile b/src/telemetrum-v1.2/Makefile new file mode 100644 index 00000000..4b650adf --- /dev/null +++ b/src/telemetrum-v1.2/Makefile @@ -0,0 +1,16 @@ +# +# AltOS build +# +# + +TM_VER=1.2 +TM_DEF=1_2 + +TM_INC = + +TM_SRC = \ + ao_companion.c \ + ao_gps_skytraq.c \ + ao_m25.c + +include ../product/Makefile.telemetrum -- cgit v1.2.3 From 392a3107b9e9cc8c1ea51df6ff5ec54817adbc65 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 26 Mar 2012 20:11:34 -0700 Subject: altosui: Restructure telemetry classes to be more sane * Make AltosTelemetryRecord be a class, rather than an interface. * Inherit from this for AltosTelemetryRecordLegacy and AltosTelemetryRecordRaw. * Remove bogus AltosTelemetryRecordGeneral class. Signed-off-by: Keith Packard --- altosui/AltosTelemetry.java | 2 +- altosui/AltosTelemetryRecord.java | 109 +++++++++++++- altosui/AltosTelemetryRecordGeneral.java | 43 ------ altosui/AltosTelemetryRecordLegacy.java | 248 ++++++++++++++++--------------- altosui/AltosTelemetryRecordRaw.java | 89 +---------- altosui/Makefile.am | 1 - 6 files changed, 241 insertions(+), 251 deletions(-) delete mode 100644 altosui/AltosTelemetryRecordGeneral.java (limited to 'altosui') diff --git a/altosui/AltosTelemetry.java b/altosui/AltosTelemetry.java index a05269f4..0052ef04 100644 --- a/altosui/AltosTelemetry.java +++ b/altosui/AltosTelemetry.java @@ -234,7 +234,7 @@ public class AltosTelemetry extends AltosRecord { final static String AO_TELEM_SAT_C_N_0 = "s_c"; static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { - AltosTelemetryRecord r = AltosTelemetryRecordGeneral.parse(line); + AltosTelemetryRecord r = AltosTelemetryRecord.parse(line); return r.update_state(previous); } diff --git a/altosui/AltosTelemetryRecord.java b/altosui/AltosTelemetryRecord.java index cfac309a..2e6b5ead 100644 --- a/altosui/AltosTelemetryRecord.java +++ b/altosui/AltosTelemetryRecord.java @@ -16,8 +16,113 @@ */ package altosui; +import java.lang.*; +import java.text.*; -public interface AltosTelemetryRecord { +public abstract class AltosTelemetryRecord { - public AltosRecord update_state(AltosRecord previous); + long received_time; + abstract public AltosRecord update_state(AltosRecord previous); + + static boolean cksum(int[] bytes) { + int sum = 0x5a; + for (int i = 1; i < bytes.length - 1; i++) + sum += bytes[i]; + sum &= 0xff; + return sum == bytes[bytes.length - 1]; + } + + final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); + final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); + final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; + + final static int packet_type_TM_sensor = 0x01; + final static int packet_type_Tm_sensor = 0x02; + final static int packet_type_Tn_sensor = 0x03; + final static int packet_type_configuration = 0x04; + final static int packet_type_location = 0x05; + final static int packet_type_satellite = 0x06; + final static int packet_type_companion = 0x07; + + static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + int[] bytes; + try { + bytes = Altos.hexbytes(hex); + } catch (NumberFormatException ne) { + throw new ParseException(ne.getMessage(), 0); + } + + /* one for length, one for checksum */ + if (bytes[0] != bytes.length - 2) + throw new ParseException(String.format("invalid length %d != %d\n", + bytes[0], + bytes.length - 2), 0); + if (!cksum(bytes)) + throw new ParseException(String.format("invalid line \"%s\"", hex), 0); + + int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; + int status = Altos.uint8(bytes, bytes.length - 2); + + if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) + throw new AltosCRCException(rssi); + + /* length, data ..., rssi, status, checksum -- 4 bytes extra */ + switch (bytes.length) { + case Altos.ao_telemetry_standard_len + 4: + int type = Altos.uint8(bytes, 4 + 1); + switch (type) { + case packet_type_TM_sensor: + case packet_type_Tm_sensor: + case packet_type_Tn_sensor: + r = new AltosTelemetryRecordSensor(bytes, rssi); + break; + case packet_type_configuration: + r = new AltosTelemetryRecordConfiguration(bytes); + break; + case packet_type_location: + r = new AltosTelemetryRecordLocation(bytes); + break; + case packet_type_satellite: + r = new AltosTelemetryRecordSatellite(bytes); + break; + case packet_type_companion: + r = new AltosTelemetryRecordCompanion(bytes); + break; + default: + r = new AltosTelemetryRecordRaw(bytes); + break; + } + break; + case Altos.ao_telemetry_0_9_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + case Altos.ao_telemetry_0_8_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + default: + throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); + } + r.received_time = System.currentTimeMillis(); + return r; + } + + public static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + String[] word = line.split("\\s+"); + int i =0; + if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(word[i++], "RSSI"); + throw new AltosCRCException(AltosParse.parse_int(word[i++])); + } + + if (word[i].equals("TELEM")) + r = parse_hex(word[i+1]); + else + r = new AltosTelemetryRecordLegacy(line); + return r; + } } diff --git a/altosui/AltosTelemetryRecordGeneral.java b/altosui/AltosTelemetryRecordGeneral.java deleted file mode 100644 index 722baba3..00000000 --- a/altosui/AltosTelemetryRecordGeneral.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryRecordGeneral { - - static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - String[] word = line.split("\\s+"); - int i =0; - if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(word[i++], "RSSI"); - throw new AltosCRCException(AltosParse.parse_int(word[i++])); - } - - if (word[i].equals("TELEM")) - r = AltosTelemetryRecordRaw.parse(word[i+1]); - else - r = new AltosTelemetryRecordLegacy(line); - return r; - } -} diff --git a/altosui/AltosTelemetryRecordLegacy.java b/altosui/AltosTelemetryRecordLegacy.java index f2f63358..a72ebb0f 100644 --- a/altosui/AltosTelemetryRecordLegacy.java +++ b/altosui/AltosTelemetryRecordLegacy.java @@ -84,7 +84,7 @@ import java.util.HashMap; * */ -public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTelemetryRecord { +public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { /* * General header fields * @@ -232,152 +232,156 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele final static String AO_TELEM_SAT_SVID = "s_v"; final static String AO_TELEM_SAT_C_N_0 = "s_c"; + AltosRecord record; + private void parse_v4(String[] words, int i) throws ParseException { AltosTelemetryMap map = new AltosTelemetryMap(words, i); - callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); - serial = map.get_int(AO_TELEM_SERIAL, MISSING); - flight = map.get_int(AO_TELEM_FLIGHT, MISSING); - rssi = map.get_int(AO_TELEM_RSSI, MISSING); - state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); - tick = map.get_int(AO_TELEM_TICK, 0); + record.callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); + record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING); + record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); + record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); + record.state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + record.tick = map.get_int(AO_TELEM_TICK, 0); /* raw sensor values */ - accel = map.get_int(AO_TELEM_RAW_ACCEL, MISSING); - pres = map.get_int(AO_TELEM_RAW_BARO, MISSING); - temp = map.get_int(AO_TELEM_RAW_THERMO, MISSING); - batt = map.get_int(AO_TELEM_RAW_BATT, MISSING); - drogue = map.get_int(AO_TELEM_RAW_DROGUE, MISSING); - main = map.get_int(AO_TELEM_RAW_MAIN, MISSING); + record.accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING); + record.pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING); + record.temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING); + record.batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING); + record.drogue = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING); + record.main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING); /* sensor calibration information */ - ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, MISSING); - ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, MISSING); - accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, MISSING); - accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, MISSING); + record.ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING); + record.ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING); + record.accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING); + record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING); /* flight computer values */ - acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, MISSING, 1/16.0); - speed = map.get_double(AO_TELEM_KALMAN_SPEED, MISSING, 1/16.0); - height = map.get_int(AO_TELEM_KALMAN_HEIGHT, MISSING); + record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); + record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); + record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); - flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, MISSING); - flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, MISSING); - flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, MISSING); + record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING); + record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); + record.flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING); if (map.has(AO_TELEM_GPS_STATE)) { - gps = new AltosGPS(map); - new_gps = true; + record.gps = new AltosGPS(map); + record.new_gps = true; } else - gps = null; + record.gps = null; } private void parse_legacy(String[] words, int i) throws ParseException { AltosParse.word (words[i++], "CALL"); - callsign = words[i++]; + record.callsign = words[i++]; AltosParse.word (words[i++], "SERIAL"); - serial = AltosParse.parse_int(words[i++]); + record.serial = AltosParse.parse_int(words[i++]); - if (version >= 2) { + if (record.version >= 2) { AltosParse.word (words[i++], "FLIGHT"); - flight = AltosParse.parse_int(words[i++]); + record.flight = AltosParse.parse_int(words[i++]); } else - flight = 0; + record.flight = 0; AltosParse.word(words[i++], "RSSI"); - rssi = AltosParse.parse_int(words[i++]); + record.rssi = AltosParse.parse_int(words[i++]); /* Older telemetry data had mis-computed RSSI value */ - if (version <= 2) - rssi = (rssi + 74) / 2 - 74; + if (record.version <= 2) + record.rssi = (record.rssi + 74) / 2 - 74; AltosParse.word(words[i++], "STATUS"); - status = AltosParse.parse_hex(words[i++]); + record.status = AltosParse.parse_hex(words[i++]); AltosParse.word(words[i++], "STATE"); - state = Altos.state(words[i++]); + record.state = Altos.state(words[i++]); - tick = AltosParse.parse_int(words[i++]); + record.tick = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "a:"); - accel = AltosParse.parse_int(words[i++]); + record.accel = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "p:"); - pres = AltosParse.parse_int(words[i++]); + record.pres = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "t:"); - temp = AltosParse.parse_int(words[i++]); + record.temp = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "v:"); - batt = AltosParse.parse_int(words[i++]); + record.batt = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "d:"); - drogue = AltosParse.parse_int(words[i++]); + record.drogue = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "m:"); - main = AltosParse.parse_int(words[i++]); + record.main = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "fa:"); - flight_accel = AltosParse.parse_int(words[i++]); + record.flight_accel = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "ga:"); - ground_accel = AltosParse.parse_int(words[i++]); + record.ground_accel = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "fv:"); - flight_vel = AltosParse.parse_int(words[i++]); + record.flight_vel = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "fp:"); - flight_pres = AltosParse.parse_int(words[i++]); + record.flight_pres = AltosParse.parse_int(words[i++]); /* Old TeleDongle code with kalman-reporting TeleMetrum code */ - if ((flight_vel & 0xffff0000) == 0x80000000) { - speed = ((short) flight_vel) / 16.0; - acceleration = flight_accel / 16.0; - height = flight_pres; - flight_vel = MISSING; - flight_pres = MISSING; - flight_accel = MISSING; + if ((record.flight_vel & 0xffff0000) == 0x80000000) { + record.speed = ((short) record.flight_vel) / 16.0; + record.acceleration = record.flight_accel / 16.0; + record.height = record.flight_pres; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + record.flight_accel = AltosRecord.MISSING; } AltosParse.word(words[i++], "gp:"); - ground_pres = AltosParse.parse_int(words[i++]); + record.ground_pres = AltosParse.parse_int(words[i++]); - if (version >= 1) { + if (record.version >= 1) { AltosParse.word(words[i++], "a+:"); - accel_plus_g = AltosParse.parse_int(words[i++]); + record.accel_plus_g = AltosParse.parse_int(words[i++]); AltosParse.word(words[i++], "a-:"); - accel_minus_g = AltosParse.parse_int(words[i++]); + record.accel_minus_g = AltosParse.parse_int(words[i++]); } else { - accel_plus_g = ground_accel; - accel_minus_g = ground_accel + 530; + record.accel_plus_g = record.ground_accel; + record.accel_minus_g = record.ground_accel + 530; } - gps = new AltosGPS(words, i, version); - new_gps = true; + record.gps = new AltosGPS(words, i, record.version); + record.new_gps = true; } public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { String[] words = line.split("\\s+"); int i = 0; + record = new AltosRecord(); + if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { i += 2; AltosParse.word(words[i++], "RSSI"); - rssi = AltosParse.parse_int(words[i++]); - throw new AltosCRCException(rssi); + record.rssi = AltosParse.parse_int(words[i++]); + throw new AltosCRCException(record.rssi); } if (words[i].equals("CALL")) { - version = 0; + record.version = 0; } else { AltosParse.word (words[i++], "VERSION"); - version = AltosParse.parse_int(words[i++]); + record.version = AltosParse.parse_int(words[i++]); } - if (version < 4) + if (record.version < 4) parse_legacy(words, i); else parse_v4(words, i); @@ -418,72 +422,74 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele static final int AO_GPS_COURSE_VALID = (1 << 7); public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { + record = new AltosRecord(); + bytes = in_bytes; - version = 4; + record.version = 4; adjust = 0; if (bytes.length == Altos.ao_telemetry_0_8_len + 4) { - serial = uint8(0); + record.serial = uint8(0); adjust = -1; } else - serial = uint16(0); - - seen = seen_flight | seen_sensor | seen_temp_volt | seen_deploy; - - callsign = string(62, 8); - flight = uint16(2); - rssi = in_rssi; - status = in_status; - state = uint8(4); - tick = uint16(21); - accel = int16(23); - pres = int16(25); - temp = int16(27); - batt = int16(29); - drogue = int16(31); - main = int16(33); + record.serial = uint16(0); + + record.seen = AltosRecord.seen_flight | AltosRecord.seen_sensor | AltosRecord.seen_temp_volt | AltosRecord.seen_deploy; + + record.callsign = string(62, 8); + record.flight = uint16(2); + record.rssi = in_rssi; + record.status = in_status; + record.state = uint8(4); + record.tick = uint16(21); + record.accel = int16(23); + record.pres = int16(25); + record.temp = int16(27); + record.batt = int16(29); + record.drogue = int16(31); + record.main = int16(33); - ground_accel = int16(7); - ground_pres = int16(15); - accel_plus_g = int16(17); - accel_minus_g = int16(19); + record.ground_accel = int16(7); + record.ground_pres = int16(15); + record.accel_plus_g = int16(17); + record.accel_minus_g = int16(19); if (uint16(11) == 0x8000) { - acceleration = int16(5); - speed = int16(9); - height = int16(13); - flight_accel = MISSING; - flight_vel = MISSING; - flight_pres = MISSING; + record.acceleration = int16(5); + record.speed = int16(9); + record.height = int16(13); + record.flight_accel = AltosRecord.MISSING; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; } else { - flight_accel = int16(5); - flight_vel = uint32(9); - flight_pres = int16(13); - acceleration = MISSING; - speed = MISSING; - height = MISSING; + record.flight_accel = int16(5); + record.flight_vel = uint32(9); + record.flight_pres = int16(13); + record.acceleration = AltosRecord.MISSING; + record.speed = AltosRecord.MISSING; + record.height = AltosRecord.MISSING; } - gps = null; + record.gps = null; int gps_flags = uint8(41); if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { - gps = new AltosGPS(); - new_gps = true; - - seen |= seen_gps_time | seen_gps_lat | seen_gps_lon; - gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); - gps.locked = (gps_flags & AO_GPS_VALID) != 0; - gps.connected = true; - gps.lat = uint32(42) / 1.0e7; - gps.lon = uint32(46) / 1.0e7; - gps.alt = int16(50); - gps.ground_speed = uint16(52) / 100.0; - gps.course = uint8(54) * 2; - gps.hdop = uint8(55) / 5.0; - gps.h_error = uint16(58); - gps.v_error = uint16(60); + record.gps = new AltosGPS(); + record.new_gps = true; + + record.seen |= record.seen_gps_time | record.seen_gps_lat | record.seen_gps_lon; + record.gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); + record.gps.locked = (gps_flags & AO_GPS_VALID) != 0; + record.gps.connected = true; + record.gps.lat = uint32(42) / 1.0e7; + record.gps.lon = uint32(46) / 1.0e7; + record.gps.alt = int16(50); + record.gps.ground_speed = uint16(52) / 100.0; + record.gps.course = uint8(54) * 2; + record.gps.hdop = uint8(55) / 5.0; + record.gps.h_error = uint16(58); + record.gps.v_error = uint16(60); int n_tracking_reported = uint8(70); if (n_tracking_reported > 12) @@ -494,22 +500,22 @@ public class AltosTelemetryRecordLegacy extends AltosRecord implements AltosTele n_tracking_actual++; } if (n_tracking_actual > 0) { - gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; + record.gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; n_tracking_actual = 0; for (int i = 0; i < n_tracking_reported; i++) { int svid = uint8(71 + i*2); int c_n0 = uint8(72 + i*2); if (svid != 0) - gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); + record.gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); } } } - time = 0.0; + record.time = 0.0; } public AltosRecord update_state(AltosRecord previous) { - return this; + return record; } } diff --git a/altosui/AltosTelemetryRecordRaw.java b/altosui/AltosTelemetryRecordRaw.java index fb2b495c..08c85e85 100644 --- a/altosui/AltosTelemetryRecordRaw.java +++ b/altosui/AltosTelemetryRecordRaw.java @@ -21,94 +21,13 @@ import java.lang.*; import java.text.*; import java.util.HashMap; -public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { +public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { int[] bytes; int serial; int tick; int type; - final static int packet_type_TM_sensor = 0x01; - final static int packet_type_Tm_sensor = 0x02; - final static int packet_type_Tn_sensor = 0x03; - final static int packet_type_configuration = 0x04; - final static int packet_type_location = 0x05; - final static int packet_type_satellite = 0x06; - final static int packet_type_companion = 0x07; - - final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); - final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); - final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; - - static boolean cksum(int[] bytes) { - int sum = 0x5a; - for (int i = 1; i < bytes.length - 1; i++) - sum += bytes[i]; - sum &= 0xff; - return sum == bytes[bytes.length - 1]; - } - - public static AltosTelemetryRecord parse (String hex) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - int[] bytes; - try { - bytes = Altos.hexbytes(hex); - } catch (NumberFormatException ne) { - throw new ParseException(ne.getMessage(), 0); - } - - /* one for length, one for checksum */ - if (bytes[0] != bytes.length - 2) - throw new ParseException(String.format("invalid length %d != %d\n", - bytes[0], - bytes.length - 2), 0); - if (!cksum(bytes)) - throw new ParseException(String.format("invalid line \"%s\"", hex), 0); - - int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; - int status = Altos.uint8(bytes, bytes.length - 2); - - if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) - throw new AltosCRCException(rssi); - - /* length, data ..., rssi, status, checksum -- 4 bytes extra */ - switch (bytes.length) { - case Altos.ao_telemetry_standard_len + 4: - int type = Altos.uint8(bytes, 4 + 1); - switch (type) { - case packet_type_TM_sensor: - case packet_type_Tm_sensor: - case packet_type_Tn_sensor: - r = new AltosTelemetryRecordSensor(bytes, rssi); - break; - case packet_type_configuration: - r = new AltosTelemetryRecordConfiguration(bytes); - break; - case packet_type_location: - r = new AltosTelemetryRecordLocation(bytes); - break; - case packet_type_satellite: - r = new AltosTelemetryRecordSatellite(bytes); - break; - case packet_type_companion: - r = new AltosTelemetryRecordCompanion(bytes); - break; - default: - r = new AltosTelemetryRecordRaw(bytes); - break; - } - break; - case Altos.ao_telemetry_0_9_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - case Altos.ao_telemetry_0_8_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - default: - throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); - } - return r; - } + long received_time; public int int8(int off) { return Altos.int8(bytes, off + 1); @@ -151,4 +70,8 @@ public class AltosTelemetryRecordRaw implements AltosTelemetryRecord { next.tick = tick; return next; } + + public long received_time() { + return received_time; + } } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index fc024fff..3138efac 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -86,7 +86,6 @@ altosui_JAVA = \ AltosRecordIterable.java \ AltosTelemetryReader.java \ AltosTelemetryRecord.java \ - AltosTelemetryRecordGeneral.java \ AltosTelemetryRecordRaw.java \ AltosTelemetryRecordSensor.java \ AltosTelemetryRecordConfiguration.java \ -- cgit v1.2.3 From 8610fdae8f47e1e8b6e8525227cc912664ecfafd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 26 Mar 2012 22:04:13 -0700 Subject: altosui: Show time since last packet in flight status window Makes it easy to see when the UI is wedged, and when telemetry data are being successfully received. Signed-off-by: Keith Packard --- altosui/AltosFlightStatus.java | 18 +++++++++++++++++- altosui/AltosFlightUI.java | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStatus.java b/altosui/AltosFlightStatus.java index ed273384..45e55b4b 100644 --- a/altosui/AltosFlightStatus.java +++ b/altosui/AltosFlightStatus.java @@ -119,18 +119,31 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay value.setText(String.format("%d", state.data.rssi)); } public RSSI (GridBagLayout layout, int x) { - super (layout, x, "RSSI (dBm)"); + super (layout, x, "RSSI"); } } RSSI rssi; + class LastPacket extends FlightValue { + void show(AltosState state, int crc_errors) { + long secs = (System.currentTimeMillis() - state.report_time + 500) / 1000; + value.setText(String.format("%d", secs)); + } + public LastPacket(GridBagLayout layout, int x) { + super (layout, x, "Age"); + } + } + + LastPacket last_packet; + public void reset () { call.reset(); serial.reset(); flight.reset(); flight_state.reset(); rssi.reset(); + last_packet.reset(); } public void set_font () { @@ -139,6 +152,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay flight.set_font(); flight_state.set_font(); rssi.set_font(); + last_packet.set_font(); } public void show (AltosState state, int crc_errors) { @@ -147,6 +161,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay flight.show(state, crc_errors); flight_state.show(state, crc_errors); rssi.show(state, crc_errors); + last_packet.show(state, crc_errors); } public int height() { @@ -164,5 +179,6 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay flight = new Flight(layout, 2); flight_state = new FlightState(layout, 3); rssi = new RSSI(layout, 4); + last_packet = new LastPacket(layout, 5); } } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index d166c9ae..dcf85277 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -28,6 +28,21 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +class AltosFlightStatusUpdate implements ActionListener { + + public AltosState saved_state; + AltosFlightStatus flightStatus; + + public void actionPerformed (ActionEvent e) { + if (saved_state != null) + flightStatus.show(saved_state, 0); + } + + public AltosFlightStatusUpdate (AltosFlightStatus in_flightStatus) { + flightStatus = in_flightStatus; + } +} + public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { AltosVoice voice; AltosFlightReader reader; @@ -98,7 +113,11 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt set_font(); } + + AltosFlightStatusUpdate status_update; + public void show(AltosState state, int crc_errors) { + status_update.saved_state = state; JComponent tab = which_tab(state); try { pad.show(state, crc_errors); @@ -151,6 +170,8 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt AltosFreqList frequencies; JComboBox telemetries; + ActionListener show_timer; + public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) { AltosPreferences.set_component(this); @@ -289,6 +310,10 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt thread = new AltosDisplayThread(this, voice, this, reader); + status_update = new AltosFlightStatusUpdate(flightStatus); + + new javax.swing.Timer(100, status_update).start(); + thread.start(); } -- cgit v1.2.3 From c2550d72aee371676d2f09316051567681e53a7c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 26 Mar 2012 22:05:04 -0700 Subject: altosui: Use ConcurrentHashMap for maps This data structure is accessed by multiple threads, so it needs to be re-entrant. Signed-off-by: Keith Packard --- altosui/AltosSiteMap.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index c258b3e5..63995c40 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -31,6 +31,7 @@ import java.util.prefs.*; import java.lang.Math; import java.awt.geom.Point2D; import java.awt.geom.Line2D; +import java.util.concurrent.*; public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { // preferred vertical step in a tile in naut. miles @@ -110,7 +111,7 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { return latlng(pt, scale_x, scale_y); } - HashMap mapTiles = new HashMap(); + ConcurrentHashMap mapTiles = new ConcurrentHashMap(); Point2D.Double centre; private Point2D.Double tileCoordOffset(Point p) { -- cgit v1.2.3 From d8ebb83e64d66fa159e75aa560d39d80bb6d9d04 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Mar 2012 10:38:32 -0700 Subject: altosui: Configure radio with new direct frequency setting Instead of computing the radio setting in altosui, let the radio do it directly. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 14 ++++++++++++-- altosui/AltosConfigData.java | 3 +++ altosui/AltosConfigUI.java | 1 + altosui/AltosConvert.java | 16 ++++++++++------ altosui/AltosFrequency.java | 2 +- altosui/AltosSerial.java | 19 +++++++++++++++++-- 6 files changed, 44 insertions(+), 11 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 93def70d..84261ec7 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -76,6 +76,7 @@ public class AltosConfig implements ActionListener { int_ref ignite_mode; int_ref pad_orientation; int_ref radio_setting; + int_ref radio_frequency; int_ref storage_size; int_ref storage_erase_unit; int_ref stored_flight; @@ -193,6 +194,7 @@ public class AltosConfig implements ActionListener { get_int(line, "Ignite mode:", ignite_mode); get_int(line, "Pad orientation:", pad_orientation); get_int(line, "Radio setting:", radio_setting); + get_int(line, "Frequency:", radio_frequency); get_int(line, "Radio enable:", radio_enable); get_int(line, "Storage size:", storage_size); get_int(line, "Storage erase unit:", storage_erase_unit); @@ -230,6 +232,7 @@ public class AltosConfig implements ActionListener { apogee_delay.set(0); radio_channel.set(0); radio_setting.set(0); + radio_frequency.set(0); radio_calibration.set(1186611); radio_enable.set(-1); flight_log_max.set(0); @@ -275,6 +278,7 @@ public class AltosConfig implements ActionListener { void save_data() { try { double frequency = frequency(); + boolean has_frequency = radio_frequency.get() > 0; boolean has_setting = radio_setting.get() > 0; start_serial(); serial_line.printf("c m %d\n", main_deploy.get()); @@ -282,6 +286,7 @@ public class AltosConfig implements ActionListener { if (!remote) serial_line.printf("c f %d\n", radio_calibration.get()); serial_line.set_radio_frequency(frequency, + has_frequency, has_setting, radio_calibration.get()); if (remote) { @@ -378,15 +383,19 @@ public class AltosConfig implements ActionListener { } double frequency() { - return AltosConvert.radio_to_frequency(radio_setting.get(), + return AltosConvert.radio_to_frequency(radio_frequency.get(), + radio_setting.get(), radio_calibration.get(), radio_channel.get()); } void set_frequency(double freq) { + int frequency = radio_frequency.get(); int setting = radio_setting.get(); - if (setting > 0) { + if (frequency > 0) { + radio_frequency.set((int) Math.floor (freq * 1000 + 0.5)); + } else if (setting > 0) { radio_setting.set(AltosConvert.radio_frequency_to_setting(freq, radio_calibration.get())); radio_channel.set(0); @@ -453,6 +462,7 @@ public class AltosConfig implements ActionListener { apogee_delay = new int_ref(0); radio_channel = new int_ref(0); radio_setting = new int_ref(0); + radio_frequency = new int_ref(0); radio_calibration = new int_ref(1186611); radio_enable = new int_ref(-1); flight_log_max = new int_ref(0); diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index c14dc5a1..e5c3566b 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -49,6 +49,7 @@ public class AltosConfigData implements Iterable { int apogee_delay; int radio_channel; int radio_setting; + int radio_frequency; String callsign; int accel_cal_plus, accel_cal_minus; int radio_calibration; @@ -107,6 +108,7 @@ public class AltosConfigData implements Iterable { serial_line.printf("c s\nf\nl\nv\n"); lines = new LinkedList(); radio_setting = 0; + radio_frequency = 0; stored_flight = 0; for (;;) { String line = serial_line.get_reply(); @@ -121,6 +123,7 @@ public class AltosConfigData implements Iterable { try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} + try { radio_frequency = get_int(line, "Frequency:"); } catch (Exception e) {} try { if (line.startsWith("Accel cal")) { String[] bits = line.split("\\s+"); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 9fef8e3b..c8ec06d2 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -638,6 +638,7 @@ public class AltosConfigUI AltosFrequency new_frequency = new AltosFrequency(new_radio_frequency, description); AltosPreferences.add_common_frequency(new_frequency); radio_frequency_value.insertItemAt(new_frequency, i); + radio_frequency_value.setSelectedIndex(i); } public double radio_frequency() { diff --git a/altosui/AltosConvert.java b/altosui/AltosConvert.java index db7039ec..df41a522 100644 --- a/altosui/AltosConvert.java +++ b/altosui/AltosConvert.java @@ -190,14 +190,18 @@ public class AltosConvert { return ignite / 32767 * 15.0; } - static double radio_to_frequency(int setting, int cal, int channel) { + static double radio_to_frequency(int freq, int setting, int cal, int channel) { double f; - if (setting <= 0) - setting = cal; - f = 434.550 * setting / cal; - /* Round to nearest 50KHz */ - f = Math.floor (20.0 * f + 0.5) / 20.0; + if (freq > 0) + f = freq / 1000.0; + else { + if (setting <= 0) + setting = cal; + f = 434.550 * setting / cal; + /* Round to nearest 50KHz */ + f = Math.floor (20.0 * f + 0.5) / 20.0; + } return f + channel * 0.100; } diff --git a/altosui/AltosFrequency.java b/altosui/AltosFrequency.java index 0617ce74..b748e460 100644 --- a/altosui/AltosFrequency.java +++ b/altosui/AltosFrequency.java @@ -35,7 +35,7 @@ public class AltosFrequency { String description; public String toString() { - return String.format("%7.3f MHz %-20.20s", + return String.format("%7.3f MHz %-20s", frequency, description); } diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 4cf306d0..ff1a91a5 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -363,12 +363,26 @@ public class AltosSerial implements Runnable { } } + private void set_radio_freq(int frequency) { + if (altos != null) { + if (monitor_mode) + printf("m 0\nc F %d\nm %x\n", + frequency, telemetry_len()); + else + printf("c F %d\n", frequency); + flush_output(); + } + } + public void set_radio_frequency(double frequency, + boolean has_frequency, boolean has_setting, int cal) { if (debug) - System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); - if (has_setting) + System.out.printf("set_radio_frequency %7.3f (freq %b) (set %b) %d\n", frequency, has_frequency, has_setting, cal); + if (has_frequency) + set_radio_freq((int) Math.floor (frequency * 1000)); + else if (has_setting) set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); else set_channel(AltosConvert.radio_frequency_to_channel(frequency)); @@ -378,6 +392,7 @@ public class AltosSerial implements Runnable { frequency = in_frequency; config_data(); set_radio_frequency(frequency, + config_data.radio_frequency != 0, config_data.radio_setting != 0, config_data.radio_calibration); } -- cgit v1.2.3 From d77a4ea206d627635159f35c76c744687d4e633b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Mar 2012 11:58:39 -0700 Subject: altosui: Show only supported telemetry version Make it clear in the UI which telemetry versions are supported, providing the combobox only for new firmware which supports all versions. Signed-off-by: Keith Packard --- altosui/AltosConfigData.java | 33 +++++++++++++++++ altosui/AltosFlightReader.java | 2 ++ altosui/AltosFlightUI.java | 74 +++++++++++++++++++++++++-------------- altosui/AltosTelemetryReader.java | 27 ++++++++++++++ 4 files changed, 110 insertions(+), 26 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index e5c3566b..0608b4d3 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -104,6 +104,39 @@ public class AltosConfigData implements Iterable { } } + int[] parse_version(String v) { + String[] parts = v.split("\\."); + int r[] = new int[parts.length]; + + for (int i = 0; i < parts.length; i++) { + try { + r[i] = Altos.fromdec(parts[i]); + } catch (NumberFormatException n) { + r[i] = 0; + } + } + + return r; + } + + public int compare_version(String other) { + int[] me = parse_version(version); + int[] them = parse_version(other); + + int l = Math.min(me.length, them.length); + + for (int i = 0; i < l; i++) { + int d = me[i] - them[i]; + if (d != 0) + return d; + } + if (me.length > l) + return 1; + if (them.length > l) + return -1; + return 0; + } + public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { serial_line.printf("c s\nf\nl\nv\n"); lines = new LinkedList(); diff --git a/altosui/AltosFlightReader.java b/altosui/AltosFlightReader.java index 47df375d..3ddf171d 100644 --- a/altosui/AltosFlightReader.java +++ b/altosui/AltosFlightReader.java @@ -43,5 +43,7 @@ public class AltosFlightReader { void update(AltosState state) throws InterruptedException { } + boolean supports_telemetry(int telemetry) { return false; } + File backing_file() { return null; } } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index dcf85277..d99da43d 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -169,6 +169,7 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt Container bag; AltosFreqList frequencies; JComboBox telemetries; + JLabel telemetry; ActionListener show_timer; @@ -216,32 +217,53 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt bag.add (frequencies, c); // Telemetry format menu - telemetries = new JComboBox(); - for (int i = 1; i <= Altos.ao_telemetry_max; i++) - telemetries.addItem(Altos.telemetry_name(i)); - int telemetry = AltosPreferences.telemetry(serial); - if (telemetry <= Altos.ao_telemetry_off || - telemetry > Altos.ao_telemetry_max) - telemetry = Altos.ao_telemetry_standard; - telemetries.setSelectedIndex(telemetry - 1); - telemetries.setMaximumRowCount(Altos.ao_telemetry_max); - telemetries.setPreferredSize(null); - telemetries.revalidate(); - telemetries.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int telemetry = telemetries.getSelectedIndex() + 1; - reader.set_telemetry(telemetry); - reader.save_telemetry(); - } - }); - c.gridx = 1; - c.gridy = 0; - c.weightx = 0; - c.weighty = 0; - c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.WEST; - bag.add (telemetries, c); - c.insets = new Insets(0, 0, 0, 0); + if (reader.supports_telemetry(Altos.ao_telemetry_standard)) { + telemetries = new JComboBox(); + for (int i = 1; i <= Altos.ao_telemetry_max; i++) + telemetries.addItem(Altos.telemetry_name(i)); + int telemetry = AltosPreferences.telemetry(serial); + if (telemetry <= Altos.ao_telemetry_off || + telemetry > Altos.ao_telemetry_max) + telemetry = Altos.ao_telemetry_standard; + telemetries.setSelectedIndex(telemetry - 1); + telemetries.setMaximumRowCount(Altos.ao_telemetry_max); + telemetries.setPreferredSize(null); + telemetries.revalidate(); + telemetries.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int telemetry = telemetries.getSelectedIndex() + 1; + reader.set_telemetry(telemetry); + reader.save_telemetry(); + } + }); + c.gridx = 1; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + bag.add (telemetries, c); + c.insets = new Insets(0, 0, 0, 0); + } else { + String version; + + if (reader.supports_telemetry(Altos.ao_telemetry_0_9)) + version = "Telemetry: 0.9"; + else if (reader.supports_telemetry(Altos.ao_telemetry_0_8)) + version = "Telemetry: 0.8"; + else + version = "Telemetry: None"; + + telemetry = new JLabel(version); + c.gridx = 1; + c.gridy = 0; + c.weightx = 0; + c.weighty = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.WEST; + bag.add (telemetry, c); + c.insets = new Insets(0, 0, 0, 0); + } } /* Flight status is always visible */ diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 1f327a67..85dc9cbc 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -56,6 +56,33 @@ class AltosTelemetryReader extends AltosFlightReader { serial.set_radio_frequency(frequency); } + public boolean supports_telemetry(int telemetry) { + + try { + /* Version 1.0 or later firmware supports all telemetry formats */ + if (serial.config_data().compare_version("1.0") >= 0) + return true; + + /* Version 0.9 firmware only supports 0.9 telemetry */ + if (serial.config_data().compare_version("0.9") >= 0) { + if (telemetry == Altos.ao_telemetry_0_9) + return true; + else + return false; + } + + /* Version 0.8 firmware only supports 0.8 telemetry */ + if (telemetry == Altos.ao_telemetry_0_8) + return true; + else + return false; + } catch (InterruptedException ie) { + return true; + } catch (TimeoutException te) { + return true; + } + } + void save_frequency() { AltosPreferences.set_frequency(device.getSerial(), frequency); } -- cgit v1.2.3 From 0952224c36eba25db34bd147d2d579c66b15bbf8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Mar 2012 18:24:51 -0700 Subject: altosui: Change flight data saving UI to separate download/delete selections First pop up a dialog to select flights for download. Download them. Then, after that, pop up a *new* dialog to select flights for delete. Offer to delete all of the downloaded flights by default. Then delete the flights. Signed-off-by: Keith Packard --- altosui/AltosEepromDelete.java | 2 +- altosui/AltosEepromDownload.java | 2 +- altosui/AltosEepromLog.java | 8 ++--- altosui/AltosEepromManage.java | 72 +++++++++++++++++++++------------------- altosui/AltosEepromSelect.java | 45 ++++++------------------- 5 files changed, 52 insertions(+), 77 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index a9d77788..fcce8155 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -90,7 +90,7 @@ public class AltosEepromDelete implements Runnable { serial_line.start_remote(); for (AltosEepromLog log : flights) { - if (log.delete) { + if (log.selected) { DeleteLog(log); } } diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index e7e52466..40c98bfd 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -351,7 +351,7 @@ public class AltosEepromDownload implements Runnable { for (AltosEepromLog log : flights) { parse_exception = null; - if (log.download) { + if (log.selected) { monitor.reset(); CaptureLog(log); } diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index ee77e5c8..475d7f12 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -43,8 +43,7 @@ public class AltosEepromLog { int year, month, day; - boolean download; - boolean delete; + boolean selected; public AltosEepromLog(AltosConfigData config_data, AltosSerial serial_line, @@ -63,10 +62,9 @@ public class AltosEepromLog { serial = config_data.serial; /* - * By default, request that every log be downloaded but not deleted + * Select all flights for download */ - download = true; - delete = false; + selected = true; /* * Look in TeleMetrum log data for date diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index 083c7372..1e06f4ca 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -39,8 +39,6 @@ public class AltosEepromManage implements ActionListener { AltosEepromList flights; AltosEepromDownload download; AltosEepromDelete delete; - boolean any_download; - boolean any_delete; public void finish() { if (serial_line != null) { @@ -57,7 +55,7 @@ public class AltosEepromManage implements ActionListener { String result = ""; for (AltosEepromLog flight : flights) { - if (flight.delete) { + if (flight.selected) { if (result.equals("")) result = String.format("%d", flight.flight); else @@ -67,18 +65,38 @@ public class AltosEepromManage implements ActionListener { return result; } + public boolean download_done() { + AltosEepromSelect select = new AltosEepromSelect(frame, flights, "Delete"); + + if (select.run()) { + boolean any_selected = false; + for (AltosEepromLog flight : flights) + any_selected = any_selected || flight.selected; + if (any_selected) { + delete = new AltosEepromDelete(frame, + serial_line, + remote, + flights); + delete.addActionListener(this); + /* + * Start flight log delete + */ + + delete.start(); + return true; + } + } + return false; + } + public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); boolean success = e.getID() != 0; boolean running = false; if (cmd.equals("download")) { - if (success) { - if (any_delete) { - delete.start(); - running = true; - } - } + if (success) + running = download_done(); } else if (cmd.equals("delete")) { if (success) { JOptionPane.showMessageDialog(frame, @@ -104,40 +122,26 @@ public class AltosEepromManage implements ActionListener { serial_line.device.toShortString(), JOptionPane.INFORMATION_MESSAGE); } else { - AltosEepromSelect select = new AltosEepromSelect(frame, flights); + AltosEepromSelect select = new AltosEepromSelect(frame, flights, "Download"); if (select.run()) { - for (AltosEepromLog flight : flights) { - any_download = any_download || flight.download; - any_delete = any_delete || flight.delete; - } - if (any_download) { + boolean any_selected = false; + for (AltosEepromLog flight : flights) + any_selected = any_selected || flight.selected; + if (any_selected) { download = new AltosEepromDownload(frame, serial_line, remote, flights); download.addActionListener(this); - } - - if (any_delete) { - delete = new AltosEepromDelete(frame, - serial_line, - remote, - flights); - delete.addActionListener(this); - } + /* + * Start flight log download + */ - /* - * Start flight log download - */ - - if (any_download) { download.start(); running = true; - } - else if (any_delete) { - delete.start(); - running = true; + } else { + running = download_done(); } } } @@ -203,8 +207,6 @@ public class AltosEepromManage implements ActionListener { device = AltosDeviceDialog.show(frame, Altos.product_any); remote = false; - any_download = false; - any_delete = false; if (device != null) { try { diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index ebafc4c8..e0fbeead 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -31,15 +31,11 @@ import libaltosJNI.SWIGTYPE_p_altos_list; class AltosEepromItem implements ActionListener { AltosEepromLog log; JLabel label; - JCheckBox download; + JCheckBox action; JCheckBox delete; public void actionPerformed(ActionEvent e) { - if (e.getSource() == download) { - log.download = download.isSelected(); - } else if (e.getSource() == delete) { - log.delete = delete.isSelected(); - } + log.selected = action.isSelected(); } public AltosEepromItem(AltosEepromLog in_log) { @@ -54,11 +50,8 @@ class AltosEepromItem implements ActionListener { label = new JLabel(text); - download = new JCheckBox("", log.download); - download.addActionListener(this); - - delete = new JCheckBox("", log.delete); - delete.addActionListener(this); + action = new JCheckBox("", log.selected); + action.addActionListener(this); } } @@ -86,7 +79,8 @@ public class AltosEepromSelect extends AltosDialog implements ActionListener { } public AltosEepromSelect (JFrame in_frame, - AltosEepromList flights) { + AltosEepromList flights, + String action) { super(in_frame, String.format("Flight list for serial %d", flights.config_data.serial), true); frame = in_frame; @@ -95,7 +89,7 @@ public class AltosEepromSelect extends AltosDialog implements ActionListener { Container contentPane = getContentPane(); /* First, we create a pane containing the dialog's header/title */ - JLabel selectLabel = new JLabel("Select flights to download and/or delete", SwingConstants.CENTER); + JLabel selectLabel = new JLabel(String.format ("Select flights to %s", action), SwingConstants.CENTER); JPanel labelPane = new JPanel(); labelPane.setLayout(new BoxLayout(labelPane, BoxLayout.X_AXIS)); @@ -132,19 +126,9 @@ public class AltosEepromSelect extends AltosDialog implements ActionListener { c.weightx = 0.5; c.anchor = GridBagConstraints.CENTER; c.insets = i; - JLabel downloadHeaderLabel = new JLabel("Download"); + JLabel downloadHeaderLabel = new JLabel(action); flightPane.add(downloadHeaderLabel, c); - /* Delete Header */ - c = new GridBagConstraints(); - c.gridx = 2; c.gridy = 0; - c.fill = GridBagConstraints.NONE; - c.weightx = 0.5; - c.anchor = GridBagConstraints.CENTER; - c.insets = i; - JLabel deleteHeaderLabel = new JLabel("Delete"); - flightPane.add(deleteHeaderLabel, c); - /* Add the flights to the GridBag */ AltosEepromItem item; int itemNumber = 1; @@ -163,23 +147,14 @@ public class AltosEepromSelect extends AltosDialog implements ActionListener { c.insets = i; flightPane.add(item.label, c); - /* Add a download checkbox for the flight */ + /* Add action checkbox for the flight */ c = new GridBagConstraints(); c.gridx = 1; c.gridy = itemNumber; c.fill = GridBagConstraints.NONE; c.weightx = 0.5; c.anchor = GridBagConstraints.CENTER; c.insets = i; - flightPane.add(item.download, c); - - /* Add a delete checkbox for the flight */ - c = new GridBagConstraints(); - c.gridx = 2; c.gridy = itemNumber; - c.fill = GridBagConstraints.NONE; - c.weightx = 0.5; - c.anchor = GridBagConstraints.CENTER; - c.insets = i; - flightPane.add(item.delete, c); + flightPane.add(item.action, c); itemNumber++; } -- cgit v1.2.3 From 170510bb183715e9ba580b180f20657d6602644e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Mar 2012 21:13:31 -0700 Subject: altosui: Find actual landing time when computing stats (trac #23) Look for the last time the height went from >10m to <2m from the nominal landing altitude and use that as the landing time when computing things like main descent speed, time under main etc. Signed-off-by: Keith Packard --- altosui/AltosFlightStats.java | 124 ++++++++++++++++++++++++------------------ altosui/AltosUI.java | 16 ++++-- 2 files changed, 82 insertions(+), 58 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index 72d12600..dce5cb3e 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -43,60 +43,88 @@ public class AltosFlightStats { int year, month, day; int hour, minute, second; - public AltosFlightStats(AltosFlightReader reader) throws InterruptedException, IOException { + double landed_time(AltosRecordIterable iterable) { + AltosState state = null; + for (AltosRecord record : iterable) { + state = new AltosState(record, state); + + if (state.state == Altos.ao_flight_landed) + break; + } + + double landed_height = state.height; + + state = null; + + boolean above = true; + + double landed_time = -1000; + + for (AltosRecord record : iterable) { + state = new AltosState(record, state); + + if (state.height > landed_height + 10) { + above = true; + } else { + if (above && state.height < landed_height + 2) { + above = false; + landed_time = state.time; + } + } + } + if (landed_time == -1000) + landed_time = state.time; + return landed_time; + } + + public AltosFlightStats(AltosRecordIterable iterable) throws InterruptedException, IOException { AltosState state = null; AltosState new_state = null; double boost_time = -1; double end_time = 0; + double landed_time = landed_time(iterable); year = month = day = -1; hour = minute = second = -1; serial = flight = -1; - for (;;) { - try { - AltosRecord record = reader.read(); - if (record == null) - break; - if (serial < 0) - serial = record.serial; - if ((record.seen & AltosRecord.seen_flight) != 0 && flight < 0) - flight = record.flight; - new_state = new AltosState(record, state); - end_time = new_state.time; - state = new_state; - if (0 <= state.state && state.state < Altos.ao_flight_invalid) { - if (state.state >= Altos.ao_flight_boost) { - if (boost_time == -1) - boost_time = state.time; - if (state.gps != null && state.gps.locked && - year < 0) { - year = state.gps.year; - month = state.gps.month; - day = state.gps.day; - hour = state.gps.hour; - minute = state.gps.minute; - second = state.gps.second; - } + for (AltosRecord record : iterable) { + if (serial < 0) + serial = record.serial; + if ((record.seen & AltosRecord.seen_flight) != 0 && flight < 0) + flight = record.flight; + new_state = new AltosState(record, state); + end_time = new_state.time; + state = new_state; + if (0 <= state.state && state.state < Altos.ao_flight_invalid) { + if (state.state >= Altos.ao_flight_boost) { + if (boost_time == -1) + boost_time = state.time; + if (state.gps != null && state.gps.locked && + year < 0) { + year = state.gps.year; + month = state.gps.month; + day = state.gps.day; + hour = state.gps.hour; + minute = state.gps.minute; + second = state.gps.second; } - state_accel[state.state] += state.acceleration; - state_speed[state.state] += state.speed; - state_baro_speed[state.state] += state.baro_speed; - state_count[state.state]++; - if (state_start[state.state] == 0.0) - state_start[state.state] = state.time; - if (state_end[state.state] < state.time) - state_end[state.state] = state.time; - max_height = state.max_height; - if (state.max_speed != 0) - max_speed = state.max_speed; - else - max_speed = state.max_baro_speed; - max_acceleration = state.max_acceleration; } - } catch (ParseException pp) { - System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage()); - } catch (AltosCRCException ce) { - + if (state.time >= landed_time) + state.state = Altos.ao_flight_landed; + state_accel[state.state] += state.acceleration; + state_speed[state.state] += state.speed; + state_baro_speed[state.state] += state.baro_speed; + state_count[state.state]++; + if (state_start[state.state] == 0.0) + state_start[state.state] = state.time; + if (state_end[state.state] < state.time) + state_end[state.state] = state.time; + max_height = state.max_height; + if (state.max_speed != 0) + max_speed = state.max_speed; + else + max_speed = state.max_baro_speed; + max_acceleration = state.max_acceleration; } } for (int s = Altos.ao_flight_startup; s <= Altos.ao_flight_landed; s++) { @@ -111,12 +139,4 @@ public class AltosFlightStats { state_end[s] = end_time; } } - - public AltosFlightStats(AltosRecordIterable iterable, File file) throws InterruptedException, IOException { - this(new AltosReplayReader(iterable.iterator(), file)); - } - - public AltosFlightStats(AltosRecordIterable iterable) throws InterruptedException, IOException { - this(iterable, new File("")); - } } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 8799d560..89f66c06 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -423,17 +423,17 @@ public class AltosUI extends AltosFrame { } } - static AltosRecordIterable record_iterable_file(String filename) { + static AltosRecordIterable record_iterable(File file) { FileInputStream in; try { - in = new FileInputStream(filename); + in = new FileInputStream(file); } catch (Exception e) { - System.out.printf("Failed to open file '%s'\n", filename); + System.out.printf("Failed to open file '%s'\n", file); return null; } AltosRecordIterable recs; AltosReplayReader reader; - if (filename.endsWith("eeprom")) { + if (file.getName().endsWith("eeprom")) { recs = new AltosEepromIterable(in); } else { recs = new AltosTelemetryIterable(in); @@ -441,6 +441,10 @@ public class AltosUI extends AltosFrame { return recs; } + static AltosRecordIterable record_iterable_file(String filename) { + return record_iterable (new File(filename)); + } + static AltosReplayReader replay_file(String filename) { AltosRecordIterable recs = record_iterable_file(filename); if (recs == null) @@ -466,9 +470,9 @@ public class AltosUI extends AltosFrame { } static void process_summary(String filename) { - AltosReplayReader reader = replay_file(filename); + AltosRecordIterable iterable = record_iterable_file(filename); try { - AltosFlightStats stats = new AltosFlightStats(reader); + AltosFlightStats stats = new AltosFlightStats(iterable); if (stats.serial > 0) System.out.printf("Serial: %5d\n", stats.serial); if (stats.flight > 0) -- cgit v1.2.3 From 2f19f9a0eaba22789fdc07a52849e8aaf6fe4695 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Mar 2012 21:48:43 -0700 Subject: altosui: Catch attempt to set radio frequency to 0.0 -- use default Monitor idle was setting the frequency to 0, which takes a while with the new native radio frequency setting code. Don't do that, instead pull out the preferred frequency for that, as is done in other places where a frequency of 0.0 is used. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index ff1a91a5..dffc74ea 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -380,6 +380,8 @@ public class AltosSerial implements Runnable { int cal) { if (debug) System.out.printf("set_radio_frequency %7.3f (freq %b) (set %b) %d\n", frequency, has_frequency, has_setting, cal); + if (frequency == 0) + return; if (has_frequency) set_radio_freq((int) Math.floor (frequency * 1000)); else if (has_setting) @@ -390,6 +392,8 @@ public class AltosSerial implements Runnable { public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { frequency = in_frequency; + if (frequency == 0.0) + frequency = AltosPreferences.frequency(device.getSerial()); config_data(); set_radio_frequency(frequency, config_data.radio_frequency != 0, -- cgit v1.2.3 From 7a9baabaf33db5e30eb4ef8f923a4fd96fd28fb4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Mar 2012 21:49:58 -0700 Subject: altosui: Mark data 'Age' in monitor idle UI too Just like with the flight monitor UI, it's nice to know how old the data in the monitor idle UI is, in case the data link to the TM isn't reliable. Signed-off-by: Keith Packard --- altosui/AltosFlightStatusUpdate.java | 45 ++++++++++++++++++++++++++++++++++++ altosui/AltosFlightUI.java | 15 ------------ altosui/AltosIdleMonitorUI.java | 7 ++++++ altosui/Makefile.am | 1 + 4 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 altosui/AltosFlightStatusUpdate.java (limited to 'altosui') diff --git a/altosui/AltosFlightStatusUpdate.java b/altosui/AltosFlightStatusUpdate.java new file mode 100644 index 00000000..a600bd02 --- /dev/null +++ b/altosui/AltosFlightStatusUpdate.java @@ -0,0 +1,45 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosFlightStatusUpdate implements ActionListener { + + public AltosState saved_state; + AltosFlightStatus flightStatus; + + public void actionPerformed (ActionEvent e) { + if (saved_state != null) + flightStatus.show(saved_state, 0); + } + + public AltosFlightStatusUpdate (AltosFlightStatus in_flightStatus) { + flightStatus = in_flightStatus; + } +} + diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index d99da43d..b2ae4858 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -28,21 +28,6 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; -class AltosFlightStatusUpdate implements ActionListener { - - public AltosState saved_state; - AltosFlightStatus flightStatus; - - public void actionPerformed (ActionEvent e) { - if (saved_state != null) - flightStatus.show(saved_state, 0); - } - - public AltosFlightStatusUpdate (AltosFlightStatus in_flightStatus) { - flightStatus = in_flightStatus; - } -} - public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { AltosVoice voice; AltosFlightReader reader; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index a5f41e25..dbac2d33 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -293,7 +293,10 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay set_font(); } + AltosFlightStatusUpdate status_update; + public void show(AltosState state, int crc_errors) { + status_update.saved_state = state; try { pad.show(state, crc_errors); flightStatus.show(state, crc_errors); @@ -399,6 +402,10 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay thread = new AltosIdleMonitor(this, device, remote); + status_update = new AltosFlightStatusUpdate(flightStatus); + + new javax.swing.Timer(100, status_update).start(); + thread.start(); } } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 3138efac..f89340fb 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -56,6 +56,7 @@ altosui_JAVA = \ AltosFlightStats.java \ AltosFlightStatsTable.java \ AltosFlightStatus.java \ + AltosFlightStatusUpdate.java \ AltosFlightUI.java \ AltosFontListener.java \ AltosFrequency.java \ -- cgit v1.2.3 From 3f0379db7067eaf104892a82b9c49142087adece Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Mar 2012 22:02:13 -0700 Subject: altosui: Make 'monitor idle' work with older TeleMetrum firmware (trac #28) Older TM firmware did not have the 'done' line at the end of the GPS report, rather it would just stop after showing the Flags value. Check the TM version and stop looking for GPS data when the Flags line appears. Signed-off-by: Keith Packard --- altosui/AltosIdleMonitorUI.java | 10 ++++++++-- altosui/AltosSerial.java | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index dbac2d33..d877be4d 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -90,7 +90,9 @@ class AltosADC { } class AltosGPSQuery extends AltosGPS { - public AltosGPSQuery (AltosSerial serial) throws TimeoutException, InterruptedException { + public AltosGPSQuery (AltosSerial serial, AltosConfigData config_data) + throws TimeoutException, InterruptedException { + boolean says_done = config_data.compare_version("1.0") >= 0; serial.printf("g\n"); for (;;) { String line = serial.get_reply_no_dialog(5000); @@ -140,6 +142,8 @@ class AltosGPSQuery extends AltosGPS { int status = Integer.decode(bits[1]); connected = (status & Altos.AO_GPS_RUNNING) != 0; locked = (status & Altos.AO_GPS_VALID) != 0; + if (!says_done) + break; continue; } if (line.startsWith("Sats:")) { @@ -184,7 +188,7 @@ class AltosIdleMonitor extends Thread { serial.flush_input(); config_data = new AltosConfigData(serial); adc = new AltosADC(serial); - gps = new AltosGPSQuery(serial); + gps = new AltosGPSQuery(serial, config_data); } finally { if (remote) serial.stop_remote(); @@ -237,6 +241,8 @@ class AltosIdleMonitor extends Thread { update_state(); post_state(); } catch (TimeoutException te) { + if (AltosSerial.debug) + System.out.printf ("monitor idle data timeout\n"); } Thread.sleep(1000); } diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index dffc74ea..77c926b1 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -55,7 +55,7 @@ public class AltosSerial implements Runnable { boolean monitor_mode; int telemetry; double frequency; - static boolean debug; + public static boolean debug; boolean remote; LinkedList pending_output = new LinkedList(); Frame frame; -- cgit v1.2.3 From b98f75dbcccd40c8cbf32c3bfd21bd6f5648b861 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 27 Mar 2012 22:54:17 -0700 Subject: altosui: Sanity check values from device configuration If someone has down-graded and re up-graded the firmware, the config entries may be garbage. Sanity check them to avoid crashing the UI. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 4 +++- altosui/AltosConfigData.java | 6 +++++- altosui/AltosConfigUI.java | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 84261ec7..8eb71e1f 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -194,7 +194,9 @@ public class AltosConfig implements ActionListener { get_int(line, "Ignite mode:", ignite_mode); get_int(line, "Pad orientation:", pad_orientation); get_int(line, "Radio setting:", radio_setting); - get_int(line, "Frequency:", radio_frequency); + if (get_int(line, "Frequency:", radio_frequency)) + if (radio_frequency.get() < 0) + radio_frequency.set(434550); get_int(line, "Radio enable:", radio_enable); get_int(line, "Storage size:", storage_size); get_int(line, "Storage erase unit:", storage_erase_unit); diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 0608b4d3..53509dfa 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -156,7 +156,11 @@ public class AltosConfigData implements Iterable { try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} - try { radio_frequency = get_int(line, "Frequency:"); } catch (Exception e) {} + try { + radio_frequency = get_int(line, "Frequency:"); + if (radio_frequency < 0) + radio_frequency = 434550; + } catch (Exception e) {} try { if (line.startsWith("Accel cal")) { String[] bits = line.split("\\s+"); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index c8ec06d2..879605bc 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -708,6 +708,8 @@ public class AltosConfigUI } public void set_ignite_mode(int new_ignite_mode) { + if (new_ignite_mode >= ignite_mode_values.length) + new_ignite_mode = 0; if (new_ignite_mode < 0) { ignite_mode_value.setEnabled(false); new_ignite_mode = 0; @@ -727,6 +729,8 @@ public class AltosConfigUI public void set_pad_orientation(int new_pad_orientation) { + if (new_pad_orientation >= pad_orientation_values.length) + new_pad_orientation = 0; if (new_pad_orientation < 0) { pad_orientation_value.setEnabled(false); new_pad_orientation = 0; -- cgit v1.2.3 From cf1e95810559584705d0b8a787375938c68e07c6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 28 Mar 2012 00:37:52 -0700 Subject: altosui: Add Configure Ground Station dialog (trac #29) Allows the user to configure the teledongle frequency without opening up the flight monitor window, and also shows the teledongle fixed values like radio calibration, serial number and software version. Signed-off-by: Keith Packard --- altosui/AltosConfigTD.java | 373 +++++++++++++++++++++++++++++++++++++++++++ altosui/AltosConfigTDUI.java | 353 ++++++++++++++++++++++++++++++++++++++++ altosui/AltosUI.java | 31 ++-- altosui/Makefile.am | 2 + 4 files changed, 750 insertions(+), 9 deletions(-) create mode 100644 altosui/AltosConfigTD.java create mode 100644 altosui/AltosConfigTDUI.java (limited to 'altosui') diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java new file mode 100644 index 00000000..68f746b2 --- /dev/null +++ b/altosui/AltosConfigTD.java @@ -0,0 +1,373 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosConfigTD implements ActionListener { + + class int_ref { + int value; + + public int get() { + return value; + } + public void set(int i) { + value = i; + } + public int_ref(int i) { + value = i; + } + } + + class string_ref { + String value; + + public String get() { + return value; + } + public void set(String i) { + value = i; + } + public string_ref(String i) { + value = i; + } + } + + JFrame owner; + AltosDevice device; + AltosSerial serial_line; + int_ref serial; + int_ref radio_channel; + int_ref radio_calibration; + int_ref radio_setting; + int_ref radio_frequency; + string_ref config_version; + string_ref version; + string_ref product; + AltosConfigTDUI config_ui; + boolean serial_started; + boolean made_visible; + + boolean get_int(String line, String label, int_ref x) { + if (line.startsWith(label)) { + try { + String tail = line.substring(label.length()).trim(); + String[] tokens = tail.split("\\s+"); + if (tokens.length > 0) { + int i = Integer.parseInt(tokens[0]); + x.set(i); + return true; + } + } catch (NumberFormatException ne) { + } + } + return false; + } + + boolean get_string(String line, String label, string_ref s) { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + s.set(quoted); + return true; + } else { + return false; + } + } + + void start_serial() throws InterruptedException, TimeoutException { + serial_started = true; + } + + void stop_serial() throws InterruptedException { + if (!serial_started) + return; + serial_started = false; + } + + void update_ui() { + config_ui.set_serial(serial.get()); + config_ui.set_product(product.get()); + config_ui.set_version(version.get()); + config_ui.set_radio_frequency(frequency()); + config_ui.set_radio_calibration(radio_calibration.get()); + config_ui.set_clean(); + if (!made_visible) { + made_visible = true; + config_ui.make_visible(); + } + } + + void process_line(String line) { + if (line == null) { + abort(); + return; + } + if (line.equals("all finished")) { + if (serial_line != null) + update_ui(); + return; + } + get_string(line, "Config version", config_version); + get_int(line, "serial-number", serial); + get_int(line, "Radio channel:", radio_channel); + if (get_int(line, "Radio cal:", radio_calibration)) + System.out.printf("got radio cal %d\n", radio_calibration.get()); + get_int(line, "Radio setting:", radio_setting); + get_string(line,"software-version", version); + get_string(line,"product", product); + } + + final static int serial_mode_read = 0; + final static int serial_mode_save = 1; + final static int serial_mode_reboot = 2; + + class SerialData implements Runnable { + AltosConfigTD config; + int serial_mode; + + void process_line(String line) { + config.process_line(line); + } + void callback(String in_line) { + final String line = in_line; + Runnable r = new Runnable() { + public void run() { + process_line(line); + } + }; + SwingUtilities.invokeLater(r); + } + + void reset_data() { + serial.set(0); + radio_channel.set(0); + radio_setting.set(0); + radio_frequency.set(0); + radio_calibration.set(1186611); + config_version.set("0.0"); + version.set("unknown"); + product.set("unknown"); + } + + void get_data() { + try { + boolean been_there = false; + config.start_serial(); + reset_data(); + + for (;;) { + config.serial_line.printf("c s\nf\nl\nv\n"); + for (;;) { + try { + String line = config.serial_line.get_reply(5000); + if (line == null) + stop_serial(); + callback(line); + if (line.startsWith("software-version")) + break; + } catch (Exception e) { + break; + } + } + System.out.printf("config_version %s\n", config_version.get()); + if (been_there) + break; + if (!config_version.get().equals("0.0")) + break; + been_there = true; + config.serial_line.printf("C\n "); + config.serial_line.flush_input(); + } + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + } finally { + try { + stop_serial(); + } catch (InterruptedException ie) { + } + } + double pref_frequency = AltosPreferences.frequency(serial.get()); + if (pref_frequency != 0) + radio_frequency.set((int) Math.floor (pref_frequency * 1000 + 0.5)); + callback("all finished"); + } + + void save_data() { + double frequency = frequency(); + if (frequency != 0) + AltosPreferences.set_frequency(serial.get(), + frequency); + } + + public void run () { + switch (serial_mode) { + case serial_mode_save: + save_data(); + /* fall through ... */ + case serial_mode_read: + get_data(); + break; + } + } + + public SerialData(AltosConfigTD in_config, int in_serial_mode) { + config = in_config; + serial_mode = in_serial_mode; + } + } + + void run_serial_thread(int serial_mode) { + SerialData sd = new SerialData(this, serial_mode); + Thread st = new Thread(sd); + st.start(); + } + + void init_ui () throws InterruptedException, TimeoutException { + config_ui = new AltosConfigTDUI(owner); + config_ui.addActionListener(this); + serial_line.set_frame(owner); + set_ui(); + } + + void abort() { + serial_line.close(); + serial_line = null; + JOptionPane.showMessageDialog(owner, + String.format("Connection to \"%s\" failed", + device.toShortString()), + "Connection Failed", + JOptionPane.ERROR_MESSAGE); + config_ui.setVisible(false); + } + + void set_ui() throws InterruptedException, TimeoutException { + if (serial_line != null) + run_serial_thread(serial_mode_read); + else + update_ui(); + } + + double frequency() { + return AltosConvert.radio_to_frequency(radio_frequency.get(), + radio_setting.get(), + radio_calibration.get(), + radio_channel.get()); + } + + void set_frequency(double freq) { + int frequency = radio_frequency.get(); + int setting = radio_setting.get(); + + if (frequency > 0) { + radio_frequency.set((int) Math.floor (freq * 1000 + 0.5)); + } else if (setting > 0) { + radio_setting.set(AltosConvert.radio_frequency_to_setting(freq, + radio_calibration.get())); + radio_channel.set(0); + } else { + radio_channel.set(AltosConvert.radio_frequency_to_channel(freq)); + } + } + + void save_data() { + + set_frequency(config_ui.radio_frequency()); + run_serial_thread(serial_mode_save); + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + try { + if (cmd.equals("Save")) { + save_data(); + } else if (cmd.equals("Reset")) { + set_ui(); + } else if (cmd.equals("Reboot")) { + if (serial_line != null) + run_serial_thread(serial_mode_reboot); + } else if (cmd.equals("Close")) { + if (serial_line != null) + serial_line.close(); + } + } catch (InterruptedException ie) { + abort(); + } catch (TimeoutException te) { + abort(); + } + } + + public AltosConfigTD(JFrame given_owner) { + owner = given_owner; + + serial = new int_ref(0); + radio_channel = new int_ref(0); + radio_setting = new int_ref(0); + radio_frequency = new int_ref(0); + radio_calibration = new int_ref(1186611); + config_version = new string_ref("0.0"); + version = new string_ref("unknown"); + product = new string_ref("unknown"); + + device = AltosDeviceDialog.show(owner, Altos.product_basestation); + if (device != null) { + try { + serial_line = new AltosSerial(device); + try { + init_ui(); + } catch (InterruptedException ie) { + abort(); + } catch (TimeoutException te) { + abort(); + } + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(owner, + ee.getMessage(), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(owner, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException ee) { + JOptionPane.showMessageDialog(owner, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + } + } + } +} \ No newline at end of file diff --git a/altosui/AltosConfigTDUI.java b/altosui/AltosConfigTDUI.java new file mode 100644 index 00000000..9f6badc7 --- /dev/null +++ b/altosui/AltosConfigTDUI.java @@ -0,0 +1,353 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +import libaltosJNI.*; + +public class AltosConfigTDUI + extends AltosDialog + implements ActionListener, ItemListener, DocumentListener +{ + + Container pane; + Box box; + JLabel product_label; + JLabel version_label; + JLabel serial_label; + JLabel frequency_label; + JLabel radio_calibration_label; + JLabel radio_frequency_label; + + public boolean dirty; + + JFrame owner; + JLabel product_value; + JLabel version_value; + JLabel serial_value; + AltosFreqList radio_frequency_value; + JLabel radio_calibration_value; + + JButton save; + JButton reset; + JButton reboot; + JButton close; + + ActionListener listener; + + + /* A window listener to catch closing events and tell the config code */ + class ConfigListener extends WindowAdapter { + AltosConfigTDUI ui; + + public ConfigListener(AltosConfigTDUI this_ui) { + ui = this_ui; + } + + public void windowClosing(WindowEvent e) { + ui.actionPerformed(new ActionEvent(e.getSource(), + ActionEvent.ACTION_PERFORMED, + "Close")); + } + } + + /* Build the UI using a grid bag */ + public AltosConfigTDUI(JFrame in_owner) { + super (in_owner, "Configure TeleDongle", false); + + owner = in_owner; + GridBagConstraints c; + + Insets il = new Insets(4,4,4,4); + Insets ir = new Insets(4,4,4,4); + + pane = getContentPane(); + pane.setLayout(new GridBagLayout()); + + /* Product */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 0; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + product_label = new JLabel("Product:"); + pane.add(product_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 0; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + product_value = new JLabel(""); + pane.add(product_value, c); + + /* Version */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 1; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + version_label = new JLabel("Software version:"); + pane.add(version_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 1; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + version_value = new JLabel(""); + pane.add(version_value, c); + + /* Serial */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 2; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + serial_label = new JLabel("Serial:"); + pane.add(serial_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 2; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + serial_value = new JLabel(""); + pane.add(serial_value, c); + + /* Frequency */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 5; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + radio_frequency_label = new JLabel("Frequency:"); + pane.add(radio_frequency_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 5; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + radio_frequency_value = new AltosFreqList(); + radio_frequency_value.addItemListener(this); + pane.add(radio_frequency_value, c); + radio_frequency_value.setToolTipText("Telemetry, RDF and packet frequency"); + + /* Radio Calibration */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 6; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + radio_calibration_label = new JLabel("RF Calibration:"); + pane.add(radio_calibration_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = 6; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + radio_calibration_value = new JLabel(String.format("%d", 1186611)); + pane.add(radio_calibration_value, c); + + /* Buttons */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 12; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + save = new JButton("Save"); + pane.add(save, c); + save.addActionListener(this); + save.setActionCommand("Save"); + + c = new GridBagConstraints(); + c.gridx = 2; c.gridy = 12; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.CENTER; + c.insets = il; + reset = new JButton("Reset"); + pane.add(reset, c); + reset.addActionListener(this); + reset.setActionCommand("Reset"); + + c = new GridBagConstraints(); + c.gridx = 6; c.gridy = 12; + c.gridwidth = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + c.insets = il; + close = new JButton("Close"); + pane.add(close, c); + close.addActionListener(this); + close.setActionCommand("Close"); + + addWindowListener(new ConfigListener(this)); + } + + /* Once the initial values are set, the config code will show the dialog */ + public void make_visible() { + pack(); + setLocationRelativeTo(owner); + setVisible(true); + } + + /* If any values have been changed, confirm before closing */ + public boolean check_dirty(String operation) { + if (dirty) { + Object[] options = { String.format("%s anyway", operation), "Keep editing" }; + int i; + i = JOptionPane.showOptionDialog(this, + String.format("Configuration modified. %s anyway?", operation), + "Configuration Modified", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, options, options[1]); + if (i != 0) + return false; + } + return true; + } + + /* Listen for events from our buttons */ + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if (cmd.equals("Close") || cmd.equals("Reboot")) + if (!check_dirty(cmd)) + return; + listener.actionPerformed(e); + if (cmd.equals("Close") || cmd.equals("Reboot")) { + setVisible(false); + dispose(); + } + dirty = false; + } + + /* ItemListener interface method */ + public void itemStateChanged(ItemEvent e) { + dirty = true; + } + + /* DocumentListener interface methods */ + public void changedUpdate(DocumentEvent e) { + dirty = true; + } + + public void insertUpdate(DocumentEvent e) { + dirty = true; + } + + public void removeUpdate(DocumentEvent e) { + dirty = true; + } + + /* Let the config code hook on a listener */ + public void addActionListener(ActionListener l) { + listener = l; + } + + /* set and get all of the dialog values */ + public void set_product(String product) { + radio_frequency_value.set_product(product); + product_value.setText(product); + } + + public void set_version(String version) { + version_value.setText(version); + } + + public void set_serial(int serial) { + radio_frequency_value.set_serial(serial); + serial_value.setText(String.format("%d", serial)); + } + + public void set_radio_frequency(double new_radio_frequency) { + int i; + for (i = 0; i < radio_frequency_value.getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i); + + if (f.close(new_radio_frequency)) { + radio_frequency_value.setSelectedIndex(i); + return; + } + } + for (i = 0; i < radio_frequency_value.getItemCount(); i++) { + AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i); + + if (new_radio_frequency < f.frequency) + break; + } + String description = String.format("%s serial %s", + product_value.getText(), + serial_value.getText()); + AltosFrequency new_frequency = new AltosFrequency(new_radio_frequency, description); + AltosPreferences.add_common_frequency(new_frequency); + radio_frequency_value.insertItemAt(new_frequency, i); + radio_frequency_value.setSelectedIndex(i); + } + + public double radio_frequency() { + return radio_frequency_value.frequency(); + } + + public void set_radio_calibration(int calibration) { + radio_calibration_value.setText(String.format("%d", calibration)); + } + + public void set_clean() { + dirty = false; + } +} diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 89f66c06..75a12ece 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -165,28 +165,29 @@ public class AltosUI extends AltosFrame { } }); b.setToolTipText("Global AltosUI settings"); - b = addButton(2, 1, "Flash Image"); + + b = addButton(2, 1, "Configure Ground Station"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - FlashImage(); + ConfigureTeleDongle(); } }); - b.setToolTipText("Replace the firmware in any AltusMetrum product"); - b = addButton(3, 1, "Fire Igniter"); + b = addButton(3, 1, "Flash Image"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - FireIgniter(); + FlashImage(); } }); - b.setToolTipText("Remote control of igniters for deployment testing"); - b = addButton(4, 1, "Quit"); + b.setToolTipText("Replace the firmware in any AltusMetrum product"); + + b = addButton(4, 1, "Fire Igniter"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - System.exit(0); + FireIgniter(); } }); - b.setToolTipText("Close all active windows and terminate AltosUI"); + b.setToolTipText("Remote control of igniters for deployment testing"); b = addButton(0, 2, "Scan Channels"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -216,6 +217,14 @@ public class AltosUI extends AltosFrame { } }); + b = addButton(4, 2, "Quit"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.exit(0); + } + }); + b.setToolTipText("Close all active windows and terminate AltosUI"); + setTitle("AltOS"); pane.doLayout(); @@ -262,6 +271,10 @@ public class AltosUI extends AltosFrame { new AltosConfig(AltosUI.this); } + void ConfigureTeleDongle() { + new AltosConfigTD(AltosUI.this); + } + void FlashImage() { AltosFlashUI.show(AltosUI.this); } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index f89340fb..d436c6a0 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -26,6 +26,8 @@ altosui_JAVA = \ AltosConfigFreqUI.java \ AltosConfigUI.java \ AltosConfigureUI.java \ + AltosConfigTD.java \ + AltosConfigTDUI.java \ AltosConvert.java \ AltosCRCException.java \ AltosCSV.java \ -- cgit v1.2.3 From bdfcc9112c41c494de23594963980a730b625cc4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 28 Mar 2012 00:49:29 -0700 Subject: altosui: Disable launch controller button The launch controller should just be a separate program. Signed-off-by: Keith Packard --- altosui/AltosUI.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 75a12ece..6993abab 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -210,12 +210,12 @@ public class AltosUI extends AltosFrame { }); b.setToolTipText("Check flight readiness of altimeter in idle mode"); - b = addButton(3, 2, "Launch Controller"); - b.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - LaunchController(); - } - }); +// b = addButton(3, 2, "Launch Controller"); +// b.addActionListener(new ActionListener() { +// public void actionPerformed(ActionEvent e) { +// LaunchController(); +// } +// }); b = addButton(4, 2, "Quit"); b.addActionListener(new ActionListener() { -- cgit v1.2.3 From 5569e4df50648a3ec131ba5e244da9b67d1a67db Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Apr 2012 00:21:03 -0700 Subject: altosui: Radio channel gets set to zero by altos when frequency is set Just remember what the channe is going to get set to. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 8eb71e1f..bb2665c2 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -397,6 +397,7 @@ public class AltosConfig implements ActionListener { if (frequency > 0) { radio_frequency.set((int) Math.floor (freq * 1000 + 0.5)); + radio_channel.set(0); } else if (setting > 0) { radio_setting.set(AltosConvert.radio_frequency_to_setting(freq, radio_calibration.get())); -- cgit v1.2.3 From 20066268d8d1853055d0afe108584db34b425fcb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Apr 2012 18:35:26 -0700 Subject: altosui: Integrate accel speed from very start of eeprom record Don't wait for the flight computer to have detected boost--that's often several samples after boost actually occurred, which can leave a bunch of acceleration out of the speed computation. Signed-off-by: Keith Packard --- altosui/AltosEepromIterable.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index d8205816..6fdaf8e0 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -99,6 +99,7 @@ public class AltosEepromIterable extends AltosRecordIterable { double ground_pres; int gps_tick; int boost_tick; + int sensor_tick; EepromState() { seen = 0; @@ -128,10 +129,13 @@ public class AltosEepromIterable extends AltosRecordIterable { state.flight_pres = state.ground_pres; } else { state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; - state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; - state.flight_vel += (state.accel_plus_g - state.accel); } + state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; + if ((eeprom.seen & seen_sensor) == 0) + eeprom.sensor_tick = record.tick - 1; + state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick); eeprom.seen |= seen_sensor; + eeprom.sensor_tick = record.tick; has_accel = true; break; case Altos.AO_LOG_PRESSURE: -- cgit v1.2.3 From e56038b65ba1c6413ba9942be3c092644986f126 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Apr 2012 18:36:36 -0700 Subject: altosui: When computing flight stats, auto-detect boost time Detect when boost actually starts by looking for the last low acceleration value before the recorded boost time. This improves the computation of the boost state data. Signed-off-by: Keith Packard --- altosui/AltosFlightStats.java | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index dce5cb3e..ed5a336e 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -77,10 +77,30 @@ public class AltosFlightStats { return landed_time; } + double boost_time(AltosRecordIterable iterable) { + double boost_time = -1000; + + AltosState state = null; + + for (AltosRecord record : iterable) { + state = new AltosState(record, state); + + if (state.acceleration < 1) + boost_time = state.time; + if (state.state >= Altos.ao_flight_boost) + break; + } + if (boost_time == -1000) + boost_time = state.time; + System.out.printf ("boost time %f instead of %f\n", boost_time, state.time); + return boost_time; + } + + public AltosFlightStats(AltosRecordIterable iterable) throws InterruptedException, IOException { AltosState state = null; AltosState new_state = null; - double boost_time = -1; + double boost_time = boost_time(iterable); double end_time = 0; double landed_time = landed_time(iterable); @@ -95,10 +115,12 @@ public class AltosFlightStats { new_state = new AltosState(record, state); end_time = new_state.time; state = new_state; + if (state.time >= boost_time && state.state < Altos.ao_flight_boost) + state.state = Altos.ao_flight_boost; + if (state.time >= landed_time && state.state < Altos.ao_flight_landed) + state.state = Altos.ao_flight_landed; if (0 <= state.state && state.state < Altos.ao_flight_invalid) { if (state.state >= Altos.ao_flight_boost) { - if (boost_time == -1) - boost_time = state.time; if (state.gps != null && state.gps.locked && year < 0) { year = state.gps.year; @@ -109,8 +131,6 @@ public class AltosFlightStats { second = state.gps.second; } } - if (state.time >= landed_time) - state.state = Altos.ao_flight_landed; state_accel[state.state] += state.acceleration; state_speed[state.state] += state.speed; state_baro_speed[state.state] += state.baro_speed; -- cgit v1.2.3 From fa96ee3db9b57cc2a88e9edd74bb9efcc228ccf3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Apr 2012 18:44:11 -0700 Subject: altosui: remove debug printf from AltosFlightStats Signed-off-by: Keith Packard --- altosui/AltosFlightStats.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index ed5a336e..578be3f9 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -92,7 +92,6 @@ public class AltosFlightStats { } if (boost_time == -1000) boost_time = state.time; - System.out.printf ("boost time %f instead of %f\n", boost_time, state.time); return boost_time; } -- cgit v1.2.3 From b4ab9f5dfa9f2a50e0528acf0a1fdeaa1f9bc523 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Apr 2012 13:52:37 -0700 Subject: altosui: Read frequency from device while configuring ground station Missed this when adding the TD config UI. Signed-off-by: Keith Packard --- altosui/AltosConfigTD.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java index 68f746b2..d3c452e1 100644 --- a/altosui/AltosConfigTD.java +++ b/altosui/AltosConfigTD.java @@ -144,6 +144,8 @@ public class AltosConfigTD implements ActionListener { get_int(line, "Radio channel:", radio_channel); if (get_int(line, "Radio cal:", radio_calibration)) System.out.printf("got radio cal %d\n", radio_calibration.get()); + if (get_int(line, "Frequency:", radio_frequency)) + System.out.printf("got radio freq %d\n", radio_frequency.get()); get_int(line, "Radio setting:", radio_setting); get_string(line,"software-version", version); get_string(line,"product", product); -- cgit v1.2.3 From cc305ea231ae22278abf91c0d9925f5992945369 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Apr 2012 13:53:36 -0700 Subject: altosui: Add apogee lockout configuration Provide suggested values of 5/10/15/20 seconds. Signed-off-by: Keith Packard --- altosui/AltosConfig.java | 7 +++ altosui/AltosConfigUI.java | 109 +++++++++++++++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 28 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index bb2665c2..58da405f 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -70,6 +70,7 @@ public class AltosConfig implements ActionListener { int_ref log_format; int_ref main_deploy; int_ref apogee_delay; + int_ref apogee_lockout; int_ref radio_channel; int_ref radio_calibration; int_ref flight_log_max; @@ -148,6 +149,7 @@ public class AltosConfig implements ActionListener { config_ui.set_version(version.get()); config_ui.set_main_deploy(main_deploy.get()); config_ui.set_apogee_delay(apogee_delay.get()); + config_ui.set_apogee_lockout(apogee_lockout.get()); config_ui.set_radio_calibration(radio_calibration.get()); config_ui.set_radio_frequency(frequency()); boolean max_enabled = true; @@ -188,6 +190,7 @@ public class AltosConfig implements ActionListener { get_int(line, "log-format", log_format); get_int(line, "Main deploy:", main_deploy); get_int(line, "Apogee delay:", apogee_delay); + get_int(line, "Apogee lockout:", apogee_lockout); get_int(line, "Radio channel:", radio_channel); get_int(line, "Radio cal:", radio_calibration); get_int(line, "Max flight log:", flight_log_max); @@ -232,6 +235,7 @@ public class AltosConfig implements ActionListener { log_format.set(Altos.AO_LOG_FORMAT_UNKNOWN); main_deploy.set(250); apogee_delay.set(0); + apogee_lockout.set(0); radio_channel.set(0); radio_setting.set(0); radio_frequency.set(0); @@ -285,6 +289,7 @@ public class AltosConfig implements ActionListener { start_serial(); serial_line.printf("c m %d\n", main_deploy.get()); serial_line.printf("c d %d\n", apogee_delay.get()); + serial_line.printf("c L %d\n", apogee_lockout.get()); if (!remote) serial_line.printf("c f %d\n", radio_calibration.get()); serial_line.set_radio_frequency(frequency, @@ -422,6 +427,7 @@ public class AltosConfig implements ActionListener { main_deploy.set(config_ui.main_deploy()); apogee_delay.set(config_ui.apogee_delay()); + apogee_lockout.set(config_ui.apogee_lockout()); radio_calibration.set(config_ui.radio_calibration()); set_frequency(config_ui.radio_frequency()); flight_log_max.set(config_ui.flight_log_max()); @@ -463,6 +469,7 @@ public class AltosConfig implements ActionListener { log_format = new int_ref(Altos.AO_LOG_FORMAT_UNKNOWN); main_deploy = new int_ref(250); apogee_delay = new int_ref(0); + apogee_lockout = new int_ref(0); radio_channel = new int_ref(0); radio_setting = new int_ref(0); radio_frequency = new int_ref(0); diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 879605bc..b0cd7f27 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -43,6 +43,7 @@ public class AltosConfigUI JLabel serial_label; JLabel main_deploy_label; JLabel apogee_delay_label; + JLabel apogee_lockout_label; JLabel frequency_label; JLabel radio_calibration_label; JLabel radio_frequency_label; @@ -60,6 +61,7 @@ public class AltosConfigUI JLabel serial_value; JComboBox main_deploy_value; JComboBox apogee_delay_value; + JComboBox apogee_lockout_value; AltosFreqList radio_frequency_value; JTextField radio_calibration_value; JRadioButton radio_enable_value; @@ -84,6 +86,10 @@ public class AltosConfigUI "0", "1", "2", "3", "4", "5" }; + static String[] apogee_lockout_values = { + "0", "5", "10", "15", "20" + }; + static String[] flight_log_max_values = { "64", "128", "192", "256", "320", "384", "448", "512", "576", "640", @@ -179,6 +185,7 @@ public class AltosConfigUI owner = in_owner; GridBagConstraints c; + int row = 0; Insets il = new Insets(4,4,4,4); Insets ir = new Insets(4,4,4,4); @@ -188,7 +195,7 @@ public class AltosConfigUI /* Product */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 0; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -197,7 +204,7 @@ public class AltosConfigUI pane.add(product_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 0; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -205,10 +212,11 @@ public class AltosConfigUI c.insets = ir; product_value = new JLabel(""); pane.add(product_value, c); + row++; /* Version */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 1; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -218,7 +226,7 @@ public class AltosConfigUI pane.add(version_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 1; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -227,10 +235,11 @@ public class AltosConfigUI c.ipady = 5; version_value = new JLabel(""); pane.add(version_value, c); + row++; /* Serial */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 2; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -240,7 +249,7 @@ public class AltosConfigUI pane.add(serial_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 2; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -249,10 +258,11 @@ public class AltosConfigUI c.ipady = 5; serial_value = new JLabel(""); pane.add(serial_value, c); + row++; /* Main deploy */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 3; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -262,7 +272,7 @@ public class AltosConfigUI pane.add(main_deploy_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 3; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -274,10 +284,11 @@ public class AltosConfigUI main_deploy_value.addItemListener(this); pane.add(main_deploy_value, c); main_deploy_value.setToolTipText("Height above pad altitude to fire main charge"); + row++; /* Apogee delay */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 4; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -287,7 +298,7 @@ public class AltosConfigUI pane.add(apogee_delay_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 4; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -299,10 +310,37 @@ public class AltosConfigUI apogee_delay_value.addItemListener(this); pane.add(apogee_delay_value, c); apogee_delay_value.setToolTipText("Delay after apogee before charge fires"); + row++; + + /* Apogee lockout */ + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = row; + c.gridwidth = 4; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + c.ipady = 5; + apogee_lockout_label = new JLabel("Apogee Lockout(s):"); + pane.add(apogee_lockout_label, c); + + c = new GridBagConstraints(); + c.gridx = 4; c.gridy = row; + c.gridwidth = 4; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.anchor = GridBagConstraints.LINE_START; + c.insets = ir; + c.ipady = 5; + apogee_lockout_value = new JComboBox(apogee_lockout_values); + apogee_lockout_value.setEditable(true); + apogee_lockout_value.addItemListener(this); + pane.add(apogee_lockout_value, c); + apogee_lockout_value.setToolTipText("Time after boost while apogee detection is locked out"); + row++; /* Frequency */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 5; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -312,7 +350,7 @@ public class AltosConfigUI pane.add(radio_frequency_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 5; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -323,10 +361,11 @@ public class AltosConfigUI radio_frequency_value.addItemListener(this); pane.add(radio_frequency_value, c); radio_frequency_value.setToolTipText("Telemetry, RDF and packet frequency"); + row++; /* Radio Calibration */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 6; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -336,7 +375,7 @@ public class AltosConfigUI pane.add(radio_calibration_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 6; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -349,10 +388,11 @@ public class AltosConfigUI radio_calibration_value.setEnabled(false); pane.add(radio_calibration_value, c); set_radio_calibration_tool_tip(); + row++; /* Radio Enable */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 7; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -362,7 +402,7 @@ public class AltosConfigUI pane.add(radio_enable_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 7; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -373,10 +413,11 @@ public class AltosConfigUI radio_enable_value.addItemListener(this); pane.add(radio_enable_value, c); set_radio_enable_tool_tip(); + row++; /* Callsign */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 8; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -386,7 +427,7 @@ public class AltosConfigUI pane.add(callsign_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 8; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -397,10 +438,11 @@ public class AltosConfigUI callsign_value.getDocument().addDocumentListener(this); pane.add(callsign_value, c); callsign_value.setToolTipText("Callsign reported in telemetry data"); + row++; /* Flight log max */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 9; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -410,7 +452,7 @@ public class AltosConfigUI pane.add(flight_log_max_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 9; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -422,10 +464,11 @@ public class AltosConfigUI flight_log_max_value.addItemListener(this); pane.add(flight_log_max_value, c); set_flight_log_max_tool_tip(); + row++; /* Ignite mode */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 10; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -435,7 +478,7 @@ public class AltosConfigUI pane.add(ignite_mode_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 10; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -447,10 +490,11 @@ public class AltosConfigUI ignite_mode_value.addItemListener(this); pane.add(ignite_mode_value, c); set_ignite_mode_tool_tip(); + row++; /* Pad orientation */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 11; + c.gridx = 0; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -460,7 +504,7 @@ public class AltosConfigUI pane.add(pad_orientation_label, c); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 11; + c.gridx = 4; c.gridy = row; c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1; @@ -472,10 +516,11 @@ public class AltosConfigUI pad_orientation_value.addItemListener(this); pane.add(pad_orientation_value, c); set_pad_orientation_tool_tip(); + row++; /* Buttons */ c = new GridBagConstraints(); - c.gridx = 0; c.gridy = 12; + c.gridx = 0; c.gridy = row; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; @@ -486,7 +531,7 @@ public class AltosConfigUI save.setActionCommand("Save"); c = new GridBagConstraints(); - c.gridx = 2; c.gridy = 12; + c.gridx = 2; c.gridy = row; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -497,7 +542,7 @@ public class AltosConfigUI reset.setActionCommand("Reset"); c = new GridBagConstraints(); - c.gridx = 4; c.gridy = 12; + c.gridx = 4; c.gridy = row; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; @@ -508,7 +553,7 @@ public class AltosConfigUI reboot.setActionCommand("Reboot"); c = new GridBagConstraints(); - c.gridx = 6; c.gridy = 12; + c.gridx = 6; c.gridy = row; c.gridwidth = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_END; @@ -616,6 +661,14 @@ public class AltosConfigUI return Integer.parseInt(apogee_delay_value.getSelectedItem().toString()); } + public void set_apogee_lockout(int new_apogee_lockout) { + apogee_lockout_value.setSelectedItem(Integer.toString(new_apogee_lockout)); + } + + public int apogee_lockout() { + return Integer.parseInt(apogee_lockout_value.getSelectedItem().toString()); + } + public void set_radio_frequency(double new_radio_frequency) { int i; for (i = 0; i < radio_frequency_value.getItemCount(); i++) { -- cgit v1.2.3 From 5f55d0490017faa19b8d70b1742e4a45266c7e79 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 20 Apr 2012 22:26:16 -0500 Subject: altosui: Mac OS Lion Java default heap space is too small (Trac #37) Increase it to 512M in the Info.plist file. Signed-off-by: Keith Packard --- altosui/AltosUI.app/Contents/Info.plist | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosUI.app/Contents/Info.plist b/altosui/AltosUI.app/Contents/Info.plist index 97b1b59c..60842804 100644 --- a/altosui/AltosUI.app/Contents/Info.plist +++ b/altosui/AltosUI.app/Contents/Info.plist @@ -29,10 +29,16 @@ JVMVersion 1.5+ ClassPath - + $JAVAROOT/altosui.jar $JAVAROOT/freetts.jar - + + VMOptions + + -Xms512M + -Xmx512M + -Dosgi.clean=true + -- cgit v1.2.3 From b5b898264077fcada29e73efa28dcbe4729f2709 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 7 May 2012 21:53:11 -0700 Subject: altosui: Output recorded clock tick in CSV files This allows eeprom and telem files to be correlated accurately Signed-off-by: Keith Packard --- altosui/AltosCSV.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index cf649db0..9ec21bef 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -31,9 +31,9 @@ public class AltosCSV implements AltosWriter { LinkedList pad_records; AltosState state; - static final int ALTOS_CSV_VERSION = 3; + static final int ALTOS_CSV_VERSION = 4; - /* Version 3 format: + /* Version 4 format: * * General info * version number @@ -41,6 +41,7 @@ public class AltosCSV implements AltosWriter { * flight number * callsign * time (seconds since boost) + * clock (tick count / 100) * rssi * link quality * @@ -91,13 +92,13 @@ public class AltosCSV implements AltosWriter { */ void write_general_header() { - out.printf("version,serial,flight,call,time,rssi,lqi"); + out.printf("version,serial,flight,call,time,clock,rssi,lqi"); } void write_general(AltosRecord record) { - out.printf("%s, %d, %d, %s, %8.2f, %4d, %3d", + out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d", ALTOS_CSV_VERSION, record.serial, record.flight, record.callsign, - (double) record.time, + (double) record.time, (double) record.tick / 100.0, record.rssi, record.status & 0x7f); } -- cgit v1.2.3 From da2c920b9f3378d5a18551e008c1da5dace1e0ef Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 7 May 2012 21:53:53 -0700 Subject: altosui: Try to make telem tick counts match eeprom telem files can have an extra wrap or two of tick count if they start recording a long time before the flight. Account for this so that the CSV file output from each have matching tick values. Signed-off-by: Keith Packard --- altosui/AltosTelemetryIterable.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java index 278cbfb7..a1b25332 100644 --- a/altosui/AltosTelemetryIterable.java +++ b/altosui/AltosTelemetryIterable.java @@ -88,6 +88,15 @@ public class AltosTelemetryIterable extends AltosRecordIterable { if (previous != null) records.add(previous); + /* Adjust all tick counts to match expected eeprom values, + * which starts with a 16-bit tick count 16 samples before boost + */ + + int tick_adjust = (boost_tick - 16) & 0xffff0000; + for (AltosRecord r : this) + r.tick -= tick_adjust; + boost_tick -= tick_adjust; + /* adjust all tick counts to be relative to boost time */ for (AltosRecord r : this) r.time = (r.tick - boost_tick) / 100.0; -- cgit v1.2.3 From 1824761f5b98e92485e2dd347b1c4d043ec207e2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Jun 2012 19:51:25 -0700 Subject: altosui: Quick hacks to download megametrum data and convert to CSV Very little useful data crunching is done, but at least we can save and convert files Signed-off-by: Keith Packard --- altosui/Altos.java | 12 + altosui/AltosCSV.java | 42 ++- altosui/AltosConfigData.java | 2 +- altosui/AltosDataChooser.java | 3 + altosui/AltosEepromChunk.java | 5 + altosui/AltosEepromDownload.java | 67 ++++- altosui/AltosEepromIterable.java | 26 +- altosui/AltosEepromList.java | 4 +- altosui/AltosEepromMega.java | 218 +++++++++++++++ altosui/AltosEepromMegaIterable.java | 523 +++++++++++++++++++++++++++++++++++ altosui/AltosIMU.java | 29 ++ altosui/AltosMag.java | 25 ++ altosui/AltosMs5607.java | 76 +++++ altosui/AltosRecord.java | 5 + altosui/AltosState.java | 5 + altosui/AltosUI.java | 2 + altosui/Makefile.am | 5 + 17 files changed, 1039 insertions(+), 10 deletions(-) create mode 100644 altosui/AltosEepromMega.java create mode 100644 altosui/AltosEepromMegaIterable.java create mode 100644 altosui/AltosIMU.java create mode 100644 altosui/AltosMag.java create mode 100644 altosui/AltosMs5607.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index aa2fd77a..1d393dbe 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -52,6 +52,17 @@ public class Altos { static final int AO_LOG_PRODUCT = 2001; static final int AO_LOG_SERIAL_NUMBER = 2002; static final int AO_LOG_LOG_FORMAT = 2003; + + /* Added for header fields in megametrum files */ + static final int AO_LOG_BARO_RESERVED = 3000; + static final int AO_LOG_BARO_SENS = 3001; + static final int AO_LOG_BARO_OFF = 3002; + static final int AO_LOG_BARO_TCS = 3004; + static final int AO_LOG_BARO_TCO = 3005; + static final int AO_LOG_BARO_TREF = 3006; + static final int AO_LOG_BARO_TEMPSENS = 3007; + static final int AO_LOG_BARO_CRC = 3008; + static final int AO_LOG_SOFTWARE_VERSION = 9999; /* Added to flag invalid records */ @@ -220,6 +231,7 @@ public class Altos { static final int AO_LOG_FORMAT_TINY = 2; static final int AO_LOG_FORMAT_TELEMETRY = 3; static final int AO_LOG_FORMAT_TELESCIENCE = 4; + static final int AO_LOG_FORMAT_MEGAMETRUM = 5; static final int AO_LOG_FORMAT_NONE = 127; static boolean isspace(int c) { diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index 9ec21bef..b88bedba 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -31,7 +31,7 @@ public class AltosCSV implements AltosWriter { LinkedList pad_records; AltosState state; - static final int ALTOS_CSV_VERSION = 4; + static final int ALTOS_CSV_VERSION = 5; /* Version 4 format: * @@ -61,6 +61,17 @@ public class AltosCSV implements AltosWriter { * drogue (V) * main (V) * + * Advanced sensors (if available) + * accel_x (m/s²) + * accel_y (m/s²) + * accel_z (m/s²) + * gyro_x (d/s) + * gyro_y (d/s) + * gyro_z (d/s) + * mag_x (g) + * mag_y (g) + * mag_z (g) + * * GPS data (if available) * connected (1/0) * locked (1/0) @@ -129,6 +140,24 @@ public class AltosCSV implements AltosWriter { record.main_voltage()); } + void write_advanced_header() { + out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z"); + } + + void write_advanced(AltosRecord record) { + AltosIMU imu = record.imu; + AltosMag mag = record.mag; + + if (imu == null) + imu = new AltosIMU(); + if (mag == null) + mag = new AltosMag(); + out.printf("%d,%d,%d,%d,%d,%d,%d,%d,%d", + imu.accel_x, imu.accel_y, imu.accel_z, + imu.gyro_x, imu.gyro_y, imu.gyro_z, + mag.x, mag.y, mag.z); + } + void write_gps_header() { out.printf("connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,hdop"); } @@ -212,10 +241,12 @@ public class AltosCSV implements AltosWriter { out.printf(",0"); } - void write_header(boolean gps, boolean companion) { + void write_header(boolean advanced, boolean gps, boolean companion) { out.printf("#"); write_general_header(); out.printf(","); write_flight_header(); out.printf(","); write_basic_header(); + if (advanced) + out.printf(","); write_advanced_header(); if (gps) { out.printf(","); write_gps_header(); out.printf(","); write_gps_sat_header(); @@ -230,7 +261,9 @@ public class AltosCSV implements AltosWriter { state = new AltosState(record, state); write_general(record); out.printf(","); write_flight(record); out.printf(","); - write_basic(record); + write_basic(record); out.printf(","); + if (record.imu != null || record.mag != null) + write_advanced(record); if (record.gps != null) { out.printf(","); write_gps(record); out.printf(","); @@ -253,7 +286,8 @@ public class AltosCSV implements AltosWriter { if (record.state == Altos.ao_flight_startup) return; if (!header_written) { - write_header(record.gps != null, record.companion != null); + write_header(record.imu != null || record.mag != null, + record.gps != null, record.companion != null); header_written = true; } if (!seen_boost) { diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 53509dfa..64d9f095 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -138,7 +138,7 @@ public class AltosConfigData implements Iterable { } public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { - serial_line.printf("c s\nf\nl\nv\n"); + serial_line.printf("c s\np\nf\nl\nv\n"); lines = new LinkedList(); radio_setting = 0; radio_frequency = 0; diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index d81ca6d1..488e1068 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -56,6 +56,9 @@ public class AltosDataChooser extends JFileChooser { } else if (filename.endsWith("telem")) { FileInputStream in = new FileInputStream(file); return new AltosTelemetryIterable(in); + } else if (filename.endsWith("mega")) { + FileInputStream in = new FileInputStream(file); + return new AltosEepromMegaIterable(in); } else { throw new FileNotFoundException(); } diff --git a/altosui/AltosEepromChunk.java b/altosui/AltosEepromChunk.java index 59767c2a..77707f7b 100644 --- a/altosui/AltosEepromChunk.java +++ b/altosui/AltosEepromChunk.java @@ -52,6 +52,11 @@ public class AltosEepromChunk { return data[offset] | (data[offset + 1] << 8); } + int data32(int offset) { + return data[offset] | (data[offset + 1] << 8) | + (data[offset+2] << 16) | (data[offset+3] << 24); + } + boolean erased(int start, int len) { for (int i = 0; i < len; i++) if (data[start+i] != 0xff) diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 40c98bfd..8f7a8544 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -248,6 +248,64 @@ public class AltosEepromDownload implements Runnable { done = true; } + void LogMega(AltosEepromMega r) throws IOException { + if (r.cmd != Altos.AO_LOG_INVALID) { + String log_line = String.format("%c %4x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n", + r.cmd, r.tick, + r.data8[0], r.data8[1], r.data8[2], r.data8[3], + r.data8[4], r.data8[5], r.data8[6], r.data8[7], + r.data8[8], r.data8[9], r.data8[10], r.data8[11], + r.data8[12], r.data8[13], r.data8[14], r.data8[15], + r.data8[16], r.data8[17], r.data8[18], r.data8[19], + r.data8[20], r.data8[21], r.data8[22], r.data8[23], + r.data8[24], r.data8[25], r.data8[26], r.data8[27]); + if (eeprom_file != null) + eeprom_file.write(log_line); + else + eeprom_pending.add(log_line); + } + } + + void CaptureMega(AltosEepromChunk eechunk) throws IOException { + boolean any_valid = false; + + extension = "mega"; + set_serial(flights.config_data.serial); + for (int i = 0; i < eechunk.chunk_size && !done; i += AltosEepromMega.record_length) { + try { + AltosEepromMega r = new AltosEepromMega(eechunk, i); + if (r.cmd == Altos.AO_LOG_FLIGHT) + set_flight(r.data16(0)); + + /* Monitor state transitions to update display */ + if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) <= Altos.ao_flight_landed) { + state = r.data16(0); + if (state > Altos.ao_flight_pad) + want_file = true; + } + + if (r.cmd == Altos.AO_LOG_GPS_TIME) { + year = 2000 + r.data8(14); + month = r.data8(15); + day = r.data8(14); + want_file = true; + } + + if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) == Altos.ao_flight_landed) + done = true; + any_valid = true; + LogMega(r); + } catch (ParseException pe) { + if (parse_exception == null) + parse_exception = pe; + } + } + if (!any_valid) + done = true; + + CheckFile(false); + } + void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException { } @@ -260,9 +318,11 @@ public class AltosEepromDownload implements Runnable { done = false; start = true; - if (flights.config_data.serial == 0) - throw new IOException("no serial number found"); +// if (flights.config_data.serial == 0) +// throw new IOException("no serial number found"); + log_format = 5; + System.out.printf ("log format: %d\n", log_format); /* Reset per-capture variables */ flight = 0; year = 0; @@ -312,6 +372,9 @@ public class AltosEepromDownload implements Runnable { extension = "science"; CaptureTeleScience(eechunk); break; + case Altos.AO_LOG_FORMAT_MEGAMETRUM: + extension = "mega"; + CaptureMega(eechunk); } } CheckFile(true); diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index 6fdaf8e0..b8e21ece 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -268,7 +268,7 @@ public class AltosEepromIterable extends AltosRecordIterable { AltosRecord r = new AltosRecord(state); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); - return list; + return list; } public Iterator iterator() { @@ -323,6 +323,30 @@ public class AltosEepromIterable extends AltosRecordIterable { case Altos.AO_LOG_SOFTWARE_VERSION: out.printf ("# Software version: %s\n", record.data); break; + case Altos.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", record.a); + break; } } } diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index da4b1166..945746dd 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -62,8 +62,8 @@ public class AltosEepromList extends ArrayList { if (remote) serial_line.start_remote(); config_data = new AltosConfigData (serial_line); - if (config_data.serial == 0) - throw new IOException("no serial number found"); +// if (config_data.serial == 0) +// throw new IOException("no serial number found"); ArrayList flights = new ArrayList(); diff --git a/altosui/AltosEepromMega.java b/altosui/AltosEepromMega.java new file mode 100644 index 00000000..8ae485cb --- /dev/null +++ b/altosui/AltosEepromMega.java @@ -0,0 +1,218 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosEepromMega { + public int cmd; + public int tick; + public boolean valid; + public String data; + int a, b; + + public int data8[]; + + static final int record_length = 32; + static final int header_length = 4; + static final int data_length = record_length - header_length; + + public int data8(int i) { + return data8[i]; + } + + public int data16(int i) { + return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16; + } + + public int data32(int i) { + return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24); + } + + /* AO_LOG_FLIGHT elements */ + public int flight() { return data16(0); } + public int ground_accel() { return data16(2); } + public int ground_pres() { return data32(4); } + public int ground_temp() { return data32(8); } + + /* AO_LOG_STATE elements */ + public int state() { return data16(0); } + public int reason() { return data16(2); } + + /* AO_LOG_SENSOR elements */ + public int pres() { return data32(0); } + public int temp() { return data32(4); } + public int accel_x() { return data16(8); } + public int accel_y() { return data16(10); } + public int accel_z() { return data16(12); } + public int gyro_x() { return data16(14); } + public int gyro_y() { return data16(16); } + public int gyro_z() { return data16(18); } + public int mag_x() { return data16(20); } + public int mag_y() { return data16(22); } + public int mag_z() { return data16(24); } + public int accel() { + int a = data16(26); + if (a != 0xffff) + return a; + return accel_y(); + } + + /* AO_LOG_VOLT elements */ + public int v_batt() { return data16(0); } + public int v_pbatt() { return data16(2); } + public int nsense() { return data16(4); } + public int sense(int i) { return data16(6 + i * 2); } + + public AltosEepromMega (AltosEepromChunk chunk, int start) throws ParseException { + cmd = chunk.data(start); + + valid = !chunk.erased(start, record_length); + if (valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + cmd = Altos.AO_LOG_INVALID; + } + + tick = chunk.data16(start+2); + + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = chunk.data(start + header_length + i); + } + + public AltosEepromMega (String line) { + valid = false; + tick = 0; + + if (line == null) { + cmd = Altos.AO_LOG_INVALID; + line = ""; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 2 + data_length) { + cmd = Altos.AO_LOG_INVALID; + data = line; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + valid = true; + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = Integer.parseInt(tokens[2 + i],16); + } + } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { + cmd = Altos.AO_LOG_CONFIG_VERSION; + data = tokens[2]; + } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { + cmd = Altos.AO_LOG_MAIN_DEPLOY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { + cmd = Altos.AO_LOG_APOGEE_DELAY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { + cmd = Altos.AO_LOG_RADIO_CHANNEL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Callsign:")) { + cmd = Altos.AO_LOG_CALLSIGN; + data = tokens[1].replaceAll("\"",""); + } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { + cmd = Altos.AO_LOG_ACCEL_CAL; + a = Integer.parseInt(tokens[3]); + b = Integer.parseInt(tokens[5]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { + cmd = Altos.AO_LOG_RADIO_CAL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { + cmd = Altos.AO_LOG_MAX_FLIGHT_LOG; + a = Integer.parseInt(tokens[3]); + } else if (tokens[0].equals("manufacturer")) { + cmd = Altos.AO_LOG_MANUFACTURER; + data = tokens[1]; + } else if (tokens[0].equals("product")) { + cmd = Altos.AO_LOG_PRODUCT; + data = tokens[1]; + } else if (tokens[0].equals("serial-number")) { + cmd = Altos.AO_LOG_SERIAL_NUMBER; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("log-format")) { + cmd = Altos.AO_LOG_LOG_FORMAT; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("software-version")) { + cmd = Altos.AO_LOG_SOFTWARE_VERSION; + data = tokens[1]; + } else if (tokens[0].equals("ms5607")) { + if (tokens[1].equals("reserved:")) { + cmd = Altos.AO_LOG_BARO_RESERVED; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("sens:")) { + cmd = Altos.AO_LOG_BARO_SENS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("off:")) { + cmd = Altos.AO_LOG_BARO_OFF; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tcs:")) { + cmd = Altos.AO_LOG_BARO_TCS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tco:")) { + cmd = Altos.AO_LOG_BARO_TCO; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tref:")) { + cmd = Altos.AO_LOG_BARO_TREF; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tempsens:")) { + cmd = Altos.AO_LOG_BARO_TEMPSENS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("crc:")) { + cmd = Altos.AO_LOG_BARO_CRC; + a = Integer.parseInt(tokens[2]); + } else { + cmd = Altos.AO_LOG_INVALID; + data = line; + } + } else { + cmd = Altos.AO_LOG_INVALID; + data = line; + } + } catch (NumberFormatException ne) { + cmd = Altos.AO_LOG_INVALID; + data = line; + } + } + } + + public AltosEepromMega(int in_cmd, int in_tick) { + cmd = in_cmd; + tick = in_tick; + valid = true; + } +} diff --git a/altosui/AltosEepromMegaIterable.java b/altosui/AltosEepromMegaIterable.java new file mode 100644 index 00000000..e2cd2785 --- /dev/null +++ b/altosui/AltosEepromMegaIterable.java @@ -0,0 +1,523 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * AltosRecords with an index field so they can be sorted by tick while preserving + * the original ordering for elements with matching ticks + */ +class AltosOrderedMegaRecord extends AltosEepromMega implements Comparable { + + public int index; + + public AltosOrderedMegaRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) + throws ParseException { + super(line); + if (prev_tick_valid) { + tick |= (prev_tick & ~0xffff); + if (tick < prev_tick) { + if (prev_tick - tick > 0x8000) + tick += 0x10000; + } else { + if (tick - prev_tick > 0x8000) + tick -= 0x10000; + } + } + index = in_index; + } + + public AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { + super(in_cmd, in_tick); + a = in_a; + b = in_b; + index = in_index; + } + + public String toString() { + return String.format("%d.%d %04x %04x %04x", + cmd, index, tick, a, b); + } + + public int compareTo(AltosOrderedMegaRecord o) { + int tick_diff = tick - o.tick; + if (tick_diff != 0) + return tick_diff; + return index - o.index; + } +} + +public class AltosEepromMegaIterable extends AltosRecordIterable { + + static final int seen_flight = 1; + static final int seen_sensor = 2; + static final int seen_temp_volt = 4; + static final int seen_deploy = 8; + static final int seen_gps_time = 16; + static final int seen_gps_lat = 32; + static final int seen_gps_lon = 64; + + static final int seen_basic = seen_flight|seen_sensor; + + boolean has_accel; + boolean has_gps; + boolean has_ignite; + + AltosEepromMega flight_record; + AltosEepromMega gps_date_record; + + TreeSet records; + + AltosMs5607 baro; + + LinkedList list; + + class EepromState { + int seen; + int n_pad_samples; + double ground_pres; + int gps_tick; + int boost_tick; + int sensor_tick; + + EepromState() { + seen = 0; + n_pad_samples = 0; + ground_pres = 0.0; + gps_tick = 0; + } + } + + void update_state(AltosRecord state, AltosEepromMega record, EepromState eeprom) { + state.tick = record.tick; + switch (record.cmd) { + case Altos.AO_LOG_FLIGHT: + eeprom.seen |= seen_flight; + state.ground_accel = record.ground_accel(); + state.flight_accel = record.ground_accel(); + state.ground_pres = baro.set(record.ground_pres(), record.ground_temp()); + state.flight_pres = state.ground_pres; + state.flight = record.data16(0); + eeprom.boost_tick = record.tick; + break; + case Altos.AO_LOG_SENSOR: + state.accel = record.accel(); + state.pres = baro.set(record.pres(), record.temp()); + state.temp = baro.cc; + state.imu = new AltosIMU(); + state.imu.accel_x = record.accel_x(); + state.imu.accel_y = record.accel_y(); + state.imu.accel_z = record.accel_z(); + state.imu.gyro_x = record.gyro_x(); + state.imu.gyro_y = record.gyro_y(); + state.imu.gyro_z = record.gyro_z(); + state.mag = new AltosMag(); + state.mag.x = record.mag_x(); + state.mag.y = record.mag_y(); + state.mag.z = record.mag_z(); + if (state.state < Altos.ao_flight_boost) { + eeprom.n_pad_samples++; + eeprom.ground_pres += state.pres; + state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); + state.flight_pres = state.ground_pres; + } else { + state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; + } + state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; + if ((eeprom.seen & seen_sensor) == 0) + eeprom.sensor_tick = record.tick - 1; + state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick); + eeprom.seen |= seen_sensor; + eeprom.sensor_tick = record.tick; + has_accel = true; + break; + case Altos.AO_LOG_PRESSURE: + state.pres = record.b; + state.flight_pres = state.pres; + if (eeprom.n_pad_samples == 0) { + eeprom.n_pad_samples++; + state.ground_pres = state.pres; + } + eeprom.seen |= seen_sensor; + break; + case Altos.AO_LOG_TEMP_VOLT: + state.batt = record.v_batt(); + eeprom.seen |= seen_temp_volt; + break; + case Altos.AO_LOG_DEPLOY: + state.drogue = record.a; + state.main = record.b; + eeprom.seen |= seen_deploy; + has_ignite = true; + break; + case Altos.AO_LOG_STATE: + state.state = record.state(); + break; + case Altos.AO_LOG_GPS_TIME: + eeprom.gps_tick = state.tick; + AltosGPS old = state.gps; + state.gps = new AltosGPS(); + + /* GPS date doesn't get repeated through the file */ + if (old != null) { + state.gps.year = old.year; + state.gps.month = old.month; + state.gps.day = old.day; + } + state.gps.hour = (record.a & 0xff); + state.gps.minute = (record.a >> 8); + state.gps.second = (record.b & 0xff); + + int flags = (record.b >> 8); + state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0; + state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0; + state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >> + Altos.AO_GPS_NUM_SAT_SHIFT; + state.new_gps = true; + has_gps = true; + break; + case Altos.AO_LOG_GPS_LAT: + int lat32 = record.a | (record.b << 16); + state.gps.lat = (double) lat32 / 1e7; + break; + case Altos.AO_LOG_GPS_LON: + int lon32 = record.a | (record.b << 16); + state.gps.lon = (double) lon32 / 1e7; + break; + case Altos.AO_LOG_GPS_ALT: + state.gps.alt = record.a; + break; + case Altos.AO_LOG_GPS_SAT: + if (state.tick == eeprom.gps_tick) { + int svid = record.a; + int c_n0 = record.b >> 8; + state.gps.add_sat(svid, c_n0); + } + break; + case Altos.AO_LOG_GPS_DATE: + state.gps.year = (record.a & 0xff) + 2000; + state.gps.month = record.a >> 8; + state.gps.day = record.b & 0xff; + break; + + case Altos.AO_LOG_CONFIG_VERSION: + break; + case Altos.AO_LOG_MAIN_DEPLOY: + break; + case Altos.AO_LOG_APOGEE_DELAY: + break; + case Altos.AO_LOG_RADIO_CHANNEL: + break; + case Altos.AO_LOG_CALLSIGN: + state.callsign = record.data; + break; + case Altos.AO_LOG_ACCEL_CAL: + state.accel_plus_g = record.a; + state.accel_minus_g = record.b; + break; + case Altos.AO_LOG_RADIO_CAL: + break; + case Altos.AO_LOG_MANUFACTURER: + break; + case Altos.AO_LOG_PRODUCT: + break; + case Altos.AO_LOG_SERIAL_NUMBER: + state.serial = record.a; + break; + case Altos.AO_LOG_SOFTWARE_VERSION: + break; + case Altos.AO_LOG_BARO_RESERVED: + baro.reserved = record.a; + break; + case Altos.AO_LOG_BARO_SENS: + baro.sens =record.a; + break; + case Altos.AO_LOG_BARO_OFF: + baro.off =record.a; + break; + case Altos.AO_LOG_BARO_TCS: + baro.tcs =record.a; + break; + case Altos.AO_LOG_BARO_TCO: + baro.tco =record.a; + break; + case Altos.AO_LOG_BARO_TREF: + baro.tref =record.a; + break; + case Altos.AO_LOG_BARO_TEMPSENS: + baro.tempsens =record.a; + break; + case Altos.AO_LOG_BARO_CRC: + baro.crc =record.a; + break; + } + state.seen |= eeprom.seen; + } + + LinkedList make_list() { + LinkedList list = new LinkedList(); + Iterator iterator = records.iterator(); + AltosOrderedMegaRecord record = null; + AltosRecord state = new AltosRecord(); + boolean last_reported = false; + EepromState eeprom = new EepromState(); + + state.state = Altos.ao_flight_pad; + state.accel_plus_g = 15758; + state.accel_minus_g = 16294; + + /* Pull in static data from the flight and gps_date records */ + if (flight_record != null) + update_state(state, flight_record, eeprom); + if (gps_date_record != null) + update_state(state, gps_date_record, eeprom); + + while (iterator.hasNext()) { + record = iterator.next(); + if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + } + update_state(state, record, eeprom); + } + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + return list; + } + + public Iterator iterator() { + if (list == null) + list = make_list(); + return list.iterator(); + } + + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; } + + public void write_comments(PrintStream out) { + Iterator iterator = records.iterator(); + out.printf("# Comments\n"); + while (iterator.hasNext()) { + AltosOrderedMegaRecord record = iterator.next(); + switch (record.cmd) { + case Altos.AO_LOG_CONFIG_VERSION: + out.printf("# Config version: %s\n", record.data); + break; + case Altos.AO_LOG_MAIN_DEPLOY: + out.printf("# Main deploy: %s\n", record.a); + break; + case Altos.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", record.a); + break; + case Altos.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", record.a); + break; + case Altos.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", record.data); + break; + case Altos.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", record.a, record.b); + break; + case Altos.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", record.a); + break; + case Altos.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", record.a); + break; + case Altos.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", record.data); + break; + case Altos.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", record.data); + break; + case Altos.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", record.a); + break; + case Altos.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", record.data); + break; + case Altos.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", record.a); + break; + } + } + } + + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedMegaRecord good, AltosOrderedMegaRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + /* Make sure this looks like a good GPS value */ + if ((flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT < 4) + flags = (flags & ~Altos.AO_GPS_NUM_SAT_MASK) | (4 << Altos.AO_GPS_NUM_SAT_SHIFT); + flags |= Altos.AO_GPS_RUNNING; + flags |= Altos.AO_GPS_VALID; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + + /* + * Read the whole file, dumping records into a RB tree so + * we can enumerate them in time order -- the eeprom data + * are sometimes out of order with GPS data getting timestamps + * matching the first packet out of the GPS unit but not + * written until the final GPS packet has been received. + */ + public AltosEepromMegaIterable (FileInputStream input) { + records = new TreeSet(); + + AltosOrderedMegaRecord last_gps_time = null; + + baro = new AltosMs5607(); + + int index = 0; + int prev_tick = 0; + boolean prev_tick_valid = false; + boolean missing_time = false; + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) + break; + AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid); + if (record == null) + break; + if (record.cmd == Altos.AO_LOG_INVALID) + continue; + prev_tick = record.tick; + if (record.cmd < Altos.AO_LOG_CONFIG_VERSION) + prev_tick_valid = true; + if (record.cmd == Altos.AO_LOG_FLIGHT) { + flight_record = record; + continue; + } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == Altos.AO_LOG_GPS_DATE) { + gps_date_record = record; + continue; + } + + /* go back and fix up any missing time values */ + if (record.cmd == Altos.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedMegaRecord old = iterator.next(); + if (old.cmd == Altos.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == Altos.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedMegaRecord add_gps_time = new AltosOrderedMegaRecord(Altos.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == Altos.AO_LOG_STATE && + record.a == Altos.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altosui/AltosIMU.java b/altosui/AltosIMU.java new file mode 100644 index 00000000..1f865a65 --- /dev/null +++ b/altosui/AltosIMU.java @@ -0,0 +1,29 @@ +/* + * 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 altosui; + +public class AltosIMU { + int accel_x; + int accel_y; + int accel_z; + + int gyro_x; + int gyro_y; + int gyro_z; +} + \ No newline at end of file diff --git a/altosui/AltosMag.java b/altosui/AltosMag.java new file mode 100644 index 00000000..b3fc542b --- /dev/null +++ b/altosui/AltosMag.java @@ -0,0 +1,25 @@ +/* + * 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 altosui; + +public class AltosMag { + int x; + int y; + int z; +} + \ No newline at end of file diff --git a/altosui/AltosMs5607.java b/altosui/AltosMs5607.java new file mode 100644 index 00000000..6f8bdbbe --- /dev/null +++ b/altosui/AltosMs5607.java @@ -0,0 +1,76 @@ +/* + * 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 altosui; + +public class AltosMs5607 { + int reserved; + int sens; + int off; + int tcs; + int tco; + int tref; + int tempsens; + int crc; + + int raw_pres; + int raw_temp; + public int pa; + public int cc; + + void convert() { + int dT; + int TEMP; + long OFF; + long SENS; + int P; + + dT = raw_temp - ((int) tref << 8); + + TEMP = (int) (2000 + (((long) dT * tempsens) >> 23)); + + OFF = ((long) off << 17) + (((long) tco * dT) >> 6); + + SENS = ((long) sens << 16) + (((long) tcs * dT) >> 7); + + if (TEMP < 2000) { + int T2 = (int) (((long) dT * (long) dT) >> 31); + int TEMPM = TEMP - 2000; + long OFF2 = (61 * (long) TEMPM * (long) TEMPM) >> 4; + long SENS2 = 2 * (long) TEMPM * (long) TEMPM; + if (TEMP < 1500) { + int TEMPP = TEMP + 1500; + long TEMPP2 = TEMPP * TEMPP; + OFF2 = OFF2 + 15 * TEMPP2; + SENS2 = SENS2 + 8 * TEMPP2; + } + TEMP -= T2; + OFF -= OFF2; + SENS -= SENS2; + } + + pa = (int) (((((long) raw_pres * SENS) >> 21) - OFF) >> 15); + cc = TEMP; + } + + public int set(int in_pres, int in_temp) { + raw_pres = in_pres; + raw_temp = in_temp; + convert(); + return pa; + } +} diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java index 4dfa98be..4643d69a 100644 --- a/altosui/AltosRecord.java +++ b/altosui/AltosRecord.java @@ -67,6 +67,9 @@ public class AltosRecord implements Comparable { AltosGPS gps; boolean new_gps; + AltosIMU imu; + AltosMag mag; + double time; /* seconds since boost */ int device_type; @@ -277,6 +280,8 @@ public class AltosRecord implements Comparable { gps = new AltosGPS(old.gps); new_gps = false; companion = old.companion; + imu = old.imu; + mag = old.mag; } public AltosRecord() { diff --git a/altosui/AltosState.java b/altosui/AltosState.java index da498bc1..9c6f85eb 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -54,6 +54,9 @@ public class AltosState { AltosGPS gps; + AltosIMU imu; + AltosMag mag; + double pad_lat; double pad_lon; double pad_alt; @@ -107,6 +110,8 @@ public class AltosState { max_acceleration = prev_state.max_acceleration; max_speed = prev_state.max_speed; max_baro_speed = prev_state.max_baro_speed; + imu = prev_state.imu; + mag = prev_state.mag; /* make sure the clock is monotonic */ while (tick < prev_state.tick) diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 6993abab..7d4b2edb 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -365,6 +365,8 @@ public class AltosUI extends AltosFrame { in = new FileInputStream(file); if (filename.endsWith("eeprom")) return new AltosEepromIterable(in); + else if (filename.endsWith("mega")) + return new AltosEepromMegaIterable(in); else return new AltosTelemetryIterable(in); } catch (FileNotFoundException fe) { diff --git a/altosui/Makefile.am b/altosui/Makefile.am index d436c6a0..16b57d40 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -48,6 +48,11 @@ altosui_JAVA = \ AltosEepromIterable.java \ AltosEepromRecord.java \ AltosEepromTeleScience.java \ + AltosEepromMega.java \ + AltosEepromMegaIterable.java \ + AltosMs5607.java \ + AltosIMU.java \ + AltosMag.java \ AltosEepromSelect.java \ AltosFile.java \ AltosFlash.java \ -- cgit v1.2.3 From c9e52287751867d9e451146ccde78109609d30d7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Jun 2012 19:06:08 -0700 Subject: altosui: Fixed width format for new IMU values. Signed-off-by: Keith Packard --- altosui/AltosCSV.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index b88bedba..db398a61 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -152,7 +152,7 @@ public class AltosCSV implements AltosWriter { imu = new AltosIMU(); if (mag == null) mag = new AltosMag(); - out.printf("%d,%d,%d,%d,%d,%d,%d,%d,%d", + out.printf("%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d", imu.accel_x, imu.accel_y, imu.accel_z, imu.gyro_x, imu.gyro_y, imu.gyro_z, mag.x, mag.y, mag.z); -- cgit v1.2.3 From 97663f922e236f4ee7bd08277ca80d419b5cd10f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 15:45:14 -0800 Subject: altosui: Split out UI-specific preferences Prepare to create library shared with android application. Signed-off-by: Keith Packard --- altosui/AltosBTKnown.java | 6 +- altosui/AltosConfig.java | 2 +- altosui/AltosConfigFreqUI.java | 4 +- altosui/AltosConfigUI.java | 4 +- altosui/AltosConfigureUI.java | 26 +++---- altosui/AltosDataChooser.java | 2 +- altosui/AltosDialog.java | 8 +- altosui/AltosFile.java | 2 +- altosui/AltosFlashUI.java | 4 +- altosui/AltosFlightUI.java | 8 +- altosui/AltosFrame.java | 6 +- altosui/AltosFreqList.java | 4 +- altosui/AltosIdleMonitorUI.java | 8 +- altosui/AltosLaunchUI.java | 8 +- altosui/AltosPreferences.java | 127 +----------------------------- altosui/AltosScanUI.java | 6 +- altosui/AltosSerial.java | 4 +- altosui/AltosSiteMap.java | 2 +- altosui/AltosTelemetryReader.java | 10 +-- altosui/AltosUI.java | 8 +- altosui/AltosUIPreferences.java | 159 ++++++++++++++++++++++++++++++++++++++ altosui/AltosVoice.java | 2 +- altosui/Makefile.am | 4 +- 23 files changed, 227 insertions(+), 187 deletions(-) create mode 100644 altosui/AltosUIPreferences.java (limited to 'altosui') diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java index 95830637..e30be057 100644 --- a/altosui/AltosBTKnown.java +++ b/altosui/AltosBTKnown.java @@ -23,7 +23,7 @@ import java.util.prefs.*; public class AltosBTKnown implements Iterable { LinkedList devices = new LinkedList(); - Preferences bt_pref = AltosPreferences.bt_devices(); + Preferences bt_pref = AltosUIPreferences.bt_devices(); private String get_address(String name) { return bt_pref.get(name, ""); @@ -57,7 +57,7 @@ public class AltosBTKnown implements Iterable { } private void flush() { - AltosPreferences.flush_preferences(); + AltosUIPreferences.flush_preferences(); } public void set(Iterable new_devices) { @@ -91,7 +91,7 @@ public class AltosBTKnown implements Iterable { public AltosBTKnown() { devices = new LinkedList(); - bt_pref = AltosPreferences.bt_devices(); + bt_pref = AltosUIPreferences.bt_devices(); load(); } } \ No newline at end of file diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 58da405f..bd930206 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -299,7 +299,7 @@ public class AltosConfig implements ActionListener { if (remote) { serial_line.stop_remote(); serial_line.set_radio_frequency(frequency); - AltosPreferences.set_frequency(device.getSerial(), frequency); + AltosUIPreferences.set_frequency(device.getSerial(), frequency); serial_line.start_remote(); } serial_line.printf("c c %s\n", callsign.get()); diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java index c6eabc53..ecb55449 100644 --- a/altosui/AltosConfigFreqUI.java +++ b/altosui/AltosConfigFreqUI.java @@ -246,7 +246,7 @@ public class AltosConfigFreqUI extends AltosDialog implements ActionListener { FrequencyList frequencies; void save_frequencies() { - AltosPreferences.set_common_frequencies(frequencies.frequencies()); + AltosUIPreferences.set_common_frequencies(frequencies.frequencies()); } JButton add, edit, remove; @@ -411,7 +411,7 @@ public class AltosConfigFreqUI extends AltosDialog implements ActionListener { Frame frame = JOptionPane.getFrameForComponent(frameComp); AltosConfigFreqUI dialog; - dialog = new AltosConfigFreqUI(frame, AltosPreferences.common_frequencies()); + dialog = new AltosConfigFreqUI(frame, AltosUIPreferences.common_frequencies()); dialog.setVisible(true); } diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index b0cd7f27..eddb223f 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -434,7 +434,7 @@ public class AltosConfigUI c.anchor = GridBagConstraints.LINE_START; c.insets = ir; c.ipady = 5; - callsign_value = new JTextField(AltosPreferences.callsign()); + callsign_value = new JTextField(AltosUIPreferences.callsign()); callsign_value.getDocument().addDocumentListener(this); pane.add(callsign_value, c); callsign_value.setToolTipText("Callsign reported in telemetry data"); @@ -689,7 +689,7 @@ public class AltosConfigUI product_value.getText(), serial_value.getText()); AltosFrequency new_frequency = new AltosFrequency(new_radio_frequency, description); - AltosPreferences.add_common_frequency(new_frequency); + AltosUIPreferences.add_common_frequency(new_frequency); radio_frequency_value.insertItemAt(new_frequency, i); radio_frequency_value.setSelectedIndex(i); } diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index 06b5745c..1789cd25 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -105,7 +105,7 @@ public class AltosConfigureUI /* DocumentListener interface methods */ public void changedUpdate(DocumentEvent e) { - AltosPreferences.set_callsign(callsign_value.getText()); + AltosUIPreferences.set_callsign(callsign_value.getText()); } public void insertUpdate(DocumentEvent e) { @@ -158,12 +158,12 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.WEST; pane.add(new JLabel("Voice"), c); - enable_voice = new JRadioButton("Enable", AltosPreferences.voice()); + enable_voice = new JRadioButton("Enable", AltosUIPreferences.voice()); enable_voice.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JRadioButton item = (JRadioButton) e.getSource(); boolean enabled = item.isSelected(); - AltosPreferences.set_voice(enabled); + AltosUIPreferences.set_voice(enabled); if (enabled) voice.speak_always("Enable voice."); else @@ -202,11 +202,11 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.WEST; pane.add(new JLabel("Log Directory"), c); - configure_log = new JButton(AltosPreferences.logdir().getPath()); + configure_log = new JButton(AltosUIPreferences.logdir().getPath()); configure_log.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - AltosPreferences.ConfigureLog(); - configure_log.setText(AltosPreferences.logdir().getPath()); + AltosUIPreferences.ConfigureLog(); + configure_log.setText(AltosUIPreferences.logdir().getPath()); } }); c.gridx = 1; @@ -225,7 +225,7 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.WEST; pane.add(new JLabel("Callsign"), c); - callsign_value = new JTextField(AltosPreferences.callsign()); + callsign_value = new JTextField(AltosUIPreferences.callsign()); callsign_value.getDocument().addDocumentListener(this); c.gridx = 1; c.gridy = row++; @@ -244,13 +244,13 @@ public class AltosConfigureUI pane.add(new JLabel("Font size"), c); font_size_value = new JComboBox(font_size_names); - int font_size = AltosPreferences.font_size(); + 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; - AltosPreferences.set_font_size(size); + AltosUIPreferences.set_font_size(size); } }); c.gridx = 1; @@ -295,7 +295,7 @@ public class AltosConfigureUI DelegatingRenderer.install(look_and_feel_value); - String look_and_feel = AltosPreferences.look_and_feel(); + 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); @@ -304,7 +304,7 @@ public class AltosConfigureUI public void actionPerformed(ActionEvent e) { int id = look_and_feel_value.getSelectedIndex(); - AltosPreferences.set_look_and_feel(look_and_feels[id].getClassName()); + AltosUIPreferences.set_look_and_feel(look_and_feels[id].getClassName()); } }); c.gridx = 1; @@ -323,12 +323,12 @@ public class AltosConfigureUI c.anchor = GridBagConstraints.WEST; pane.add(new JLabel("Serial Debug"), c); - serial_debug = new JRadioButton("Enable", AltosPreferences.serial_debug()); + 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(); - AltosPreferences.set_serial_debug(enabled); + AltosUIPreferences.set_serial_debug(enabled); } }); serial_debug.setToolTipText("Enable/Disable USB I/O getting sent to the console"); diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index 488e1068..c4a46d01 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -77,6 +77,6 @@ public class AltosDataChooser extends JFileChooser { setDialogTitle("Select Flight Record File"); setFileFilter(new FileNameExtensionFilter("Flight data file", "telem", "eeprom")); - setCurrentDirectory(AltosPreferences.logdir()); + setCurrentDirectory(AltosUIPreferences.logdir()); } } diff --git a/altosui/AltosDialog.java b/altosui/AltosDialog.java index c30b5757..1e8e538c 100644 --- a/altosui/AltosDialog.java +++ b/altosui/AltosDialog.java @@ -32,7 +32,7 @@ import libaltosJNI.*; class AltosDialogListener extends WindowAdapter { public void windowClosing (WindowEvent e) { - AltosPreferences.unregister_ui_listener((AltosDialog) e.getWindow()); + AltosUIPreferences.unregister_ui_listener((AltosDialog) e.getWindow()); } } @@ -44,19 +44,19 @@ public class AltosDialog extends JDialog implements AltosUIListener { } public AltosDialog() { - AltosPreferences.register_ui_listener(this); + AltosUIPreferences.register_ui_listener(this); addWindowListener(new AltosDialogListener()); } public AltosDialog(Frame frame, String label, boolean modal) { super(frame, label, modal); - AltosPreferences.register_ui_listener(this); + AltosUIPreferences.register_ui_listener(this); addWindowListener(new AltosDialogListener()); } public AltosDialog(Frame frame, boolean modal) { super(frame, modal); - AltosPreferences.register_ui_listener(this); + AltosUIPreferences.register_ui_listener(this); addWindowListener(new AltosDialogListener()); } } diff --git a/altosui/AltosFile.java b/altosui/AltosFile.java index 2e33b271..e2b6d5a6 100644 --- a/altosui/AltosFile.java +++ b/altosui/AltosFile.java @@ -24,7 +24,7 @@ import java.util.*; class AltosFile extends File { public AltosFile(int year, int month, int day, int serial, int flight, String extension) { - super (AltosPreferences.logdir(), + super (AltosUIPreferences.logdir(), String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", year, month, day, serial, flight, extension)); } diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 704ce35c..f91c542d 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -161,7 +161,7 @@ public class AltosFlashUI boolean select_source_file() { JFileChooser hexfile_chooser = new JFileChooser(); - File firmwaredir = AltosPreferences.firmwaredir(); + File firmwaredir = AltosUIPreferences.firmwaredir(); if (firmwaredir != null) hexfile_chooser.setCurrentDirectory(firmwaredir); @@ -174,7 +174,7 @@ public class AltosFlashUI file = hexfile_chooser.getSelectedFile(); if (file == null) return false; - AltosPreferences.set_firmwaredir(file.getParentFile()); + AltosUIPreferences.set_firmwaredir(file.getParentFile()); return true; } diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index b2ae4858..5c6e0629 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -159,7 +159,7 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt ActionListener show_timer; public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) { - AltosPreferences.set_component(this); + AltosUIPreferences.set_component(this); voice = in_voice; reader = in_reader; @@ -178,7 +178,7 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt /* Stick channel selector at top of table for telemetry monitoring */ if (serial >= 0) { // Channel menu - frequencies = new AltosFreqList(AltosPreferences.frequency(serial)); + frequencies = new AltosFreqList(AltosUIPreferences.frequency(serial)); frequencies.set_product("Monitor"); frequencies.set_serial(serial); frequencies.addActionListener(new ActionListener() { @@ -298,7 +298,7 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - AltosPreferences.register_font_listener(this); + AltosUIPreferences.register_font_listener(this); addWindowListener(new WindowAdapter() { @Override @@ -306,7 +306,7 @@ public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, Alt disconnect(); setVisible(false); dispose(); - AltosPreferences.unregister_font_listener(AltosFlightUI.this); + AltosUIPreferences.unregister_font_listener(AltosFlightUI.this); if (exit_on_close) System.exit(0); } diff --git a/altosui/AltosFrame.java b/altosui/AltosFrame.java index f8cc4f52..36ddcae9 100644 --- a/altosui/AltosFrame.java +++ b/altosui/AltosFrame.java @@ -32,7 +32,7 @@ import libaltosJNI.*; class AltosFrameListener extends WindowAdapter { public void windowClosing (WindowEvent e) { - AltosPreferences.unregister_ui_listener((AltosFrame) e.getWindow()); + AltosUIPreferences.unregister_ui_listener((AltosFrame) e.getWindow()); } } @@ -44,13 +44,13 @@ public class AltosFrame extends JFrame implements AltosUIListener { } public AltosFrame() { - AltosPreferences.register_ui_listener(this); + AltosUIPreferences.register_ui_listener(this); addWindowListener(new AltosFrameListener()); } public AltosFrame(String name) { super(name); - AltosPreferences.register_ui_listener(this); + AltosUIPreferences.register_ui_listener(this); addWindowListener(new AltosFrameListener()); } } diff --git a/altosui/AltosFreqList.java b/altosui/AltosFreqList.java index 59b0e127..e4135df7 100644 --- a/altosui/AltosFreqList.java +++ b/altosui/AltosFreqList.java @@ -52,7 +52,7 @@ public class AltosFreqList extends JComboBox { } String description = String.format("%s serial %d", product, serial); AltosFrequency frequency = new AltosFrequency(new_frequency, description); - AltosPreferences.add_common_frequency(frequency); + AltosUIPreferences.add_common_frequency(frequency); insertItemAt(frequency, i); setMaximumRowCount(getItemCount()); } @@ -73,7 +73,7 @@ public class AltosFreqList extends JComboBox { } public AltosFreqList () { - super(AltosPreferences.common_frequencies()); + super(AltosUIPreferences.common_frequencies()); setMaximumRowCount(getItemCount()); setEditable(false); product = "Unknown"; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index d877be4d..8eb0d520 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -342,12 +342,12 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay /* Stick frequency selector at top of table for telemetry monitoring */ if (remote && serial >= 0) { // Frequency menu - frequencies = new AltosFreqList(AltosPreferences.frequency(serial)); + frequencies = new AltosFreqList(AltosUIPreferences.frequency(serial)); frequencies.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { double frequency = frequencies.frequency(); thread.set_frequency(frequency); - AltosPreferences.set_frequency(device.getSerial(), + AltosUIPreferences.set_frequency(device.getSerial(), frequency); } }); @@ -391,7 +391,7 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - AltosPreferences.register_font_listener(this); + AltosUIPreferences.register_font_listener(this); addWindowListener(new WindowAdapter() { @Override @@ -399,7 +399,7 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay disconnect(); setVisible(false); dispose(); - AltosPreferences.unregister_font_listener(AltosIdleMonitorUI.this); + AltosUIPreferences.unregister_font_listener(AltosIdleMonitorUI.this); } }); diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index 73fae16b..a6c36604 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -316,7 +316,7 @@ public class AltosLaunchUI void set_serial() { try { launcher_serial = Integer.parseInt(launcher_serial_text.getText()); - AltosPreferences.set_launcher_serial(launcher_serial); + AltosUIPreferences.set_launcher_serial(launcher_serial); send_command("set_remote"); } catch (NumberFormatException ne) { launcher_serial_text.setText(String.format("%d", launcher_serial)); @@ -326,7 +326,7 @@ public class AltosLaunchUI void set_channel() { try { launcher_channel = Integer.parseInt(launcher_channel_text.getText()); - AltosPreferences.set_launcher_serial(launcher_channel); + AltosUIPreferences.set_launcher_serial(launcher_channel); send_command("set_remote"); } catch (NumberFormatException ne) { launcher_channel_text.setText(String.format("%d", launcher_channel)); @@ -388,8 +388,8 @@ public class AltosLaunchUI public AltosLaunchUI(JFrame in_owner) { - launcher_channel = AltosPreferences.launcher_channel(); - launcher_serial = AltosPreferences.launcher_serial(); + launcher_channel = AltosUIPreferences.launcher_channel(); + launcher_serial = AltosUIPreferences.launcher_serial(); owner = in_owner; armed_status = AltosLaunch.Unknown; igniter_status = AltosLaunch.Unknown; diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java index cc2b1a95..7510c7c2 100644 --- a/altosui/AltosPreferences.java +++ b/altosui/AltosPreferences.java @@ -26,7 +26,7 @@ import javax.swing.*; import javax.swing.filechooser.FileSystemView; class AltosPreferences { - static Preferences preferences; + public static Preferences preferences; /* logdir preference name */ final static String logdirPreference = "LOGDIR"; @@ -55,24 +55,15 @@ class AltosPreferences { /* scanning telemetry preferences name */ final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; - /* font size preferences name */ - final static String fontSizePreference = "FONT-SIZE"; - /* Launcher serial preference name */ final static String launcherSerialPreference = "LAUNCHER-SERIAL"; /* Launcher channel preference name */ final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; - /* Look&Feel preference name */ - final static String lookAndFeelPreference = "LOOK-AND-FEEL"; - /* Default logdir is ~/TeleMetrum */ final static String logdirName = "TeleMetrum"; - /* UI Component to pop dialogs up */ - static Component component; - /* Log directory */ static File logdir; @@ -100,14 +91,6 @@ class AltosPreferences { /* Scanning telemetry */ static int scanning_telemetry; - static LinkedList font_listeners; - - static int font_size = Altos.font_size_medium; - - static LinkedList ui_listeners; - - static String look_and_feel = null; - /* List of frequencies */ final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; static AltosFrequency[] common_frequencies; @@ -187,11 +170,6 @@ class AltosPreferences { scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << Altos.ao_telemetry_standard)); - font_listeners = new LinkedList(); - - font_size = preferences.getInt(fontSizePreference, Altos.font_size_medium); - Altos.set_fonts(font_size); - launcher_serial = preferences.getInt(launcherSerialPreference, 0); launcher_channel = preferences.getInt(launcherChannelPreference, 0); @@ -207,27 +185,22 @@ class AltosPreferences { common_frequencies = load_common_frequencies(); - look_and_feel = preferences.get(lookAndFeelPreference, UIManager.getSystemLookAndFeelClassName()); - - ui_listeners = new LinkedList(); } static { init(); } - static void set_component(Component in_component) { - component = in_component; - } - static void flush_preferences() { try { preferences.flush(); } catch (BackingStoreException ee) { +/* if (component != null) JOptionPane.showMessageDialog(component, preferences.absolutePath(), "Cannot save prefernces", JOptionPane.ERROR_MESSAGE); else +*/ System.err.printf("Cannot save preferences\n"); } } @@ -243,41 +216,6 @@ class AltosPreferences { } } - 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 File logdir() { return logdir; } @@ -371,65 +309,6 @@ class AltosPreferences { return firmwaredir; } - public static int font_size() { - return font_size; - } - - static void set_fonts() { - } - - public static void set_font_size(int new_font_size) { - font_size = new_font_size; - synchronized (preferences) { - preferences.putInt(fontSizePreference, font_size); - flush_preferences(); - Altos.set_fonts(font_size); - for (AltosFontListener l : font_listeners) - l.font_size_changed(font_size); - } - } - - public static void register_font_listener(AltosFontListener l) { - synchronized (preferences) { - font_listeners.add(l); - } - } - - public static void unregister_font_listener(AltosFontListener l) { - synchronized (preferences) { - font_listeners.remove(l); - } - } - - public static void set_look_and_feel(String new_look_and_feel) { - look_and_feel = new_look_and_feel; - try { - UIManager.setLookAndFeel(look_and_feel); - } catch (Exception e) { - } - synchronized(preferences) { - preferences.put(lookAndFeelPreference, look_and_feel); - flush_preferences(); - for (AltosUIListener l : ui_listeners) - l.ui_changed(look_and_feel); - } - } - - public static String look_and_feel() { - return look_and_feel; - } - - public static void register_ui_listener(AltosUIListener l) { - synchronized(preferences) { - ui_listeners.add(l); - } - } - - public static void unregister_ui_listener(AltosUIListener l) { - synchronized (preferences) { - ui_listeners.remove(l); - } - } public static void set_serial_debug(boolean new_serial_debug) { serial_debug = new_serial_debug; AltosSerial.set_debug(serial_debug); diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index e188834e..2b9137d8 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -267,7 +267,7 @@ public class AltosScanUI scanning_telemetry |= (1 << Altos.ao_telemetry_standard); telemetry_boxes[Altos.ao_telemetry_standard - Altos.ao_telemetry_min].setSelected(true); } - AltosPreferences.set_scanning_telemetry(scanning_telemetry); + AltosUIPreferences.set_scanning_telemetry(scanning_telemetry); } if (cmd.equals("monitor")) { @@ -359,7 +359,7 @@ public class AltosScanUI owner = in_owner; - frequencies = AltosPreferences.common_frequencies(); + frequencies = AltosUIPreferences.common_frequencies(); frequency_index = 0; telemetry = Altos.ao_telemetry_min; @@ -400,7 +400,7 @@ public class AltosScanUI c.gridy = 2; pane.add(telemetry_label, c); - int scanning_telemetry = AltosPreferences.scanning_telemetry(); + int scanning_telemetry = AltosUIPreferences.scanning_telemetry(); telemetry_boxes = new JCheckBox[Altos.ao_telemetry_max - Altos.ao_telemetry_min + 1]; for (int k = Altos.ao_telemetry_min; k <= Altos.ao_telemetry_max; k++) { int j = k - Altos.ao_telemetry_min; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 77c926b1..afb9f21a 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -438,9 +438,9 @@ public class AltosSerial implements Runnable { if (debug) System.out.printf("start remote %7.3f\n", frequency); if (frequency == 0.0) - frequency = AltosPreferences.frequency(device.getSerial()); + frequency = AltosUIPreferences.frequency(device.getSerial()); set_radio_frequency(frequency); - set_callsign(AltosPreferences.callsign()); + set_callsign(AltosUIPreferences.callsign()); printf("p\nE 0\n"); flush_input(); remote = true; diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index 63995c40..93c54d02 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -250,7 +250,7 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { char chlng = lng < 0 ? 'W' : 'E'; if (lat < 0) lat = -lat; if (lng < 0) lng = -lng; - return new File(AltosPreferences.mapdir(), + return new File(AltosUIPreferences.mapdir(), String.format("map-%c%.6f,%c%.6f-%d.png", chlat, lat, chlng, lng, zoom)); } diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java index 85dc9cbc..dde60dc9 100644 --- a/altosui/AltosTelemetryReader.java +++ b/altosui/AltosTelemetryReader.java @@ -84,7 +84,7 @@ class AltosTelemetryReader extends AltosFlightReader { } void save_frequency() { - AltosPreferences.set_frequency(device.getSerial(), frequency); + AltosUIPreferences.set_frequency(device.getSerial(), frequency); } void set_telemetry(int in_telemetry) { @@ -93,7 +93,7 @@ class AltosTelemetryReader extends AltosFlightReader { } void save_telemetry() { - AltosPreferences.set_telemetry(device.getSerial(), telemetry); + AltosUIPreferences.set_telemetry(device.getSerial(), telemetry); } File backing_file() { @@ -109,11 +109,11 @@ class AltosTelemetryReader extends AltosFlightReader { previous = null; telem = new LinkedBlockingQueue(); - frequency = AltosPreferences.frequency(device.getSerial()); + frequency = AltosUIPreferences.frequency(device.getSerial()); set_frequency(frequency); - telemetry = AltosPreferences.telemetry(device.getSerial()); + telemetry = AltosUIPreferences.telemetry(device.getSerial()); set_telemetry(telemetry); - serial.set_callsign(AltosPreferences.callsign()); + serial.set_callsign(AltosUIPreferences.callsign()); serial.add_monitor(telem); } } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 7d4b2edb..a2816a3a 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -108,7 +108,7 @@ public class AltosUI extends AltosFrame { if (imgURL != null) setIconImage(new ImageIcon(imgURL).getImage()); - AltosPreferences.set_component(this); + AltosUIPreferences.set_component(this); pane = getContentPane(); gridbag = new GridBagLayout(); @@ -262,9 +262,9 @@ public class AltosUI extends AltosFrame { String result; result = JOptionPane.showInputDialog(AltosUI.this, "Configure Callsign", - AltosPreferences.callsign()); + AltosUIPreferences.callsign()); if (result != null) - AltosPreferences.set_callsign(result); + AltosUIPreferences.set_callsign(result); } void ConfigureTeleMetrum() { @@ -538,7 +538,7 @@ public class AltosUI extends AltosFrame { public static void main(final String[] args) { try { - UIManager.setLookAndFeel(AltosPreferences.look_and_feel()); + UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel()); } catch (Exception e) { } /* Handle batch-mode */ diff --git a/altosui/AltosUIPreferences.java b/altosui/AltosUIPreferences.java new file mode 100644 index 00000000..da6c3968 --- /dev/null +++ b/altosui/AltosUIPreferences.java @@ -0,0 +1,159 @@ +/* + * 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 altosui; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.awt.Component; +import javax.swing.*; +import javax.swing.filechooser.FileSystemView; + +/* import org.altusmetrum.AltosLib.*; */ + +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 font_listeners; + + static int font_size = Altos.font_size_medium; + + static LinkedList ui_listeners; + + static String look_and_feel = null; + + public static void init() { + font_listeners = new LinkedList(); + + font_size = preferences.getInt(fontSizePreference, Altos.font_size_medium); + Altos.set_fonts(font_size); + look_and_feel = preferences.get(lookAndFeelPreference, UIManager.getSystemLookAndFeelClassName()); + + ui_listeners = new LinkedList(); + } + + static { init(); } + + 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() { + return font_size; + } + + static void set_fonts() { + } + + public static void set_font_size(int new_font_size) { + font_size = new_font_size; + synchronized (preferences) { + preferences.putInt(fontSizePreference, font_size); + flush_preferences(); + Altos.set_fonts(font_size); + for (AltosFontListener l : font_listeners) + l.font_size_changed(font_size); + } + } + + public static void register_font_listener(AltosFontListener l) { + synchronized (preferences) { + font_listeners.add(l); + } + } + + public static void unregister_font_listener(AltosFontListener l) { + synchronized (preferences) { + font_listeners.remove(l); + } + } + + public static void set_look_and_feel(String new_look_and_feel) { + look_and_feel = new_look_and_feel; + try { + UIManager.setLookAndFeel(look_and_feel); + } catch (Exception e) { + } + synchronized(preferences) { + preferences.put(lookAndFeelPreference, look_and_feel); + flush_preferences(); + for (AltosUIListener l : ui_listeners) + l.ui_changed(look_and_feel); + } + } + + public static String look_and_feel() { + return look_and_feel; + } + + public static void register_ui_listener(AltosUIListener l) { + synchronized(preferences) { + ui_listeners.add(l); + } + } + + public static void unregister_ui_listener(AltosUIListener l) { + synchronized (preferences) { + ui_listeners.remove(l); + } + } +} \ No newline at end of file diff --git a/altosui/AltosVoice.java b/altosui/AltosVoice.java index ac13ee14..ab74e0b3 100644 --- a/altosui/AltosVoice.java +++ b/altosui/AltosVoice.java @@ -65,7 +65,7 @@ public class AltosVoice implements Runnable { } public void speak(String s) { - if (AltosPreferences.voice()) + if (AltosUIPreferences.voice()) speak_always(s); } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 16b57d40..c3fd6bb6 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=libaltos +SUBDIRS=libaltos altoslib JAVAROOT=classes AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation @@ -87,7 +87,9 @@ altosui_JAVA = \ AltosLog.java \ AltosPad.java \ AltosParse.java \ + AltosUIPreferences.java \ AltosPreferences.java \ + AltosUIPreferences.java \ AltosReader.java \ AltosRecord.java \ AltosRecordCompanion.java \ -- cgit v1.2.3 From 6510e8495fc5e8057b6092963def4d78978625a0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 16:09:29 -0800 Subject: altosui: Split out lots of the altosui code to a shared library To be shared with the Android application eventually Signed-off-by: Keith Packard --- altosui/Altos.java | 18 +- altosui/AltosCRCException.java | 26 - altosui/AltosConvert.java | 259 ---------- altosui/AltosFontListener.java | 22 - altosui/AltosFrequency.java | 57 --- altosui/AltosGPS.java | 248 ---------- altosui/AltosGPSSat.java | 32 -- altosui/AltosLine.java | 30 -- altosui/AltosParse.java | 79 ---- altosui/AltosRecord.java | 317 ------------- altosui/AltosRecordCompanion.java | 38 -- altosui/AltosRecordIterable.java | 37 -- altosui/AltosTelemetry.java | 241 ---------- altosui/AltosTelemetryIterable.java | 109 ----- altosui/AltosTelemetryMap.java | 63 --- altosui/AltosTelemetryReader.java | 119 ----- altosui/AltosTelemetryRecord.java | 128 ----- altosui/AltosTelemetryRecordCompanion.java | 52 -- altosui/AltosTelemetryRecordConfiguration.java | 64 --- altosui/AltosTelemetryRecordLegacy.java | 521 --------------------- altosui/AltosTelemetryRecordLocation.java | 93 ---- altosui/AltosTelemetryRecordRaw.java | 77 --- altosui/AltosTelemetryRecordSatellite.java | 52 -- altosui/AltosTelemetryRecordSensor.java | 104 ---- altosui/altoslib/Makefile.am | 56 +++ .../altusmetrum/AltosLib/AltosCRCException.java | 26 + .../src/org/altusmetrum/AltosLib/AltosConvert.java | 259 ++++++++++ .../altusmetrum/AltosLib/AltosFontListener.java | 22 + .../org/altusmetrum/AltosLib/AltosFrequency.java | 57 +++ .../src/org/altusmetrum/AltosLib/AltosGPS.java | 248 ++++++++++ .../src/org/altusmetrum/AltosLib/AltosGPSSat.java | 32 ++ .../src/org/altusmetrum/AltosLib/AltosLine.java | 30 ++ .../src/org/altusmetrum/AltosLib/AltosParse.java | 79 ++++ .../src/org/altusmetrum/AltosLib/AltosRecord.java | 317 +++++++++++++ .../altusmetrum/AltosLib/AltosRecordCompanion.java | 38 ++ .../altusmetrum/AltosLib/AltosRecordIterable.java | 37 ++ .../org/altusmetrum/AltosLib/AltosTelemetry.java | 241 ++++++++++ .../AltosLib/AltosTelemetryIterable.java | 109 +++++ .../altusmetrum/AltosLib/AltosTelemetryMap.java | 63 +++ .../altusmetrum/AltosLib/AltosTelemetryReader.java | 119 +++++ .../altusmetrum/AltosLib/AltosTelemetryRecord.java | 128 +++++ .../AltosLib/AltosTelemetryRecordCompanion.java | 52 ++ .../AltosTelemetryRecordConfiguration.java | 64 +++ .../AltosLib/AltosTelemetryRecordGeneral.java | 43 ++ .../AltosLib/AltosTelemetryRecordLegacy.java | 521 +++++++++++++++++++++ .../AltosLib/AltosTelemetryRecordLocation.java | 93 ++++ .../AltosLib/AltosTelemetryRecordRaw.java | 77 +++ .../AltosLib/AltosTelemetryRecordSatellite.java | 52 ++ .../AltosLib/AltosTelemetryRecordSensor.java | 104 ++++ configure.ac | 1 + 50 files changed, 2871 insertions(+), 2783 deletions(-) delete mode 100644 altosui/AltosCRCException.java delete mode 100644 altosui/AltosConvert.java delete mode 100644 altosui/AltosFontListener.java delete mode 100644 altosui/AltosFrequency.java delete mode 100644 altosui/AltosGPS.java delete mode 100644 altosui/AltosGPSSat.java delete mode 100644 altosui/AltosLine.java delete mode 100644 altosui/AltosParse.java delete mode 100644 altosui/AltosRecord.java delete mode 100644 altosui/AltosRecordCompanion.java delete mode 100644 altosui/AltosRecordIterable.java delete mode 100644 altosui/AltosTelemetry.java delete mode 100644 altosui/AltosTelemetryIterable.java delete mode 100644 altosui/AltosTelemetryMap.java delete mode 100644 altosui/AltosTelemetryReader.java delete mode 100644 altosui/AltosTelemetryRecord.java delete mode 100644 altosui/AltosTelemetryRecordCompanion.java delete mode 100644 altosui/AltosTelemetryRecordConfiguration.java delete mode 100644 altosui/AltosTelemetryRecordLegacy.java delete mode 100644 altosui/AltosTelemetryRecordLocation.java delete mode 100644 altosui/AltosTelemetryRecordRaw.java delete mode 100644 altosui/AltosTelemetryRecordSatellite.java delete mode 100644 altosui/AltosTelemetryRecordSensor.java create mode 100644 altosui/altoslib/Makefile.am create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFontListener.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 1d393dbe..3e2a7a40 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -24,20 +24,9 @@ import java.nio.charset.Charset; import libaltosJNI.*; -public class Altos { - /* EEProm command letters */ - static final int AO_LOG_FLIGHT = 'F'; - static final int AO_LOG_SENSOR = 'A'; - static final int AO_LOG_TEMP_VOLT = 'T'; - static final int AO_LOG_DEPLOY = 'D'; - static final int AO_LOG_STATE = 'S'; - static final int AO_LOG_GPS_TIME = 'G'; - static final int AO_LOG_GPS_LAT = 'N'; - static final int AO_LOG_GPS_LON = 'W'; - static final int AO_LOG_GPS_ALT = 'H'; - static final int AO_LOG_GPS_SAT = 'V'; - static final int AO_LOG_GPS_DATE = 'Y'; - static final int AO_LOG_PRESSURE = 'P'; +import org.altusmetrum.AltosLib.*; + +public class Altos extends AltosLib { /* Added for header fields in eeprom files */ static final int AO_LOG_CONFIG_VERSION = 1000; @@ -107,7 +96,6 @@ public class Altos { static boolean map_initialized = false; static final int tab_elt_pad = 5; - static Font label_font; static Font value_font; static Font status_font; diff --git a/altosui/AltosCRCException.java b/altosui/AltosCRCException.java deleted file mode 100644 index 4a529bcf..00000000 --- a/altosui/AltosCRCException.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 altosui; - -public class AltosCRCException extends Exception { - public int rssi; - - public AltosCRCException (int in_rssi) { - rssi = in_rssi; - } -} diff --git a/altosui/AltosConvert.java b/altosui/AltosConvert.java deleted file mode 100644 index df41a522..00000000 --- a/altosui/AltosConvert.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * 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. - */ - -/* - * Sensor data conversion functions - */ -package altosui; - -public class AltosConvert { - /* - * Pressure Sensor Model, version 1.1 - * - * written by Holly Grimes - * - * Uses the International Standard Atmosphere as described in - * "A Quick Derivation relating altitude to air pressure" (version 1.03) - * from the Portland State Aerospace Society, except that the atmosphere - * is divided into layers with each layer having a different lapse rate. - * - * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 - * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ - return 0; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted altitude */ - for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - base_pressure *= Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - base_pressure *= Math.pow(base, exponent); - } - base_temperature += delta_z * lapse_rate[layer_number]; - } - - /* calculate the pressure at the inputted altitude */ - delta_z = altitude - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - pressure = base_pressure * Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - pressure = base_pressure * Math.pow(base, exponent); - } - - return pressure; - } - - -/* outputs the altitude associated with the given pressure. the altitude - returned is measured with respect to the mean sea level */ - static double - pressure_to_altitude(double pressure) - { - - double next_base_temperature = LAYER0_BASE_TEMPERATURE; - double next_base_pressure = LAYER0_BASE_PRESSURE; - - double altitude; - double base_pressure; - double base_temperature; - double base; /* base for function to determine base pressure of next layer */ - double exponent; /* exponent for function to determine base pressure - of next layer */ - double coefficient; - int layer_number; /* identifies layer in the atmosphere */ - int delta_z; /* difference between two altitudes */ - - if (pressure < 0) /* illegal pressure */ - return -1; - if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ - return MAXIMUM_ALTITUDE; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted pressure. */ - layer_number = -1; - do { - layer_number++; - base_pressure = next_base_pressure; - base_temperature = next_base_temperature; - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - next_base_pressure *= Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - next_base_pressure *= Math.pow(base, exponent); - } - next_base_temperature += delta_z * lapse_rate[layer_number]; - } - while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); - - /* calculate the altitude associated with the inputted pressure */ - if (lapse_rate[layer_number] == 0.0) { - coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) - * base_temperature; - altitude = base_altitude[layer_number] - + coefficient * Math.log(pressure / base_pressure); - } - else { - base = pressure / base_pressure; - exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] - / GRAVITATIONAL_ACCELERATION; - coefficient = base_temperature / lapse_rate[layer_number]; - altitude = base_altitude[layer_number] - + coefficient * (Math.pow(base, exponent) - 1); - } - - return altitude; - } - - static double - cc_battery_to_voltage(double battery) - { - return battery / 32767.0 * 5.0; - } - - static double - cc_ignitor_to_voltage(double ignite) - { - return ignite / 32767 * 15.0; - } - - static double radio_to_frequency(int freq, int setting, int cal, int channel) { - double f; - - if (freq > 0) - f = freq / 1000.0; - else { - if (setting <= 0) - setting = cal; - f = 434.550 * setting / cal; - /* Round to nearest 50KHz */ - f = Math.floor (20.0 * f + 0.5) / 20.0; - } - return f + channel * 0.100; - } - - static int radio_frequency_to_setting(double frequency, int cal) { - double set = frequency / 434.550 * cal; - - return (int) Math.floor (set + 0.5); - } - - static int radio_frequency_to_channel(double frequency) { - int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); - - if (channel < 0) - channel = 0; - if (channel > 9) - channel = 9; - return channel; - } - - static double radio_channel_to_frequency(int channel) { - return 434.550 + channel * 0.100; - } - - static int[] ParseHex(String line) { - String[] tokens = line.split("\\s+"); - int[] array = new int[tokens.length]; - - for (int i = 0; i < tokens.length; i++) - try { - array[i] = Integer.parseInt(tokens[i], 16); - } catch (NumberFormatException ne) { - return null; - } - return array; - } - - static double meters_to_feet(double meters) { - return meters * (100 / (2.54 * 12)); - } - - static double meters_to_mach(double meters) { - return meters / 343; /* something close to mach at usual rocket sites */ - } - - static double meters_to_g(double meters) { - return meters / 9.80665; - } - - static int checksum(int[] data, int start, int length) { - int csum = 0x5a; - for (int i = 0; i < length; i++) - csum += data[i + start]; - return csum & 0xff; - } -} diff --git a/altosui/AltosFontListener.java b/altosui/AltosFontListener.java deleted file mode 100644 index 0dda0f29..00000000 --- a/altosui/AltosFontListener.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 altosui; - -public interface AltosFontListener { - void font_size_changed(int font_size); -} diff --git a/altosui/AltosFrequency.java b/altosui/AltosFrequency.java deleted file mode 100644 index b748e460..00000000 --- a/altosui/AltosFrequency.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import javax.swing.event.*; -import javax.swing.plaf.basic.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -public class AltosFrequency { - double frequency; - String description; - - public String toString() { - return String.format("%7.3f MHz %-20s", - frequency, description); - } - - public String toShortString() { - return String.format("%7.3f MHz %s", - frequency, description); - } - - public boolean close(double f) { - double diff = Math.abs(frequency - f); - - return diff < 0.010; - } - - public AltosFrequency(double f, String d) { - frequency = f; - description = d; - } -} \ No newline at end of file diff --git a/altosui/AltosGPS.java b/altosui/AltosGPS.java deleted file mode 100644 index b5df7c9a..00000000 --- a/altosui/AltosGPS.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; - -public class AltosGPS { - - final static int MISSING = AltosRecord.MISSING; - - int nsat; - boolean locked; - boolean connected; - double lat; /* degrees (+N -S) */ - double lon; /* degrees (+E -W) */ - int alt; /* m */ - int year; - int month; - int day; - int hour; - int minute; - int second; - - double ground_speed; /* m/s */ - int course; /* degrees */ - double climb_rate; /* m/s */ - double hdop; /* unitless */ - double vdop; /* unitless */ - int h_error; /* m */ - int v_error; /* m */ - - AltosGPSSat[] cc_gps_sat; /* tracking data */ - - void ParseGPSDate(String date) throws ParseException { - String[] ymd = date.split("-"); - if (ymd.length != 3) - throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); - year = AltosParse.parse_int(ymd[0]); - month = AltosParse.parse_int(ymd[1]); - day = AltosParse.parse_int(ymd[2]); - } - - void ParseGPSTime(String time) throws ParseException { - String[] hms = time.split(":"); - if (hms.length != 3) - throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); - hour = AltosParse.parse_int(hms[0]); - minute = AltosParse.parse_int(hms[1]); - second = AltosParse.parse_int(hms[2]); - } - - void ClearGPSTime() { - year = month = day = 0; - hour = minute = second = 0; - } - - public AltosGPS(AltosTelemetryMap map) throws ParseException { - String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, - AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); - - nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0); - if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) { - connected = true; - locked = true; - lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); - lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); - alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING); - year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING); - if (year != MISSING) - year += 2000; - month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING); - day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING); - - hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0); - minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0); - second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0); - - ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, - AltosRecord.MISSING, 1/100.0); - course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, - AltosRecord.MISSING); - hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0); - vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0); - h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING); - v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING); - } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) { - connected = true; - locked = false; - } else { - connected = false; - locked = false; - } - } - - public AltosGPS(String[] words, int i, int version) throws ParseException { - AltosParse.word(words[i++], "GPS"); - nsat = AltosParse.parse_int(words[i++]); - AltosParse.word(words[i++], "sat"); - - connected = false; - locked = false; - lat = lon = 0; - alt = 0; - ClearGPSTime(); - if ((words[i]).equals("unlocked")) { - connected = true; - i++; - } else if ((words[i]).equals("not-connected")) { - i++; - } else if (words.length >= 40) { - locked = true; - connected = true; - - if (version > 1) - ParseGPSDate(words[i++]); - else - year = month = day = 0; - ParseGPSTime(words[i++]); - lat = AltosParse.parse_coord(words[i++]); - lon = AltosParse.parse_coord(words[i++]); - alt = AltosParse.parse_int(words[i++]); - if (version > 1 || (i < words.length && !words[i].equals("SAT"))) { - ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)")); - course = AltosParse.parse_int(words[i++]); - climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)")); - hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)")); - h_error = AltosParse.parse_int(words[i++]); - v_error = AltosParse.parse_int(words[i++]); - } - } else { - i++; - } - if (i < words.length) { - AltosParse.word(words[i++], "SAT"); - int tracking_channels = 0; - if (words[i].equals("not-connected")) - tracking_channels = 0; - else - tracking_channels = AltosParse.parse_int(words[i]); - i++; - cc_gps_sat = new AltosGPSSat[tracking_channels]; - for (int chan = 0; chan < tracking_channels; chan++) { - cc_gps_sat[chan] = new AltosGPSSat(); - cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); - /* Older versions included SiRF status bits */ - if (version < 2) - i++; - cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); - } - } else - cc_gps_sat = new AltosGPSSat[0]; - } - - public void set_latitude(int in_lat) { - lat = in_lat / 10.0e7; - } - - public void set_longitude(int in_lon) { - lon = in_lon / 10.0e7; - } - - public void set_time(int hour, int minute, int second) { - hour = hour; - minute = minute; - second = second; - } - - public void set_date(int year, int month, int day) { - year = year; - month = month; - day = day; - } - - public void set_flags(int flags) { - flags = flags; - } - - public void set_altitude(int altitude) { - altitude = altitude; - } - - public void add_sat(int svid, int c_n0) { - if (cc_gps_sat == null) { - cc_gps_sat = new AltosGPSSat[1]; - } else { - AltosGPSSat[] new_gps_sat = new AltosGPSSat[cc_gps_sat.length + 1]; - for (int i = 0; i < cc_gps_sat.length; i++) - new_gps_sat[i] = cc_gps_sat[i]; - cc_gps_sat = new_gps_sat; - } - AltosGPSSat sat = new AltosGPSSat(); - sat.svid = svid; - sat.c_n0 = c_n0; - cc_gps_sat[cc_gps_sat.length - 1] = sat; - } - - public AltosGPS() { - ClearGPSTime(); - cc_gps_sat = null; - } - - public AltosGPS(AltosGPS old) { - nsat = old.nsat; - locked = old.locked; - connected = old.connected; - lat = old.lat; /* degrees (+N -S) */ - lon = old.lon; /* degrees (+E -W) */ - alt = old.alt; /* m */ - year = old.year; - month = old.month; - day = old.day; - hour = old.hour; - minute = old.minute; - second = old.second; - - ground_speed = old.ground_speed; /* m/s */ - course = old.course; /* degrees */ - climb_rate = old.climb_rate; /* m/s */ - hdop = old.hdop; /* unitless? */ - h_error = old.h_error; /* m */ - v_error = old.v_error; /* m */ - - if (old.cc_gps_sat != null) { - cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; - for (int i = 0; i < old.cc_gps_sat.length; i++) { - cc_gps_sat[i] = new AltosGPSSat(); - cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; - cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; - } - } - } -} diff --git a/altosui/AltosGPSSat.java b/altosui/AltosGPSSat.java deleted file mode 100644 index fb125651..00000000 --- a/altosui/AltosGPSSat.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 altosui; - -public class AltosGPSSat { - int svid; - int c_n0; - - public AltosGPSSat(int s, int c) { - svid = s; - c_n0= c; - } - - public AltosGPSSat() { - } -} - diff --git a/altosui/AltosLine.java b/altosui/AltosLine.java deleted file mode 100644 index 86e9d4c6..00000000 --- a/altosui/AltosLine.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 altosui; - -public class AltosLine { - public String line; - - public AltosLine() { - line = null; - } - - public AltosLine(String s) { - line = s; - } -} \ No newline at end of file diff --git a/altosui/AltosParse.java b/altosui/AltosParse.java deleted file mode 100644 index fbfcaaee..00000000 --- a/altosui/AltosParse.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 altosui; - -import java.text.*; -import java.lang.*; - -public class AltosParse { - static boolean isdigit(char c) { - return '0' <= c && c <= '9'; - } - - static int parse_int(String v) throws ParseException { - try { - return Altos.fromdec(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing int " + v, 0); - } - } - - static int parse_hex(String v) throws ParseException { - try { - return Altos.fromhex(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing hex " + v, 0); - } - } - - static double parse_double(String v) throws ParseException { - try { - return Double.parseDouble(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing double " + v, 0); - } - } - - static double parse_coord(String coord) throws ParseException { - String[] dsf = coord.split("\\D+"); - - if (dsf.length != 3) { - throw new ParseException("error parsing coord " + coord, 0); - } - int deg = parse_int(dsf[0]); - int min = parse_int(dsf[1]); - int frac = parse_int(dsf[2]); - - double r = deg + (min + frac / 10000.0) / 60.0; - if (coord.endsWith("S") || coord.endsWith("W")) - r = -r; - return r; - } - - static String strip_suffix(String v, String suffix) { - if (v.endsWith(suffix)) - return v.substring(0, v.length() - suffix.length()); - return v; - } - - static void word(String v, String m) throws ParseException { - if (!v.equals(m)) { - throw new ParseException("error matching '" + v + "' '" + m + "'", 0); - } - } -} diff --git a/altosui/AltosRecord.java b/altosui/AltosRecord.java deleted file mode 100644 index 4643d69a..00000000 --- a/altosui/AltosRecord.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; -import java.io.*; - -public class AltosRecord implements Comparable { - final static int MISSING = 0x7fffffff; - - static final int seen_flight = 1; - static final int seen_sensor = 2; - static final int seen_temp_volt = 4; - static final int seen_deploy = 8; - static final int seen_gps_time = 16; - static final int seen_gps_lat = 32; - static final int seen_gps_lon = 64; - static final int seen_companion = 128; - int seen; - - int version; - String callsign; - int serial; - int flight; - int rssi; - int status; - int state; - int tick; - - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; - - int ground_accel; - int ground_pres; - int accel_plus_g; - int accel_minus_g; - - double acceleration; - double speed; - double height; - - int flight_accel; - int flight_vel; - int flight_pres; - - AltosGPS gps; - boolean new_gps; - - AltosIMU imu; - AltosMag mag; - - double time; /* seconds since boost */ - - int device_type; - int config_major; - int config_minor; - int apogee_delay; - int main_deploy; - int flight_log_max; - String firmware_version; - - AltosRecordCompanion companion; - /* - * Values for our MP3H6115A pressure sensor - * - * From the data sheet: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * - * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa - * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa - */ - - static final double counts_per_kPa = 27 * 2047 / 3300; - static final double counts_at_101_3kPa = 1674.0; - - static double - barometer_to_pressure(double count) - { - return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; - } - - public double raw_pressure() { - if (pres == MISSING) - return MISSING; - return barometer_to_pressure(pres); - } - - public double filtered_pressure() { - if (flight_pres == MISSING) - return MISSING; - return barometer_to_pressure(flight_pres); - } - - public double ground_pressure() { - if (ground_pres == MISSING) - return MISSING; - return barometer_to_pressure(ground_pres); - } - - public double raw_altitude() { - double p = raw_pressure(); - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double ground_altitude() { - double p = ground_pressure(); - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double filtered_altitude() { - if (height != MISSING && ground_pres != MISSING) - return height + ground_altitude(); - - double p = filtered_pressure(); - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double filtered_height() { - if (height != MISSING) - return height; - - double f = filtered_altitude(); - double g = ground_altitude(); - if (f == MISSING || g == MISSING) - return MISSING; - return f - g; - } - - public double raw_height() { - double r = raw_altitude(); - double g = ground_altitude(); - - if (r == MISSING || g == MISSING) - return height; - return r - g; - } - - public double battery_voltage() { - if (batt == MISSING) - return MISSING; - return AltosConvert.cc_battery_to_voltage(batt); - } - - public double main_voltage() { - if (main == MISSING) - return MISSING; - return AltosConvert.cc_ignitor_to_voltage(main); - } - - public double drogue_voltage() { - if (drogue == MISSING) - return MISSING; - return AltosConvert.cc_ignitor_to_voltage(drogue); - } - - /* Value for the CC1111 built-in temperature sensor - * Output voltage at 0°C = 0.755V - * Coefficient = 0.00247V/°C - * Reference voltage = 1.25V - * - * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 - * = (value - 19791.268) / 32768 * 1.25 / 0.00247 - */ - - static double - thermometer_to_temperature(double thermo) - { - return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; - } - - public double temperature() { - if (temp == MISSING) - return MISSING; - return thermometer_to_temperature(temp); - } - - double accel_counts_per_mss() { - double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; - - return counts_per_g / 9.80665; - } - - public double acceleration() { - if (acceleration != MISSING) - return acceleration; - - if (ground_accel == MISSING || accel == MISSING) - return MISSING; - return (ground_accel - accel) / accel_counts_per_mss(); - } - - public double accel_speed() { - if (speed != MISSING) - return speed; - if (flight_vel == MISSING) - return MISSING; - return flight_vel / (accel_counts_per_mss() * 100.0); - } - - public String state() { - return Altos.state_name(state); - } - - public static String gets(FileInputStream s) throws IOException { - int c; - String line = ""; - - while ((c = s.read()) != -1) { - if (c == '\r') - continue; - if (c == '\n') { - return line; - } - line = line + (char) c; - } - return null; - } - - public int compareTo(AltosRecord o) { - return tick - o.tick; - } - - public AltosRecord(AltosRecord old) { - version = old.version; - seen = old.seen; - callsign = old.callsign; - serial = old.serial; - flight = old.flight; - rssi = old.rssi; - status = old.status; - state = old.state; - tick = old.tick; - accel = old.accel; - pres = old.pres; - temp = old.temp; - batt = old.batt; - drogue = old.drogue; - main = old.main; - flight_accel = old.flight_accel; - ground_accel = old.ground_accel; - flight_vel = old.flight_vel; - flight_pres = old.flight_pres; - ground_pres = old.ground_pres; - accel_plus_g = old.accel_plus_g; - accel_minus_g = old.accel_minus_g; - acceleration = old.acceleration; - speed = old.speed; - height = old.height; - gps = new AltosGPS(old.gps); - new_gps = false; - companion = old.companion; - imu = old.imu; - mag = old.mag; - } - - public AltosRecord() { - version = 0; - seen = 0; - callsign = "N0CALL"; - serial = 0; - flight = 0; - rssi = 0; - status = 0; - state = Altos.ao_flight_startup; - tick = 0; - accel = MISSING; - pres = MISSING; - temp = MISSING; - batt = MISSING; - drogue = MISSING; - main = MISSING; - flight_accel = 0; - ground_accel = 0; - flight_vel = 0; - flight_pres = 0; - ground_pres = 0; - accel_plus_g = 0; - accel_minus_g = 0; - acceleration = MISSING; - speed = MISSING; - height = MISSING; - gps = new AltosGPS(); - new_gps = false; - companion = null; - } -} diff --git a/altosui/AltosRecordCompanion.java b/altosui/AltosRecordCompanion.java deleted file mode 100644 index 0a8f9f4b..00000000 --- a/altosui/AltosRecordCompanion.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 altosui; - -public class AltosRecordCompanion { - final static int board_id_telescience = 0x0a; - final static int MAX_CHANNELS = 12; - - int tick; - int board_id; - int update_period; - int channels; - int[] companion_data; - - public AltosRecordCompanion(int in_channels) { - channels = in_channels; - if (channels < 0) - channels = 0; - if (channels > MAX_CHANNELS) - channels = MAX_CHANNELS; - companion_data = new int[channels]; - } -} diff --git a/altosui/AltosRecordIterable.java b/altosui/AltosRecordIterable.java deleted file mode 100644 index 45843b92..00000000 --- a/altosui/AltosRecordIterable.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; - -public abstract class AltosRecordIterable implements Iterable { - public abstract Iterator iterator(); - public void write_comments(PrintStream out) { } - public boolean has_accel() { return false; } - public boolean has_gps() { return false; } - public boolean has_ignite() { return false; }; -} diff --git a/altosui/AltosTelemetry.java b/altosui/AltosTelemetry.java deleted file mode 100644 index 0052ef04..00000000 --- a/altosui/AltosTelemetry.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -/* - * Telemetry data contents - */ - - -/* - * The packet format is a simple hex dump of the raw telemetry frame. - * It starts with 'TELEM', then contains hex digits with a checksum as the last - * byte on the line. - * - * Version 4 is a replacement with consistent syntax. Each telemetry line - * contains a sequence of space-separated names and values, the values are - * either integers or strings. The names are all unique. All values are - * optional - * - * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 - * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 - * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 - * - * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 - * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 - * - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - * - * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports - * in 1/2dB increments while this protocol provides only integers. So, - * the syntax didn't change just the interpretation of the RSSI - * values. - * - * Version 2 of the telemetry data stream is a bit of a mess, with no - * consistent formatting. In particular, the GPS data is formatted for - * viewing instead of parsing. However, the key feature is that every - * telemetry line contains all of the information necessary to - * describe the current rocket state, including the calibration values - * for accelerometer and barometer. - * - * GPS unlocked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ - * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ - * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 - * - * GPS locked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ - * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ - * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ - * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ - * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ - * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 - * - */ - -public class AltosTelemetry extends AltosRecord { - - /* - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - */ - - final static String AO_TELEM_VERSION = "VERSION"; - final static String AO_TELEM_CALL = "c"; - final static String AO_TELEM_SERIAL = "n"; - final static String AO_TELEM_FLIGHT = "f"; - final static String AO_TELEM_RSSI = "r"; - final static String AO_TELEM_STATE = "s"; - final static String AO_TELEM_TICK = "t"; - - /* - * Raw sensor values - * - * Name Value - * r_a Accelerometer reading (integer) - * r_b Barometer reading (integer) - * r_t Thermometer reading (integer) - * r_v Battery reading (integer) - * r_d Drogue continuity (integer) - * r_m Main continuity (integer) - */ - - final static String AO_TELEM_RAW_ACCEL = "r_a"; - final static String AO_TELEM_RAW_BARO = "r_b"; - final static String AO_TELEM_RAW_THERMO = "r_t"; - final static String AO_TELEM_RAW_BATT = "r_v"; - final static String AO_TELEM_RAW_DROGUE = "r_d"; - final static String AO_TELEM_RAW_MAIN = "r_m"; - - /* - * Sensor calibration values - * - * Name Value - * c_a Ground accelerometer reading (integer) - * c_b Ground barometer reading (integer) - * c_p Accelerometer reading for +1g - * c_m Accelerometer reading for -1g - */ - - final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; - final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; - final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; - final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; - - /* - * Kalman state values - * - * Name Value - * k_h Height above pad (integer, meters) - * k_s Vertical speeed (integer, m/s * 16) - * k_a Vertical acceleration (integer, m/s² * 16) - */ - - final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; - final static String AO_TELEM_KALMAN_SPEED = "k_s"; - final static String AO_TELEM_KALMAN_ACCEL = "k_a"; - - /* - * Ad-hoc flight values - * - * Name Value - * a_a Acceleration (integer, sensor units) - * a_s Speed (integer, integrated acceleration value) - * a_b Barometer reading (integer, sensor units) - */ - - final static String AO_TELEM_ADHOC_ACCEL = "a_a"; - final static String AO_TELEM_ADHOC_SPEED = "a_s"; - final static String AO_TELEM_ADHOC_BARO = "a_b"; - - /* - * GPS values - * - * Name Value - * g_s GPS state (string): - * l locked - * u unlocked - * e error (missing or broken) - * g_n Number of sats used in solution - * g_ns Latitude (degrees * 10e7) - * g_ew Longitude (degrees * 10e7) - * g_a Altitude (integer meters) - * g_Y GPS year (integer) - * g_M GPS month (integer - 1-12) - * g_D GPS day (integer - 1-31) - * g_h GPS hour (integer - 0-23) - * g_m GPS minute (integer - 0-59) - * g_s GPS second (integer - 0-59) - * g_v GPS vertical speed (integer, cm/sec) - * g_s GPS horizontal speed (integer, cm/sec) - * g_c GPS course (integer, 0-359) - * g_hd GPS hdop (integer * 10) - * g_vd GPS vdop (integer * 10) - * g_he GPS h error (integer) - * g_ve GPS v error (integer) - */ - - final static String AO_TELEM_GPS_STATE = "g"; - final static String AO_TELEM_GPS_STATE_LOCKED = "l"; - final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; - final static String AO_TELEM_GPS_STATE_ERROR = "e"; - final static String AO_TELEM_GPS_NUM_SAT = "g_n"; - final static String AO_TELEM_GPS_LATITUDE = "g_ns"; - final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; - final static String AO_TELEM_GPS_ALTITUDE = "g_a"; - final static String AO_TELEM_GPS_YEAR = "g_Y"; - final static String AO_TELEM_GPS_MONTH = "g_M"; - final static String AO_TELEM_GPS_DAY = "g_D"; - final static String AO_TELEM_GPS_HOUR = "g_h"; - final static String AO_TELEM_GPS_MINUTE = "g_m"; - final static String AO_TELEM_GPS_SECOND = "g_s"; - final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; - final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; - final static String AO_TELEM_GPS_COURSE = "g_c"; - final static String AO_TELEM_GPS_HDOP = "g_hd"; - final static String AO_TELEM_GPS_VDOP = "g_vd"; - final static String AO_TELEM_GPS_HERROR = "g_he"; - final static String AO_TELEM_GPS_VERROR = "g_ve"; - - /* - * GPS satellite values - * - * Name Value - * s_n Number of satellites reported (integer) - * s_v0 Space vehicle ID (integer) for report 0 - * s_c0 C/N0 number (integer) for report 0 - * s_v1 Space vehicle ID (integer) for report 1 - * s_c1 C/N0 number (integer) for report 1 - * ... - */ - - final static String AO_TELEM_SAT_NUM = "s_n"; - final static String AO_TELEM_SAT_SVID = "s_v"; - final static String AO_TELEM_SAT_C_N_0 = "s_c"; - - static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { - AltosTelemetryRecord r = AltosTelemetryRecord.parse(line); - - return r.update_state(previous); - } -} diff --git a/altosui/AltosTelemetryIterable.java b/altosui/AltosTelemetryIterable.java deleted file mode 100644 index a1b25332..00000000 --- a/altosui/AltosTelemetryIterable.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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 altosui; - -import java.io.*; -import java.util.*; -import java.text.*; - -public class AltosTelemetryIterable extends AltosRecordIterable { - TreeSet records; - - public Iterator iterator () { - return records.iterator(); - } - - boolean has_gps = false; - boolean has_accel = false; - boolean has_ignite = false; - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; }; - - public AltosTelemetryIterable (FileInputStream input) { - boolean saw_boost = false; - int current_tick = 0; - int boost_tick = 0; - - AltosRecord previous = null; - records = new TreeSet (); - - try { - for (;;) { - String line = AltosRecord.gets(input); - if (line == null) { - break; - } - try { - AltosRecord record = AltosTelemetry.parse(line, previous); - if (record == null) - break; - if (records.isEmpty()) { - current_tick = record.tick; - } else { - int tick = record.tick; - while (tick < current_tick - 0x1000) - tick += 0x10000; - current_tick = tick; - record.tick = current_tick; - } - if (!saw_boost && record.state >= Altos.ao_flight_boost) - { - saw_boost = true; - boost_tick = record.tick; - } - if (record.accel != AltosRecord.MISSING) - has_accel = true; - if (record.gps != null) - has_gps = true; - if (record.main != AltosRecord.MISSING) - has_ignite = true; - if (previous != null && previous.tick != record.tick) - records.add(previous); - previous = record; - } catch (ParseException pe) { - System.out.printf("parse exception %s\n", pe.getMessage()); - } catch (AltosCRCException ce) { - } - } - } catch (IOException io) { - System.out.printf("io exception\n"); - } - - if (previous != null) - records.add(previous); - - /* Adjust all tick counts to match expected eeprom values, - * which starts with a 16-bit tick count 16 samples before boost - */ - - int tick_adjust = (boost_tick - 16) & 0xffff0000; - for (AltosRecord r : this) - r.tick -= tick_adjust; - boost_tick -= tick_adjust; - - /* adjust all tick counts to be relative to boost time */ - for (AltosRecord r : this) - r.time = (r.tick - boost_tick) / 100.0; - - try { - input.close(); - } catch (IOException ie) { - } - } -} diff --git a/altosui/AltosTelemetryMap.java b/altosui/AltosTelemetryMap.java deleted file mode 100644 index d906100f..00000000 --- a/altosui/AltosTelemetryMap.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 altosui; -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryMap extends HashMap { - public boolean has(String key) { - return containsKey(key); - } - - public String get_string(String key) throws ParseException { - if (!has(key)) - throw new ParseException ("missing " + key, 0); - return (String) get(key); - } - - public String get_string(String key, String def) { - if (has(key)) - return get(key); - else - return def; - } - - public int get_int(String key) throws ParseException { - return AltosParse.parse_int(get_string(key)); - } - - public int get_int(String key, int def) throws ParseException { - if (has(key)) - return get_int(key); - else - return def; - } - - public double get_double(String key, double def, double scale) throws ParseException { - if (has(key)) - return get_int(key) * scale; - else - return def; - } - - public AltosTelemetryMap(String[] words, int start) { - for (int i = start; i < words.length - 1; i += 2) - put(words[i], words[i+1]); - } -} diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java deleted file mode 100644 index dde60dc9..00000000 --- a/altosui/AltosTelemetryReader.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; -import java.io.*; -import java.util.concurrent.*; - -class AltosTelemetryReader extends AltosFlightReader { - AltosDevice device; - AltosSerial serial; - AltosLog log; - AltosRecord previous; - double frequency; - int telemetry; - - LinkedBlockingQueue telem; - - AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { - AltosLine l = telem.take(); - if (l.line == null) - throw new IOException("IO error"); - AltosRecord next = AltosTelemetry.parse(l.line, previous); - previous = next; - return next; - } - - void flush() { - telem.clear(); - } - - void close(boolean interrupted) { - serial.remove_monitor(telem); - log.close(); - serial.close(); - } - - public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - serial.set_radio_frequency(frequency); - } - - public boolean supports_telemetry(int telemetry) { - - try { - /* Version 1.0 or later firmware supports all telemetry formats */ - if (serial.config_data().compare_version("1.0") >= 0) - return true; - - /* Version 0.9 firmware only supports 0.9 telemetry */ - if (serial.config_data().compare_version("0.9") >= 0) { - if (telemetry == Altos.ao_telemetry_0_9) - return true; - else - return false; - } - - /* Version 0.8 firmware only supports 0.8 telemetry */ - if (telemetry == Altos.ao_telemetry_0_8) - return true; - else - return false; - } catch (InterruptedException ie) { - return true; - } catch (TimeoutException te) { - return true; - } - } - - void save_frequency() { - AltosUIPreferences.set_frequency(device.getSerial(), frequency); - } - - void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - serial.set_telemetry(telemetry); - } - - void save_telemetry() { - AltosUIPreferences.set_telemetry(device.getSerial(), telemetry); - } - - File backing_file() { - return log.file(); - } - - public AltosTelemetryReader (AltosDevice in_device) - throws FileNotFoundException, AltosSerialInUseException, IOException, InterruptedException, TimeoutException { - device = in_device; - serial = new AltosSerial(device); - log = new AltosLog(serial); - name = device.toShortString(); - previous = null; - - telem = new LinkedBlockingQueue(); - frequency = AltosUIPreferences.frequency(device.getSerial()); - set_frequency(frequency); - telemetry = AltosUIPreferences.telemetry(device.getSerial()); - set_telemetry(telemetry); - serial.set_callsign(AltosUIPreferences.callsign()); - serial.add_monitor(telem); - } -} diff --git a/altosui/AltosTelemetryRecord.java b/altosui/AltosTelemetryRecord.java deleted file mode 100644 index 2e6b5ead..00000000 --- a/altosui/AltosTelemetryRecord.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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 altosui; -import java.lang.*; -import java.text.*; - -public abstract class AltosTelemetryRecord { - - long received_time; - abstract public AltosRecord update_state(AltosRecord previous); - - static boolean cksum(int[] bytes) { - int sum = 0x5a; - for (int i = 1; i < bytes.length - 1; i++) - sum += bytes[i]; - sum &= 0xff; - return sum == bytes[bytes.length - 1]; - } - - final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); - final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); - final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; - - final static int packet_type_TM_sensor = 0x01; - final static int packet_type_Tm_sensor = 0x02; - final static int packet_type_Tn_sensor = 0x03; - final static int packet_type_configuration = 0x04; - final static int packet_type_location = 0x05; - final static int packet_type_satellite = 0x06; - final static int packet_type_companion = 0x07; - - static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - int[] bytes; - try { - bytes = Altos.hexbytes(hex); - } catch (NumberFormatException ne) { - throw new ParseException(ne.getMessage(), 0); - } - - /* one for length, one for checksum */ - if (bytes[0] != bytes.length - 2) - throw new ParseException(String.format("invalid length %d != %d\n", - bytes[0], - bytes.length - 2), 0); - if (!cksum(bytes)) - throw new ParseException(String.format("invalid line \"%s\"", hex), 0); - - int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; - int status = Altos.uint8(bytes, bytes.length - 2); - - if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) - throw new AltosCRCException(rssi); - - /* length, data ..., rssi, status, checksum -- 4 bytes extra */ - switch (bytes.length) { - case Altos.ao_telemetry_standard_len + 4: - int type = Altos.uint8(bytes, 4 + 1); - switch (type) { - case packet_type_TM_sensor: - case packet_type_Tm_sensor: - case packet_type_Tn_sensor: - r = new AltosTelemetryRecordSensor(bytes, rssi); - break; - case packet_type_configuration: - r = new AltosTelemetryRecordConfiguration(bytes); - break; - case packet_type_location: - r = new AltosTelemetryRecordLocation(bytes); - break; - case packet_type_satellite: - r = new AltosTelemetryRecordSatellite(bytes); - break; - case packet_type_companion: - r = new AltosTelemetryRecordCompanion(bytes); - break; - default: - r = new AltosTelemetryRecordRaw(bytes); - break; - } - break; - case Altos.ao_telemetry_0_9_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - case Altos.ao_telemetry_0_8_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - default: - throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); - } - r.received_time = System.currentTimeMillis(); - return r; - } - - public static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - String[] word = line.split("\\s+"); - int i =0; - if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(word[i++], "RSSI"); - throw new AltosCRCException(AltosParse.parse_int(word[i++])); - } - - if (word[i].equals("TELEM")) - r = parse_hex(word[i+1]); - else - r = new AltosTelemetryRecordLegacy(line); - return r; - } -} diff --git a/altosui/AltosTelemetryRecordCompanion.java b/altosui/AltosTelemetryRecordCompanion.java deleted file mode 100644 index 52d7f4cf..00000000 --- a/altosui/AltosTelemetryRecordCompanion.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 altosui; - -public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { - - AltosRecordCompanion companion; - - public AltosTelemetryRecordCompanion(int[] in_bytes) { - super(in_bytes); - - int off = 0; - if (uint8(6) == 0) - off = 1; - int channels = uint8(7+off); - - if (off != 0 && channels >= 12) - channels = 11; - - companion = new AltosRecordCompanion(channels); - companion.tick = tick; - companion.board_id = uint8(5); - companion.update_period = uint8(6+off); - for (int i = 0; i < companion.companion_data.length; i++) - companion.companion_data[i] = uint16(8 + off + i * 2); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - next.companion = companion; - next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; - - companion.tick = tick; - return next; - } -} diff --git a/altosui/AltosTelemetryRecordConfiguration.java b/altosui/AltosTelemetryRecordConfiguration.java deleted file mode 100644 index b029d120..00000000 --- a/altosui/AltosTelemetryRecordConfiguration.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 altosui; - - -public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { - int device_type; - int flight; - int config_major; - int config_minor; - int apogee_delay; - int main_deploy; - int flight_log_max; - String callsign; - String version; - - public AltosTelemetryRecordConfiguration(int[] in_bytes) { - super(in_bytes); - - device_type = uint8(5); - flight = uint16(6); - config_major = uint8(8); - config_minor = uint8(9); - apogee_delay = uint16(10); - main_deploy = uint16(12); - flight_log_max = uint16(14); - callsign = string(16, 8); - version = string(24, 8); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - next.device_type = device_type; - next.flight = flight; - next.config_major = config_major; - next.config_minor = config_minor; - next.apogee_delay = apogee_delay; - next.main_deploy = main_deploy; - next.flight_log_max = flight_log_max; - - next.callsign = callsign; - next.firmware_version = version; - - next.seen |= AltosRecord.seen_deploy | AltosRecord.seen_flight; - - return next; - } -} diff --git a/altosui/AltosTelemetryRecordLegacy.java b/altosui/AltosTelemetryRecordLegacy.java deleted file mode 100644 index a72ebb0f..00000000 --- a/altosui/AltosTelemetryRecordLegacy.java +++ /dev/null @@ -1,521 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -/* - * Telemetry data contents - */ - - -/* - * The packet format is a simple hex dump of the raw telemetry frame. - * It starts with 'TELEM', then contains hex digits with a checksum as the last - * byte on the line. - * - * Version 4 is a replacement with consistent syntax. Each telemetry line - * contains a sequence of space-separated names and values, the values are - * either integers or strings. The names are all unique. All values are - * optional - * - * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 - * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 - * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 - * - * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 - * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 - * - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - * - * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports - * in 1/2dB increments while this protocol provides only integers. So, - * the syntax didn't change just the interpretation of the RSSI - * values. - * - * Version 2 of the telemetry data stream is a bit of a mess, with no - * consistent formatting. In particular, the GPS data is formatted for - * viewing instead of parsing. However, the key feature is that every - * telemetry line contains all of the information necessary to - * describe the current rocket state, including the calibration values - * for accelerometer and barometer. - * - * GPS unlocked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ - * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ - * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 - * - * GPS locked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ - * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ - * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ - * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ - * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ - * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 - * - */ - -public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { - /* - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - */ - - final static String AO_TELEM_VERSION = "VERSION"; - final static String AO_TELEM_CALL = "c"; - final static String AO_TELEM_SERIAL = "n"; - final static String AO_TELEM_FLIGHT = "f"; - final static String AO_TELEM_RSSI = "r"; - final static String AO_TELEM_STATE = "s"; - final static String AO_TELEM_TICK = "t"; - - /* - * Raw sensor values - * - * Name Value - * r_a Accelerometer reading (integer) - * r_b Barometer reading (integer) - * r_t Thermometer reading (integer) - * r_v Battery reading (integer) - * r_d Drogue continuity (integer) - * r_m Main continuity (integer) - */ - - final static String AO_TELEM_RAW_ACCEL = "r_a"; - final static String AO_TELEM_RAW_BARO = "r_b"; - final static String AO_TELEM_RAW_THERMO = "r_t"; - final static String AO_TELEM_RAW_BATT = "r_v"; - final static String AO_TELEM_RAW_DROGUE = "r_d"; - final static String AO_TELEM_RAW_MAIN = "r_m"; - - /* - * Sensor calibration values - * - * Name Value - * c_a Ground accelerometer reading (integer) - * c_b Ground barometer reading (integer) - * c_p Accelerometer reading for +1g - * c_m Accelerometer reading for -1g - */ - - final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; - final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; - final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; - final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; - - /* - * Kalman state values - * - * Name Value - * k_h Height above pad (integer, meters) - * k_s Vertical speeed (integer, m/s * 16) - * k_a Vertical acceleration (integer, m/s² * 16) - */ - - final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; - final static String AO_TELEM_KALMAN_SPEED = "k_s"; - final static String AO_TELEM_KALMAN_ACCEL = "k_a"; - - /* - * Ad-hoc flight values - * - * Name Value - * a_a Acceleration (integer, sensor units) - * a_s Speed (integer, integrated acceleration value) - * a_b Barometer reading (integer, sensor units) - */ - - final static String AO_TELEM_ADHOC_ACCEL = "a_a"; - final static String AO_TELEM_ADHOC_SPEED = "a_s"; - final static String AO_TELEM_ADHOC_BARO = "a_b"; - - /* - * GPS values - * - * Name Value - * g_s GPS state (string): - * l locked - * u unlocked - * e error (missing or broken) - * g_n Number of sats used in solution - * g_ns Latitude (degrees * 10e7) - * g_ew Longitude (degrees * 10e7) - * g_a Altitude (integer meters) - * g_Y GPS year (integer) - * g_M GPS month (integer - 1-12) - * g_D GPS day (integer - 1-31) - * g_h GPS hour (integer - 0-23) - * g_m GPS minute (integer - 0-59) - * g_s GPS second (integer - 0-59) - * g_v GPS vertical speed (integer, cm/sec) - * g_s GPS horizontal speed (integer, cm/sec) - * g_c GPS course (integer, 0-359) - * g_hd GPS hdop (integer * 10) - * g_vd GPS vdop (integer * 10) - * g_he GPS h error (integer) - * g_ve GPS v error (integer) - */ - - final static String AO_TELEM_GPS_STATE = "g"; - final static String AO_TELEM_GPS_STATE_LOCKED = "l"; - final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; - final static String AO_TELEM_GPS_STATE_ERROR = "e"; - final static String AO_TELEM_GPS_NUM_SAT = "g_n"; - final static String AO_TELEM_GPS_LATITUDE = "g_ns"; - final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; - final static String AO_TELEM_GPS_ALTITUDE = "g_a"; - final static String AO_TELEM_GPS_YEAR = "g_Y"; - final static String AO_TELEM_GPS_MONTH = "g_M"; - final static String AO_TELEM_GPS_DAY = "g_D"; - final static String AO_TELEM_GPS_HOUR = "g_h"; - final static String AO_TELEM_GPS_MINUTE = "g_m"; - final static String AO_TELEM_GPS_SECOND = "g_s"; - final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; - final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; - final static String AO_TELEM_GPS_COURSE = "g_c"; - final static String AO_TELEM_GPS_HDOP = "g_hd"; - final static String AO_TELEM_GPS_VDOP = "g_vd"; - final static String AO_TELEM_GPS_HERROR = "g_he"; - final static String AO_TELEM_GPS_VERROR = "g_ve"; - - /* - * GPS satellite values - * - * Name Value - * s_n Number of satellites reported (integer) - * s_v0 Space vehicle ID (integer) for report 0 - * s_c0 C/N0 number (integer) for report 0 - * s_v1 Space vehicle ID (integer) for report 1 - * s_c1 C/N0 number (integer) for report 1 - * ... - */ - - final static String AO_TELEM_SAT_NUM = "s_n"; - final static String AO_TELEM_SAT_SVID = "s_v"; - final static String AO_TELEM_SAT_C_N_0 = "s_c"; - - AltosRecord record; - - private void parse_v4(String[] words, int i) throws ParseException { - AltosTelemetryMap map = new AltosTelemetryMap(words, i); - - record.callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); - record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING); - record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); - record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); - record.state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); - record.tick = map.get_int(AO_TELEM_TICK, 0); - - /* raw sensor values */ - record.accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING); - record.pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING); - record.temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING); - record.batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING); - record.drogue = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING); - record.main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING); - - /* sensor calibration information */ - record.ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING); - record.ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING); - record.accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING); - record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING); - - /* flight computer values */ - record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); - record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); - record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); - - record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING); - record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); - record.flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING); - - if (map.has(AO_TELEM_GPS_STATE)) { - record.gps = new AltosGPS(map); - record.new_gps = true; - } - else - record.gps = null; - } - - private void parse_legacy(String[] words, int i) throws ParseException { - - AltosParse.word (words[i++], "CALL"); - record.callsign = words[i++]; - - AltosParse.word (words[i++], "SERIAL"); - record.serial = AltosParse.parse_int(words[i++]); - - if (record.version >= 2) { - AltosParse.word (words[i++], "FLIGHT"); - record.flight = AltosParse.parse_int(words[i++]); - } else - record.flight = 0; - - AltosParse.word(words[i++], "RSSI"); - record.rssi = AltosParse.parse_int(words[i++]); - - /* Older telemetry data had mis-computed RSSI value */ - if (record.version <= 2) - record.rssi = (record.rssi + 74) / 2 - 74; - - AltosParse.word(words[i++], "STATUS"); - record.status = AltosParse.parse_hex(words[i++]); - - AltosParse.word(words[i++], "STATE"); - record.state = Altos.state(words[i++]); - - record.tick = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "a:"); - record.accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "p:"); - record.pres = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "t:"); - record.temp = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "v:"); - record.batt = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "d:"); - record.drogue = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "m:"); - record.main = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fa:"); - record.flight_accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "ga:"); - record.ground_accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fv:"); - record.flight_vel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fp:"); - record.flight_pres = AltosParse.parse_int(words[i++]); - - /* Old TeleDongle code with kalman-reporting TeleMetrum code */ - if ((record.flight_vel & 0xffff0000) == 0x80000000) { - record.speed = ((short) record.flight_vel) / 16.0; - record.acceleration = record.flight_accel / 16.0; - record.height = record.flight_pres; - record.flight_vel = AltosRecord.MISSING; - record.flight_pres = AltosRecord.MISSING; - record.flight_accel = AltosRecord.MISSING; - } - - AltosParse.word(words[i++], "gp:"); - record.ground_pres = AltosParse.parse_int(words[i++]); - - if (record.version >= 1) { - AltosParse.word(words[i++], "a+:"); - record.accel_plus_g = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "a-:"); - record.accel_minus_g = AltosParse.parse_int(words[i++]); - } else { - record.accel_plus_g = record.ground_accel; - record.accel_minus_g = record.ground_accel + 530; - } - - record.gps = new AltosGPS(words, i, record.version); - record.new_gps = true; - } - - public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { - String[] words = line.split("\\s+"); - int i = 0; - - record = new AltosRecord(); - - if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(words[i++], "RSSI"); - record.rssi = AltosParse.parse_int(words[i++]); - throw new AltosCRCException(record.rssi); - } - if (words[i].equals("CALL")) { - record.version = 0; - } else { - AltosParse.word (words[i++], "VERSION"); - record.version = AltosParse.parse_int(words[i++]); - } - - if (record.version < 4) - parse_legacy(words, i); - else - parse_v4(words, i); - } - - /* - * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that - */ - - int[] bytes; - int adjust; - - private int int8(int i) { - return Altos.int8(bytes, i + 1 + adjust); - } - private int uint8(int i) { - return Altos.uint8(bytes, i + 1 + adjust); - } - private int int16(int i) { - return Altos.int16(bytes, i + 1 + adjust); - } - private int uint16(int i) { - return Altos.uint16(bytes, i + 1 + adjust); - } - private int uint32(int i) { - return Altos.uint32(bytes, i + 1 + adjust); - } - private String string(int i, int l) { - return Altos.string(bytes, i + 1 + adjust, l); - } - - static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); - static final int AO_GPS_NUM_SAT_SHIFT = (0); - - static final int AO_GPS_VALID = (1 << 4); - static final int AO_GPS_RUNNING = (1 << 5); - static final int AO_GPS_DATE_VALID = (1 << 6); - static final int AO_GPS_COURSE_VALID = (1 << 7); - - public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { - record = new AltosRecord(); - - bytes = in_bytes; - record.version = 4; - adjust = 0; - - if (bytes.length == Altos.ao_telemetry_0_8_len + 4) { - record.serial = uint8(0); - adjust = -1; - } else - record.serial = uint16(0); - - record.seen = AltosRecord.seen_flight | AltosRecord.seen_sensor | AltosRecord.seen_temp_volt | AltosRecord.seen_deploy; - - record.callsign = string(62, 8); - record.flight = uint16(2); - record.rssi = in_rssi; - record.status = in_status; - record.state = uint8(4); - record.tick = uint16(21); - record.accel = int16(23); - record.pres = int16(25); - record.temp = int16(27); - record.batt = int16(29); - record.drogue = int16(31); - record.main = int16(33); - - record.ground_accel = int16(7); - record.ground_pres = int16(15); - record.accel_plus_g = int16(17); - record.accel_minus_g = int16(19); - - if (uint16(11) == 0x8000) { - record.acceleration = int16(5); - record.speed = int16(9); - record.height = int16(13); - record.flight_accel = AltosRecord.MISSING; - record.flight_vel = AltosRecord.MISSING; - record.flight_pres = AltosRecord.MISSING; - } else { - record.flight_accel = int16(5); - record.flight_vel = uint32(9); - record.flight_pres = int16(13); - record.acceleration = AltosRecord.MISSING; - record.speed = AltosRecord.MISSING; - record.height = AltosRecord.MISSING; - } - - record.gps = null; - - int gps_flags = uint8(41); - - if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { - record.gps = new AltosGPS(); - record.new_gps = true; - - record.seen |= record.seen_gps_time | record.seen_gps_lat | record.seen_gps_lon; - record.gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); - record.gps.locked = (gps_flags & AO_GPS_VALID) != 0; - record.gps.connected = true; - record.gps.lat = uint32(42) / 1.0e7; - record.gps.lon = uint32(46) / 1.0e7; - record.gps.alt = int16(50); - record.gps.ground_speed = uint16(52) / 100.0; - record.gps.course = uint8(54) * 2; - record.gps.hdop = uint8(55) / 5.0; - record.gps.h_error = uint16(58); - record.gps.v_error = uint16(60); - - int n_tracking_reported = uint8(70); - if (n_tracking_reported > 12) - n_tracking_reported = 12; - int n_tracking_actual = 0; - for (int i = 0; i < n_tracking_reported; i++) { - if (uint8(71 + i*2) != 0) - n_tracking_actual++; - } - if (n_tracking_actual > 0) { - record.gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; - - n_tracking_actual = 0; - for (int i = 0; i < n_tracking_reported; i++) { - int svid = uint8(71 + i*2); - int c_n0 = uint8(72 + i*2); - if (svid != 0) - record.gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); - } - } - } - - record.time = 0.0; - } - - public AltosRecord update_state(AltosRecord previous) { - return record; - } -} diff --git a/altosui/AltosTelemetryRecordLocation.java b/altosui/AltosTelemetryRecordLocation.java deleted file mode 100644 index 80db454d..00000000 --- a/altosui/AltosTelemetryRecordLocation.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 altosui; - - -public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { - int flags; - int altitude; - int latitude; - int longitude; - int year; - int month; - int day; - int hour; - int minute; - int second; - int pdop; - int hdop; - int vdop; - int mode; - int ground_speed; - int climb_rate; - int course; - - public AltosTelemetryRecordLocation(int[] in_bytes) { - super(in_bytes); - - flags = uint8(5); - altitude = int16(6); - latitude = uint32(8); - longitude = uint32(12); - year = uint8(16); - month = uint8(17); - day = uint8(18); - hour = uint8(19); - minute = uint8(20); - second = uint8(21); - pdop = uint8(22); - hdop = uint8(23); - vdop = uint8(24); - mode = uint8(25); - ground_speed = uint16(26); - climb_rate = int16(28); - course = uint8(30); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - if (next.gps == null) - next.gps = new AltosGPS(); - - next.gps.nsat = flags & 0xf; - next.gps.locked = (flags & (1 << 4)) != 0; - next.gps.connected = (flags & (1 << 5)) != 0; - - if (next.gps.locked) { - next.gps.lat = latitude * 1.0e-7; - next.gps.lon = longitude * 1.0e-7; - next.gps.alt = altitude; - next.gps.year = 2000 + year; - next.gps.month = month; - next.gps.day = day; - next.gps.hour = hour; - next.gps.minute = minute; - next.gps.second = second; - next.gps.ground_speed = ground_speed * 1.0e-2; - next.gps.course = course * 2; - next.gps.climb_rate = climb_rate * 1.0e-2; - next.gps.hdop = hdop; - next.gps.vdop = vdop; - next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon; - next.new_gps = true; - } - - return next; - } -} diff --git a/altosui/AltosTelemetryRecordRaw.java b/altosui/AltosTelemetryRecordRaw.java deleted file mode 100644 index 08c85e85..00000000 --- a/altosui/AltosTelemetryRecordRaw.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { - int[] bytes; - int serial; - int tick; - int type; - - long received_time; - - public int int8(int off) { - return Altos.int8(bytes, off + 1); - } - - public int uint8(int off) { - return Altos.uint8(bytes, off + 1); - } - - public int int16(int off) { - return Altos.int16(bytes, off + 1); - } - - public int uint16(int off) { - return Altos.uint16(bytes, off + 1); - } - - public int uint32(int off) { - return Altos.uint32(bytes, off + 1); - } - - public String string(int off, int l) { - return Altos.string(bytes, off + 1, l); - } - - public AltosTelemetryRecordRaw(int[] in_bytes) { - bytes = in_bytes; - serial = uint16(0); - tick = uint16(2); - type = uint8(4); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next; - if (previous != null) - next = new AltosRecord(previous); - else - next = new AltosRecord(); - next.serial = serial; - next.tick = tick; - return next; - } - - public long received_time() { - return received_time; - } -} diff --git a/altosui/AltosTelemetryRecordSatellite.java b/altosui/AltosTelemetryRecordSatellite.java deleted file mode 100644 index 2dd782ad..00000000 --- a/altosui/AltosTelemetryRecordSatellite.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 altosui; - -public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { - int channels; - AltosGPSSat[] sats; - - public AltosTelemetryRecordSatellite(int[] in_bytes) { - super(in_bytes); - - channels = uint8(5); - if (channels > 12) - channels = 12; - if (channels == 0) - sats = null; - else { - sats = new AltosGPSSat[channels]; - for (int i = 0; i < channels; i++) { - int svid = uint8(6 + i * 2 + 0); - int c_n_1 = uint8(6 + i * 2 + 1); - sats[i] = new AltosGPSSat(svid, c_n_1); - } - } - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - if (next.gps == null) - next.gps = new AltosGPS(); - - next.gps.cc_gps_sat = sats; - - return next; - } -} diff --git a/altosui/AltosTelemetryRecordSensor.java b/altosui/AltosTelemetryRecordSensor.java deleted file mode 100644 index 96fee81f..00000000 --- a/altosui/AltosTelemetryRecordSensor.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 altosui; - - -public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { - int state; - int accel; - int pres; - int temp; - int v_batt; - int sense_d; - int sense_m; - - int acceleration; - int speed; - int height; - - int ground_accel; - int ground_pres; - int accel_plus_g; - int accel_minus_g; - - int rssi; - - public AltosTelemetryRecordSensor(int[] in_bytes, int in_rssi) { - super(in_bytes); - state = uint8(5); - - accel = int16(6); - pres = int16(8); - temp = int16(10); - v_batt = int16(12); - sense_d = int16(14); - sense_m = int16(16); - - acceleration = int16(18); - speed = int16(20); - height = int16(22); - - ground_pres = int16(24); - ground_accel = int16(26); - accel_plus_g = int16(28); - accel_minus_g = int16(30); - - rssi = in_rssi; - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - next.state = state; - if (type == packet_type_TM_sensor) - next.accel = accel; - else - next.accel = AltosRecord.MISSING; - next.pres = pres; - next.temp = temp; - next.batt = v_batt; - if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) { - next.drogue = sense_d; - next.main = sense_m; - } else { - next.drogue = AltosRecord.MISSING; - next.main = AltosRecord.MISSING; - } - - next.acceleration = acceleration / 16.0; - next.speed = speed / 16.0; - next.height = height; - - next.ground_pres = ground_pres; - if (type == packet_type_TM_sensor) { - next.ground_accel = ground_accel; - next.accel_plus_g = accel_plus_g; - next.accel_minus_g = accel_minus_g; - } else { - next.ground_accel = AltosRecord.MISSING; - next.accel_plus_g = AltosRecord.MISSING; - next.accel_minus_g = AltosRecord.MISSING; - } - - next.rssi = rssi; - - next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; - - return next; - } -} diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am new file mode 100644 index 00000000..9c655131 --- /dev/null +++ b/altosui/altoslib/Makefile.am @@ -0,0 +1,56 @@ +AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation + +JAVAROOT=bin + +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="bin:$(FREETTS)/*:/usr/share/java/*" + +SRC=src/org/altusmetrum/AltosLib +BIN=bin/org/altusmetrum/AltosLib + +AltosLibdir = $(datadir)/java + +AltosLib_JAVA = \ + $(SRC)/AltosLib.java \ + $(SRC)/AltosConvert.java \ + $(SRC)/AltosCRCException.java \ + $(SRC)/AltosFrequency.java \ + $(SRC)/AltosGPS.java \ + $(SRC)/AltosGPSSat.java \ + $(SRC)/AltosLine.java \ + $(SRC)/AltosParse.java \ + $(SRC)/AltosRecordCompanion.java \ + $(SRC)/AltosRecordIterable.java \ + $(SRC)/AltosRecord.java \ + $(SRC)/AltosTelemetryIterable.java \ + $(SRC)/AltosTelemetry.java \ + $(SRC)/AltosTelemetryMap.java \ + $(SRC)/AltosTelemetryRecordCompanion.java \ + $(SRC)/AltosTelemetryRecordConfiguration.java \ + $(SRC)/AltosTelemetryRecordGeneral.java \ + $(SRC)/AltosTelemetryRecord.java \ + $(SRC)/AltosTelemetryRecordLegacy.java \ + $(SRC)/AltosTelemetryRecordLocation.java \ + $(SRC)/AltosTelemetryRecordRaw.java \ + $(SRC)/AltosTelemetryRecordSatellite.java \ + $(SRC)/AltosTelemetryRecordSensor.java + +JAR=AltosLib.jar + +all-local: $(JAR) + +clean-local: + -rm -rf bin $(JAR) + +altosuidir=$(datadir)/java + +install-altosuiJAVA: $(JAR) + @$(NORMAL_INSTALL) + test -z "$(altosuidir)" || $(MKDIR_P) "$(DESTDIR)$(altosuidir)" + echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/$(JAR)"; \ + $(INSTALL_DATA) "$<" "$(DESTDIR)$(altosuidir)" + +bin: + mkdir -p bin + +$(JAR): classAltosLib.stamp + jar cf $@ -C bin org diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java new file mode 100644 index 00000000..4a529bcf --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java @@ -0,0 +1,26 @@ +/* + * 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 altosui; + +public class AltosCRCException extends Exception { + public int rssi; + + public AltosCRCException (int in_rssi) { + rssi = in_rssi; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java new file mode 100644 index 00000000..df41a522 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java @@ -0,0 +1,259 @@ +/* + * 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. + */ + +/* + * Sensor data conversion functions + */ +package altosui; + +public class AltosConvert { + /* + * Pressure Sensor Model, version 1.1 + * + * written by Holly Grimes + * + * Uses the International Standard Atmosphere as described in + * "A Quick Derivation relating altitude to air pressure" (version 1.03) + * from the Portland State Aerospace Society, except that the atmosphere + * is divided into layers with each layer having a different lapse rate. + * + * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 + * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ + return 0; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted altitude */ + for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + base_pressure *= Math.pow(base, exponent); + } + base_temperature += delta_z * lapse_rate[layer_number]; + } + + /* calculate the pressure at the inputted altitude */ + delta_z = altitude - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + pressure = base_pressure * Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + pressure = base_pressure * Math.pow(base, exponent); + } + + return pressure; + } + + +/* outputs the altitude associated with the given pressure. the altitude + returned is measured with respect to the mean sea level */ + static double + pressure_to_altitude(double pressure) + { + + double next_base_temperature = LAYER0_BASE_TEMPERATURE; + double next_base_pressure = LAYER0_BASE_PRESSURE; + + double altitude; + double base_pressure; + double base_temperature; + double base; /* base for function to determine base pressure of next layer */ + double exponent; /* exponent for function to determine base pressure + of next layer */ + double coefficient; + int layer_number; /* identifies layer in the atmosphere */ + int delta_z; /* difference between two altitudes */ + + if (pressure < 0) /* illegal pressure */ + return -1; + if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ + return MAXIMUM_ALTITUDE; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted pressure. */ + layer_number = -1; + do { + layer_number++; + base_pressure = next_base_pressure; + base_temperature = next_base_temperature; + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + next_base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + next_base_pressure *= Math.pow(base, exponent); + } + next_base_temperature += delta_z * lapse_rate[layer_number]; + } + while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); + + /* calculate the altitude associated with the inputted pressure */ + if (lapse_rate[layer_number] == 0.0) { + coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) + * base_temperature; + altitude = base_altitude[layer_number] + + coefficient * Math.log(pressure / base_pressure); + } + else { + base = pressure / base_pressure; + exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] + / GRAVITATIONAL_ACCELERATION; + coefficient = base_temperature / lapse_rate[layer_number]; + altitude = base_altitude[layer_number] + + coefficient * (Math.pow(base, exponent) - 1); + } + + return altitude; + } + + static double + cc_battery_to_voltage(double battery) + { + return battery / 32767.0 * 5.0; + } + + static double + cc_ignitor_to_voltage(double ignite) + { + return ignite / 32767 * 15.0; + } + + static double radio_to_frequency(int freq, int setting, int cal, int channel) { + double f; + + if (freq > 0) + f = freq / 1000.0; + else { + if (setting <= 0) + setting = cal; + f = 434.550 * setting / cal; + /* Round to nearest 50KHz */ + f = Math.floor (20.0 * f + 0.5) / 20.0; + } + return f + channel * 0.100; + } + + static int radio_frequency_to_setting(double frequency, int cal) { + double set = frequency / 434.550 * cal; + + return (int) Math.floor (set + 0.5); + } + + static int radio_frequency_to_channel(double frequency) { + int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); + + if (channel < 0) + channel = 0; + if (channel > 9) + channel = 9; + return channel; + } + + static double radio_channel_to_frequency(int channel) { + return 434.550 + channel * 0.100; + } + + static int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + static double meters_to_feet(double meters) { + return meters * (100 / (2.54 * 12)); + } + + static double meters_to_mach(double meters) { + return meters / 343; /* something close to mach at usual rocket sites */ + } + + static double meters_to_g(double meters) { + return meters / 9.80665; + } + + static int checksum(int[] data, int start, int length) { + int csum = 0x5a; + for (int i = 0; i < length; i++) + csum += data[i + start]; + return csum & 0xff; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFontListener.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFontListener.java new file mode 100644 index 00000000..0dda0f29 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFontListener.java @@ -0,0 +1,22 @@ +/* + * 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 altosui; + +public interface AltosFontListener { + void font_size_changed(int font_size); +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java new file mode 100644 index 00000000..b748e460 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java @@ -0,0 +1,57 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import javax.swing.plaf.basic.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosFrequency { + double frequency; + String description; + + public String toString() { + return String.format("%7.3f MHz %-20s", + frequency, description); + } + + public String toShortString() { + return String.format("%7.3f MHz %s", + frequency, description); + } + + public boolean close(double f) { + double diff = Math.abs(frequency - f); + + return diff < 0.010; + } + + public AltosFrequency(double f, String d) { + frequency = f; + description = d; + } +} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java new file mode 100644 index 00000000..b5df7c9a --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java @@ -0,0 +1,248 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; + +public class AltosGPS { + + final static int MISSING = AltosRecord.MISSING; + + int nsat; + boolean locked; + boolean connected; + double lat; /* degrees (+N -S) */ + double lon; /* degrees (+E -W) */ + int alt; /* m */ + int year; + int month; + int day; + int hour; + int minute; + int second; + + double ground_speed; /* m/s */ + int course; /* degrees */ + double climb_rate; /* m/s */ + double hdop; /* unitless */ + double vdop; /* unitless */ + int h_error; /* m */ + int v_error; /* m */ + + AltosGPSSat[] cc_gps_sat; /* tracking data */ + + void ParseGPSDate(String date) throws ParseException { + String[] ymd = date.split("-"); + if (ymd.length != 3) + throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); + year = AltosParse.parse_int(ymd[0]); + month = AltosParse.parse_int(ymd[1]); + day = AltosParse.parse_int(ymd[2]); + } + + void ParseGPSTime(String time) throws ParseException { + String[] hms = time.split(":"); + if (hms.length != 3) + throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); + hour = AltosParse.parse_int(hms[0]); + minute = AltosParse.parse_int(hms[1]); + second = AltosParse.parse_int(hms[2]); + } + + void ClearGPSTime() { + year = month = day = 0; + hour = minute = second = 0; + } + + public AltosGPS(AltosTelemetryMap map) throws ParseException { + String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, + AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); + + nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0); + if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) { + connected = true; + locked = true; + lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); + lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); + alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING); + year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING); + if (year != MISSING) + year += 2000; + month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING); + day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING); + + hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0); + minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0); + second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0); + + ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, + AltosRecord.MISSING, 1/100.0); + course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, + AltosRecord.MISSING); + hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0); + vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0); + h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING); + v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING); + } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) { + connected = true; + locked = false; + } else { + connected = false; + locked = false; + } + } + + public AltosGPS(String[] words, int i, int version) throws ParseException { + AltosParse.word(words[i++], "GPS"); + nsat = AltosParse.parse_int(words[i++]); + AltosParse.word(words[i++], "sat"); + + connected = false; + locked = false; + lat = lon = 0; + alt = 0; + ClearGPSTime(); + if ((words[i]).equals("unlocked")) { + connected = true; + i++; + } else if ((words[i]).equals("not-connected")) { + i++; + } else if (words.length >= 40) { + locked = true; + connected = true; + + if (version > 1) + ParseGPSDate(words[i++]); + else + year = month = day = 0; + ParseGPSTime(words[i++]); + lat = AltosParse.parse_coord(words[i++]); + lon = AltosParse.parse_coord(words[i++]); + alt = AltosParse.parse_int(words[i++]); + if (version > 1 || (i < words.length && !words[i].equals("SAT"))) { + ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)")); + course = AltosParse.parse_int(words[i++]); + climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)")); + hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)")); + h_error = AltosParse.parse_int(words[i++]); + v_error = AltosParse.parse_int(words[i++]); + } + } else { + i++; + } + if (i < words.length) { + AltosParse.word(words[i++], "SAT"); + int tracking_channels = 0; + if (words[i].equals("not-connected")) + tracking_channels = 0; + else + tracking_channels = AltosParse.parse_int(words[i]); + i++; + cc_gps_sat = new AltosGPSSat[tracking_channels]; + for (int chan = 0; chan < tracking_channels; chan++) { + cc_gps_sat[chan] = new AltosGPSSat(); + cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); + /* Older versions included SiRF status bits */ + if (version < 2) + i++; + cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); + } + } else + cc_gps_sat = new AltosGPSSat[0]; + } + + public void set_latitude(int in_lat) { + lat = in_lat / 10.0e7; + } + + public void set_longitude(int in_lon) { + lon = in_lon / 10.0e7; + } + + public void set_time(int hour, int minute, int second) { + hour = hour; + minute = minute; + second = second; + } + + public void set_date(int year, int month, int day) { + year = year; + month = month; + day = day; + } + + public void set_flags(int flags) { + flags = flags; + } + + public void set_altitude(int altitude) { + altitude = altitude; + } + + public void add_sat(int svid, int c_n0) { + if (cc_gps_sat == null) { + cc_gps_sat = new AltosGPSSat[1]; + } else { + AltosGPSSat[] new_gps_sat = new AltosGPSSat[cc_gps_sat.length + 1]; + for (int i = 0; i < cc_gps_sat.length; i++) + new_gps_sat[i] = cc_gps_sat[i]; + cc_gps_sat = new_gps_sat; + } + AltosGPSSat sat = new AltosGPSSat(); + sat.svid = svid; + sat.c_n0 = c_n0; + cc_gps_sat[cc_gps_sat.length - 1] = sat; + } + + public AltosGPS() { + ClearGPSTime(); + cc_gps_sat = null; + } + + public AltosGPS(AltosGPS old) { + nsat = old.nsat; + locked = old.locked; + connected = old.connected; + lat = old.lat; /* degrees (+N -S) */ + lon = old.lon; /* degrees (+E -W) */ + alt = old.alt; /* m */ + year = old.year; + month = old.month; + day = old.day; + hour = old.hour; + minute = old.minute; + second = old.second; + + ground_speed = old.ground_speed; /* m/s */ + course = old.course; /* degrees */ + climb_rate = old.climb_rate; /* m/s */ + hdop = old.hdop; /* unitless? */ + h_error = old.h_error; /* m */ + v_error = old.v_error; /* m */ + + if (old.cc_gps_sat != null) { + cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; + for (int i = 0; i < old.cc_gps_sat.length; i++) { + cc_gps_sat[i] = new AltosGPSSat(); + cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; + cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; + } + } + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java new file mode 100644 index 00000000..fb125651 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java @@ -0,0 +1,32 @@ +/* + * 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 altosui; + +public class AltosGPSSat { + int svid; + int c_n0; + + public AltosGPSSat(int s, int c) { + svid = s; + c_n0= c; + } + + public AltosGPSSat() { + } +} + diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java new file mode 100644 index 00000000..86e9d4c6 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java @@ -0,0 +1,30 @@ +/* + * 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 altosui; + +public class AltosLine { + public String line; + + public AltosLine() { + line = null; + } + + public AltosLine(String s) { + line = s; + } +} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java new file mode 100644 index 00000000..fbfcaaee --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java @@ -0,0 +1,79 @@ +/* + * 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 altosui; + +import java.text.*; +import java.lang.*; + +public class AltosParse { + static boolean isdigit(char c) { + return '0' <= c && c <= '9'; + } + + static int parse_int(String v) throws ParseException { + try { + return Altos.fromdec(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing int " + v, 0); + } + } + + static int parse_hex(String v) throws ParseException { + try { + return Altos.fromhex(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing hex " + v, 0); + } + } + + static double parse_double(String v) throws ParseException { + try { + return Double.parseDouble(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing double " + v, 0); + } + } + + static double parse_coord(String coord) throws ParseException { + String[] dsf = coord.split("\\D+"); + + if (dsf.length != 3) { + throw new ParseException("error parsing coord " + coord, 0); + } + int deg = parse_int(dsf[0]); + int min = parse_int(dsf[1]); + int frac = parse_int(dsf[2]); + + double r = deg + (min + frac / 10000.0) / 60.0; + if (coord.endsWith("S") || coord.endsWith("W")) + r = -r; + return r; + } + + static String strip_suffix(String v, String suffix) { + if (v.endsWith(suffix)) + return v.substring(0, v.length() - suffix.length()); + return v; + } + + static void word(String v, String m) throws ParseException { + if (!v.equals(m)) { + throw new ParseException("error matching '" + v + "' '" + m + "'", 0); + } + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java new file mode 100644 index 00000000..4643d69a --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java @@ -0,0 +1,317 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; +import java.io.*; + +public class AltosRecord implements Comparable { + final static int MISSING = 0x7fffffff; + + static final int seen_flight = 1; + static final int seen_sensor = 2; + static final int seen_temp_volt = 4; + static final int seen_deploy = 8; + static final int seen_gps_time = 16; + static final int seen_gps_lat = 32; + static final int seen_gps_lon = 64; + static final int seen_companion = 128; + int seen; + + int version; + String callsign; + int serial; + int flight; + int rssi; + int status; + int state; + int tick; + + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + + int ground_accel; + int ground_pres; + int accel_plus_g; + int accel_minus_g; + + double acceleration; + double speed; + double height; + + int flight_accel; + int flight_vel; + int flight_pres; + + AltosGPS gps; + boolean new_gps; + + AltosIMU imu; + AltosMag mag; + + double time; /* seconds since boost */ + + int device_type; + int config_major; + int config_minor; + int apogee_delay; + int main_deploy; + int flight_log_max; + String firmware_version; + + AltosRecordCompanion companion; + /* + * Values for our MP3H6115A pressure sensor + * + * From the data sheet: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * + * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa + * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa + */ + + static final double counts_per_kPa = 27 * 2047 / 3300; + static final double counts_at_101_3kPa = 1674.0; + + static double + barometer_to_pressure(double count) + { + return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; + } + + public double raw_pressure() { + if (pres == MISSING) + return MISSING; + return barometer_to_pressure(pres); + } + + public double filtered_pressure() { + if (flight_pres == MISSING) + return MISSING; + return barometer_to_pressure(flight_pres); + } + + public double ground_pressure() { + if (ground_pres == MISSING) + return MISSING; + return barometer_to_pressure(ground_pres); + } + + public double raw_altitude() { + double p = raw_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double ground_altitude() { + double p = ground_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double filtered_altitude() { + if (height != MISSING && ground_pres != MISSING) + return height + ground_altitude(); + + double p = filtered_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double filtered_height() { + if (height != MISSING) + return height; + + double f = filtered_altitude(); + double g = ground_altitude(); + if (f == MISSING || g == MISSING) + return MISSING; + return f - g; + } + + public double raw_height() { + double r = raw_altitude(); + double g = ground_altitude(); + + if (r == MISSING || g == MISSING) + return height; + return r - g; + } + + public double battery_voltage() { + if (batt == MISSING) + return MISSING; + return AltosConvert.cc_battery_to_voltage(batt); + } + + public double main_voltage() { + if (main == MISSING) + return MISSING; + return AltosConvert.cc_ignitor_to_voltage(main); + } + + public double drogue_voltage() { + if (drogue == MISSING) + return MISSING; + return AltosConvert.cc_ignitor_to_voltage(drogue); + } + + /* Value for the CC1111 built-in temperature sensor + * Output voltage at 0°C = 0.755V + * Coefficient = 0.00247V/°C + * Reference voltage = 1.25V + * + * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 + * = (value - 19791.268) / 32768 * 1.25 / 0.00247 + */ + + static double + thermometer_to_temperature(double thermo) + { + return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; + } + + public double temperature() { + if (temp == MISSING) + return MISSING; + return thermometer_to_temperature(temp); + } + + double accel_counts_per_mss() { + double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; + + return counts_per_g / 9.80665; + } + + public double acceleration() { + if (acceleration != MISSING) + return acceleration; + + if (ground_accel == MISSING || accel == MISSING) + return MISSING; + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public double accel_speed() { + if (speed != MISSING) + return speed; + if (flight_vel == MISSING) + return MISSING; + return flight_vel / (accel_counts_per_mss() * 100.0); + } + + public String state() { + return Altos.state_name(state); + } + + public static String gets(FileInputStream s) throws IOException { + int c; + String line = ""; + + while ((c = s.read()) != -1) { + if (c == '\r') + continue; + if (c == '\n') { + return line; + } + line = line + (char) c; + } + return null; + } + + public int compareTo(AltosRecord o) { + return tick - o.tick; + } + + public AltosRecord(AltosRecord old) { + version = old.version; + seen = old.seen; + callsign = old.callsign; + serial = old.serial; + flight = old.flight; + rssi = old.rssi; + status = old.status; + state = old.state; + tick = old.tick; + accel = old.accel; + pres = old.pres; + temp = old.temp; + batt = old.batt; + drogue = old.drogue; + main = old.main; + flight_accel = old.flight_accel; + ground_accel = old.ground_accel; + flight_vel = old.flight_vel; + flight_pres = old.flight_pres; + ground_pres = old.ground_pres; + accel_plus_g = old.accel_plus_g; + accel_minus_g = old.accel_minus_g; + acceleration = old.acceleration; + speed = old.speed; + height = old.height; + gps = new AltosGPS(old.gps); + new_gps = false; + companion = old.companion; + imu = old.imu; + mag = old.mag; + } + + public AltosRecord() { + version = 0; + seen = 0; + callsign = "N0CALL"; + serial = 0; + flight = 0; + rssi = 0; + status = 0; + state = Altos.ao_flight_startup; + tick = 0; + accel = MISSING; + pres = MISSING; + temp = MISSING; + batt = MISSING; + drogue = MISSING; + main = MISSING; + flight_accel = 0; + ground_accel = 0; + flight_vel = 0; + flight_pres = 0; + ground_pres = 0; + accel_plus_g = 0; + accel_minus_g = 0; + acceleration = MISSING; + speed = MISSING; + height = MISSING; + gps = new AltosGPS(); + new_gps = false; + companion = null; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java new file mode 100644 index 00000000..0a8f9f4b --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java @@ -0,0 +1,38 @@ +/* + * 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 altosui; + +public class AltosRecordCompanion { + final static int board_id_telescience = 0x0a; + final static int MAX_CHANNELS = 12; + + int tick; + int board_id; + int update_period; + int channels; + int[] companion_data; + + public AltosRecordCompanion(int in_channels) { + channels = in_channels; + if (channels < 0) + channels = 0; + if (channels > MAX_CHANNELS) + channels = MAX_CHANNELS; + companion_data = new int[channels]; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java new file mode 100644 index 00000000..45843b92 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java @@ -0,0 +1,37 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +public abstract class AltosRecordIterable implements Iterable { + public abstract Iterator iterator(); + public void write_comments(PrintStream out) { } + public boolean has_accel() { return false; } + public boolean has_gps() { return false; } + public boolean has_ignite() { return false; }; +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java new file mode 100644 index 00000000..0052ef04 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java @@ -0,0 +1,241 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * The packet format is a simple hex dump of the raw telemetry frame. + * It starts with 'TELEM', then contains hex digits with a checksum as the last + * byte on the line. + * + * Version 4 is a replacement with consistent syntax. Each telemetry line + * contains a sequence of space-separated names and values, the values are + * either integers or strings. The names are all unique. All values are + * optional + * + * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 + * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 + * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 + * + * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 + * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 + * + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + * + * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports + * in 1/2dB increments while this protocol provides only integers. So, + * the syntax didn't change just the interpretation of the RSSI + * values. + * + * Version 2 of the telemetry data stream is a bit of a mess, with no + * consistent formatting. In particular, the GPS data is formatted for + * viewing instead of parsing. However, the key feature is that every + * telemetry line contains all of the information necessary to + * describe the current rocket state, including the calibration values + * for accelerometer and barometer. + * + * GPS unlocked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ + * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ + * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 + * + * GPS locked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ + * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ + * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ + * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ + * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ + * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 + * + */ + +public class AltosTelemetry extends AltosRecord { + + /* + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + */ + + final static String AO_TELEM_VERSION = "VERSION"; + final static String AO_TELEM_CALL = "c"; + final static String AO_TELEM_SERIAL = "n"; + final static String AO_TELEM_FLIGHT = "f"; + final static String AO_TELEM_RSSI = "r"; + final static String AO_TELEM_STATE = "s"; + final static String AO_TELEM_TICK = "t"; + + /* + * Raw sensor values + * + * Name Value + * r_a Accelerometer reading (integer) + * r_b Barometer reading (integer) + * r_t Thermometer reading (integer) + * r_v Battery reading (integer) + * r_d Drogue continuity (integer) + * r_m Main continuity (integer) + */ + + final static String AO_TELEM_RAW_ACCEL = "r_a"; + final static String AO_TELEM_RAW_BARO = "r_b"; + final static String AO_TELEM_RAW_THERMO = "r_t"; + final static String AO_TELEM_RAW_BATT = "r_v"; + final static String AO_TELEM_RAW_DROGUE = "r_d"; + final static String AO_TELEM_RAW_MAIN = "r_m"; + + /* + * Sensor calibration values + * + * Name Value + * c_a Ground accelerometer reading (integer) + * c_b Ground barometer reading (integer) + * c_p Accelerometer reading for +1g + * c_m Accelerometer reading for -1g + */ + + final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; + final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; + final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; + final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; + + /* + * Kalman state values + * + * Name Value + * k_h Height above pad (integer, meters) + * k_s Vertical speeed (integer, m/s * 16) + * k_a Vertical acceleration (integer, m/s² * 16) + */ + + final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; + final static String AO_TELEM_KALMAN_SPEED = "k_s"; + final static String AO_TELEM_KALMAN_ACCEL = "k_a"; + + /* + * Ad-hoc flight values + * + * Name Value + * a_a Acceleration (integer, sensor units) + * a_s Speed (integer, integrated acceleration value) + * a_b Barometer reading (integer, sensor units) + */ + + final static String AO_TELEM_ADHOC_ACCEL = "a_a"; + final static String AO_TELEM_ADHOC_SPEED = "a_s"; + final static String AO_TELEM_ADHOC_BARO = "a_b"; + + /* + * GPS values + * + * Name Value + * g_s GPS state (string): + * l locked + * u unlocked + * e error (missing or broken) + * g_n Number of sats used in solution + * g_ns Latitude (degrees * 10e7) + * g_ew Longitude (degrees * 10e7) + * g_a Altitude (integer meters) + * g_Y GPS year (integer) + * g_M GPS month (integer - 1-12) + * g_D GPS day (integer - 1-31) + * g_h GPS hour (integer - 0-23) + * g_m GPS minute (integer - 0-59) + * g_s GPS second (integer - 0-59) + * g_v GPS vertical speed (integer, cm/sec) + * g_s GPS horizontal speed (integer, cm/sec) + * g_c GPS course (integer, 0-359) + * g_hd GPS hdop (integer * 10) + * g_vd GPS vdop (integer * 10) + * g_he GPS h error (integer) + * g_ve GPS v error (integer) + */ + + final static String AO_TELEM_GPS_STATE = "g"; + final static String AO_TELEM_GPS_STATE_LOCKED = "l"; + final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; + final static String AO_TELEM_GPS_STATE_ERROR = "e"; + final static String AO_TELEM_GPS_NUM_SAT = "g_n"; + final static String AO_TELEM_GPS_LATITUDE = "g_ns"; + final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; + final static String AO_TELEM_GPS_ALTITUDE = "g_a"; + final static String AO_TELEM_GPS_YEAR = "g_Y"; + final static String AO_TELEM_GPS_MONTH = "g_M"; + final static String AO_TELEM_GPS_DAY = "g_D"; + final static String AO_TELEM_GPS_HOUR = "g_h"; + final static String AO_TELEM_GPS_MINUTE = "g_m"; + final static String AO_TELEM_GPS_SECOND = "g_s"; + final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; + final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; + final static String AO_TELEM_GPS_COURSE = "g_c"; + final static String AO_TELEM_GPS_HDOP = "g_hd"; + final static String AO_TELEM_GPS_VDOP = "g_vd"; + final static String AO_TELEM_GPS_HERROR = "g_he"; + final static String AO_TELEM_GPS_VERROR = "g_ve"; + + /* + * GPS satellite values + * + * Name Value + * s_n Number of satellites reported (integer) + * s_v0 Space vehicle ID (integer) for report 0 + * s_c0 C/N0 number (integer) for report 0 + * s_v1 Space vehicle ID (integer) for report 1 + * s_c1 C/N0 number (integer) for report 1 + * ... + */ + + final static String AO_TELEM_SAT_NUM = "s_n"; + final static String AO_TELEM_SAT_SVID = "s_v"; + final static String AO_TELEM_SAT_C_N_0 = "s_c"; + + static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { + AltosTelemetryRecord r = AltosTelemetryRecord.parse(line); + + return r.update_state(previous); + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java new file mode 100644 index 00000000..a1b25332 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java @@ -0,0 +1,109 @@ +/* + * 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 altosui; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosTelemetryIterable extends AltosRecordIterable { + TreeSet records; + + public Iterator iterator () { + return records.iterator(); + } + + boolean has_gps = false; + boolean has_accel = false; + boolean has_ignite = false; + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; }; + + public AltosTelemetryIterable (FileInputStream input) { + boolean saw_boost = false; + int current_tick = 0; + int boost_tick = 0; + + AltosRecord previous = null; + records = new TreeSet (); + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) { + break; + } + try { + AltosRecord record = AltosTelemetry.parse(line, previous); + if (record == null) + break; + if (records.isEmpty()) { + current_tick = record.tick; + } else { + int tick = record.tick; + while (tick < current_tick - 0x1000) + tick += 0x10000; + current_tick = tick; + record.tick = current_tick; + } + if (!saw_boost && record.state >= Altos.ao_flight_boost) + { + saw_boost = true; + boost_tick = record.tick; + } + if (record.accel != AltosRecord.MISSING) + has_accel = true; + if (record.gps != null) + has_gps = true; + if (record.main != AltosRecord.MISSING) + has_ignite = true; + if (previous != null && previous.tick != record.tick) + records.add(previous); + previous = record; + } catch (ParseException pe) { + System.out.printf("parse exception %s\n", pe.getMessage()); + } catch (AltosCRCException ce) { + } + } + } catch (IOException io) { + System.out.printf("io exception\n"); + } + + if (previous != null) + records.add(previous); + + /* Adjust all tick counts to match expected eeprom values, + * which starts with a 16-bit tick count 16 samples before boost + */ + + int tick_adjust = (boost_tick - 16) & 0xffff0000; + for (AltosRecord r : this) + r.tick -= tick_adjust; + boost_tick -= tick_adjust; + + /* adjust all tick counts to be relative to boost time */ + for (AltosRecord r : this) + r.time = (r.tick - boost_tick) / 100.0; + + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java new file mode 100644 index 00000000..d906100f --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java @@ -0,0 +1,63 @@ +/* + * 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 altosui; +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryMap extends HashMap { + public boolean has(String key) { + return containsKey(key); + } + + public String get_string(String key) throws ParseException { + if (!has(key)) + throw new ParseException ("missing " + key, 0); + return (String) get(key); + } + + public String get_string(String key, String def) { + if (has(key)) + return get(key); + else + return def; + } + + public int get_int(String key) throws ParseException { + return AltosParse.parse_int(get_string(key)); + } + + public int get_int(String key, int def) throws ParseException { + if (has(key)) + return get_int(key); + else + return def; + } + + public double get_double(String key, double def, double scale) throws ParseException { + if (has(key)) + return get_int(key) * scale; + else + return def; + } + + public AltosTelemetryMap(String[] words, int start) { + for (int i = start; i < words.length - 1; i += 2) + put(words[i], words[i+1]); + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java new file mode 100644 index 00000000..dde60dc9 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java @@ -0,0 +1,119 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +class AltosTelemetryReader extends AltosFlightReader { + AltosDevice device; + AltosSerial serial; + AltosLog log; + AltosRecord previous; + double frequency; + int telemetry; + + LinkedBlockingQueue telem; + + AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { + AltosLine l = telem.take(); + if (l.line == null) + throw new IOException("IO error"); + AltosRecord next = AltosTelemetry.parse(l.line, previous); + previous = next; + return next; + } + + void flush() { + telem.clear(); + } + + void close(boolean interrupted) { + serial.remove_monitor(telem); + log.close(); + serial.close(); + } + + public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + serial.set_radio_frequency(frequency); + } + + public boolean supports_telemetry(int telemetry) { + + try { + /* Version 1.0 or later firmware supports all telemetry formats */ + if (serial.config_data().compare_version("1.0") >= 0) + return true; + + /* Version 0.9 firmware only supports 0.9 telemetry */ + if (serial.config_data().compare_version("0.9") >= 0) { + if (telemetry == Altos.ao_telemetry_0_9) + return true; + else + return false; + } + + /* Version 0.8 firmware only supports 0.8 telemetry */ + if (telemetry == Altos.ao_telemetry_0_8) + return true; + else + return false; + } catch (InterruptedException ie) { + return true; + } catch (TimeoutException te) { + return true; + } + } + + void save_frequency() { + AltosUIPreferences.set_frequency(device.getSerial(), frequency); + } + + void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + serial.set_telemetry(telemetry); + } + + void save_telemetry() { + AltosUIPreferences.set_telemetry(device.getSerial(), telemetry); + } + + File backing_file() { + return log.file(); + } + + public AltosTelemetryReader (AltosDevice in_device) + throws FileNotFoundException, AltosSerialInUseException, IOException, InterruptedException, TimeoutException { + device = in_device; + serial = new AltosSerial(device); + log = new AltosLog(serial); + name = device.toShortString(); + previous = null; + + telem = new LinkedBlockingQueue(); + frequency = AltosUIPreferences.frequency(device.getSerial()); + set_frequency(frequency); + telemetry = AltosUIPreferences.telemetry(device.getSerial()); + set_telemetry(telemetry); + serial.set_callsign(AltosUIPreferences.callsign()); + serial.add_monitor(telem); + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java new file mode 100644 index 00000000..2e6b5ead --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java @@ -0,0 +1,128 @@ +/* + * 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 altosui; +import java.lang.*; +import java.text.*; + +public abstract class AltosTelemetryRecord { + + long received_time; + abstract public AltosRecord update_state(AltosRecord previous); + + static boolean cksum(int[] bytes) { + int sum = 0x5a; + for (int i = 1; i < bytes.length - 1; i++) + sum += bytes[i]; + sum &= 0xff; + return sum == bytes[bytes.length - 1]; + } + + final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); + final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); + final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; + + final static int packet_type_TM_sensor = 0x01; + final static int packet_type_Tm_sensor = 0x02; + final static int packet_type_Tn_sensor = 0x03; + final static int packet_type_configuration = 0x04; + final static int packet_type_location = 0x05; + final static int packet_type_satellite = 0x06; + final static int packet_type_companion = 0x07; + + static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + int[] bytes; + try { + bytes = Altos.hexbytes(hex); + } catch (NumberFormatException ne) { + throw new ParseException(ne.getMessage(), 0); + } + + /* one for length, one for checksum */ + if (bytes[0] != bytes.length - 2) + throw new ParseException(String.format("invalid length %d != %d\n", + bytes[0], + bytes.length - 2), 0); + if (!cksum(bytes)) + throw new ParseException(String.format("invalid line \"%s\"", hex), 0); + + int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; + int status = Altos.uint8(bytes, bytes.length - 2); + + if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) + throw new AltosCRCException(rssi); + + /* length, data ..., rssi, status, checksum -- 4 bytes extra */ + switch (bytes.length) { + case Altos.ao_telemetry_standard_len + 4: + int type = Altos.uint8(bytes, 4 + 1); + switch (type) { + case packet_type_TM_sensor: + case packet_type_Tm_sensor: + case packet_type_Tn_sensor: + r = new AltosTelemetryRecordSensor(bytes, rssi); + break; + case packet_type_configuration: + r = new AltosTelemetryRecordConfiguration(bytes); + break; + case packet_type_location: + r = new AltosTelemetryRecordLocation(bytes); + break; + case packet_type_satellite: + r = new AltosTelemetryRecordSatellite(bytes); + break; + case packet_type_companion: + r = new AltosTelemetryRecordCompanion(bytes); + break; + default: + r = new AltosTelemetryRecordRaw(bytes); + break; + } + break; + case Altos.ao_telemetry_0_9_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + case Altos.ao_telemetry_0_8_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + default: + throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); + } + r.received_time = System.currentTimeMillis(); + return r; + } + + public static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + String[] word = line.split("\\s+"); + int i =0; + if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(word[i++], "RSSI"); + throw new AltosCRCException(AltosParse.parse_int(word[i++])); + } + + if (word[i].equals("TELEM")) + r = parse_hex(word[i+1]); + else + r = new AltosTelemetryRecordLegacy(line); + return r; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java new file mode 100644 index 00000000..52d7f4cf --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java @@ -0,0 +1,52 @@ +/* + * 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 altosui; + +public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { + + AltosRecordCompanion companion; + + public AltosTelemetryRecordCompanion(int[] in_bytes) { + super(in_bytes); + + int off = 0; + if (uint8(6) == 0) + off = 1; + int channels = uint8(7+off); + + if (off != 0 && channels >= 12) + channels = 11; + + companion = new AltosRecordCompanion(channels); + companion.tick = tick; + companion.board_id = uint8(5); + companion.update_period = uint8(6+off); + for (int i = 0; i < companion.companion_data.length; i++) + companion.companion_data[i] = uint16(8 + off + i * 2); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + next.companion = companion; + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + + companion.tick = tick; + return next; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java new file mode 100644 index 00000000..b029d120 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java @@ -0,0 +1,64 @@ +/* + * 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 altosui; + + +public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { + int device_type; + int flight; + int config_major; + int config_minor; + int apogee_delay; + int main_deploy; + int flight_log_max; + String callsign; + String version; + + public AltosTelemetryRecordConfiguration(int[] in_bytes) { + super(in_bytes); + + device_type = uint8(5); + flight = uint16(6); + config_major = uint8(8); + config_minor = uint8(9); + apogee_delay = uint16(10); + main_deploy = uint16(12); + flight_log_max = uint16(14); + callsign = string(16, 8); + version = string(24, 8); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + next.device_type = device_type; + next.flight = flight; + next.config_major = config_major; + next.config_minor = config_minor; + next.apogee_delay = apogee_delay; + next.main_deploy = main_deploy; + next.flight_log_max = flight_log_max; + + next.callsign = callsign; + next.firmware_version = version; + + next.seen |= AltosRecord.seen_deploy | AltosRecord.seen_flight; + + return next; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java new file mode 100644 index 00000000..722baba3 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java @@ -0,0 +1,43 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordGeneral { + + static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + String[] word = line.split("\\s+"); + int i =0; + if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(word[i++], "RSSI"); + throw new AltosCRCException(AltosParse.parse_int(word[i++])); + } + + if (word[i].equals("TELEM")) + r = AltosTelemetryRecordRaw.parse(word[i+1]); + else + r = new AltosTelemetryRecordLegacy(line); + return r; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java new file mode 100644 index 00000000..a72ebb0f --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java @@ -0,0 +1,521 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * The packet format is a simple hex dump of the raw telemetry frame. + * It starts with 'TELEM', then contains hex digits with a checksum as the last + * byte on the line. + * + * Version 4 is a replacement with consistent syntax. Each telemetry line + * contains a sequence of space-separated names and values, the values are + * either integers or strings. The names are all unique. All values are + * optional + * + * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 + * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 + * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 + * + * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 + * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 + * + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + * + * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports + * in 1/2dB increments while this protocol provides only integers. So, + * the syntax didn't change just the interpretation of the RSSI + * values. + * + * Version 2 of the telemetry data stream is a bit of a mess, with no + * consistent formatting. In particular, the GPS data is formatted for + * viewing instead of parsing. However, the key feature is that every + * telemetry line contains all of the information necessary to + * describe the current rocket state, including the calibration values + * for accelerometer and barometer. + * + * GPS unlocked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ + * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ + * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 + * + * GPS locked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ + * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ + * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ + * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ + * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ + * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 + * + */ + +public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { + /* + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + */ + + final static String AO_TELEM_VERSION = "VERSION"; + final static String AO_TELEM_CALL = "c"; + final static String AO_TELEM_SERIAL = "n"; + final static String AO_TELEM_FLIGHT = "f"; + final static String AO_TELEM_RSSI = "r"; + final static String AO_TELEM_STATE = "s"; + final static String AO_TELEM_TICK = "t"; + + /* + * Raw sensor values + * + * Name Value + * r_a Accelerometer reading (integer) + * r_b Barometer reading (integer) + * r_t Thermometer reading (integer) + * r_v Battery reading (integer) + * r_d Drogue continuity (integer) + * r_m Main continuity (integer) + */ + + final static String AO_TELEM_RAW_ACCEL = "r_a"; + final static String AO_TELEM_RAW_BARO = "r_b"; + final static String AO_TELEM_RAW_THERMO = "r_t"; + final static String AO_TELEM_RAW_BATT = "r_v"; + final static String AO_TELEM_RAW_DROGUE = "r_d"; + final static String AO_TELEM_RAW_MAIN = "r_m"; + + /* + * Sensor calibration values + * + * Name Value + * c_a Ground accelerometer reading (integer) + * c_b Ground barometer reading (integer) + * c_p Accelerometer reading for +1g + * c_m Accelerometer reading for -1g + */ + + final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; + final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; + final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; + final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; + + /* + * Kalman state values + * + * Name Value + * k_h Height above pad (integer, meters) + * k_s Vertical speeed (integer, m/s * 16) + * k_a Vertical acceleration (integer, m/s² * 16) + */ + + final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; + final static String AO_TELEM_KALMAN_SPEED = "k_s"; + final static String AO_TELEM_KALMAN_ACCEL = "k_a"; + + /* + * Ad-hoc flight values + * + * Name Value + * a_a Acceleration (integer, sensor units) + * a_s Speed (integer, integrated acceleration value) + * a_b Barometer reading (integer, sensor units) + */ + + final static String AO_TELEM_ADHOC_ACCEL = "a_a"; + final static String AO_TELEM_ADHOC_SPEED = "a_s"; + final static String AO_TELEM_ADHOC_BARO = "a_b"; + + /* + * GPS values + * + * Name Value + * g_s GPS state (string): + * l locked + * u unlocked + * e error (missing or broken) + * g_n Number of sats used in solution + * g_ns Latitude (degrees * 10e7) + * g_ew Longitude (degrees * 10e7) + * g_a Altitude (integer meters) + * g_Y GPS year (integer) + * g_M GPS month (integer - 1-12) + * g_D GPS day (integer - 1-31) + * g_h GPS hour (integer - 0-23) + * g_m GPS minute (integer - 0-59) + * g_s GPS second (integer - 0-59) + * g_v GPS vertical speed (integer, cm/sec) + * g_s GPS horizontal speed (integer, cm/sec) + * g_c GPS course (integer, 0-359) + * g_hd GPS hdop (integer * 10) + * g_vd GPS vdop (integer * 10) + * g_he GPS h error (integer) + * g_ve GPS v error (integer) + */ + + final static String AO_TELEM_GPS_STATE = "g"; + final static String AO_TELEM_GPS_STATE_LOCKED = "l"; + final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; + final static String AO_TELEM_GPS_STATE_ERROR = "e"; + final static String AO_TELEM_GPS_NUM_SAT = "g_n"; + final static String AO_TELEM_GPS_LATITUDE = "g_ns"; + final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; + final static String AO_TELEM_GPS_ALTITUDE = "g_a"; + final static String AO_TELEM_GPS_YEAR = "g_Y"; + final static String AO_TELEM_GPS_MONTH = "g_M"; + final static String AO_TELEM_GPS_DAY = "g_D"; + final static String AO_TELEM_GPS_HOUR = "g_h"; + final static String AO_TELEM_GPS_MINUTE = "g_m"; + final static String AO_TELEM_GPS_SECOND = "g_s"; + final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; + final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; + final static String AO_TELEM_GPS_COURSE = "g_c"; + final static String AO_TELEM_GPS_HDOP = "g_hd"; + final static String AO_TELEM_GPS_VDOP = "g_vd"; + final static String AO_TELEM_GPS_HERROR = "g_he"; + final static String AO_TELEM_GPS_VERROR = "g_ve"; + + /* + * GPS satellite values + * + * Name Value + * s_n Number of satellites reported (integer) + * s_v0 Space vehicle ID (integer) for report 0 + * s_c0 C/N0 number (integer) for report 0 + * s_v1 Space vehicle ID (integer) for report 1 + * s_c1 C/N0 number (integer) for report 1 + * ... + */ + + final static String AO_TELEM_SAT_NUM = "s_n"; + final static String AO_TELEM_SAT_SVID = "s_v"; + final static String AO_TELEM_SAT_C_N_0 = "s_c"; + + AltosRecord record; + + private void parse_v4(String[] words, int i) throws ParseException { + AltosTelemetryMap map = new AltosTelemetryMap(words, i); + + record.callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); + record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING); + record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); + record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); + record.state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + record.tick = map.get_int(AO_TELEM_TICK, 0); + + /* raw sensor values */ + record.accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING); + record.pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING); + record.temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING); + record.batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING); + record.drogue = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING); + record.main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING); + + /* sensor calibration information */ + record.ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING); + record.ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING); + record.accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING); + record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING); + + /* flight computer values */ + record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); + record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); + record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); + + record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING); + record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); + record.flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING); + + if (map.has(AO_TELEM_GPS_STATE)) { + record.gps = new AltosGPS(map); + record.new_gps = true; + } + else + record.gps = null; + } + + private void parse_legacy(String[] words, int i) throws ParseException { + + AltosParse.word (words[i++], "CALL"); + record.callsign = words[i++]; + + AltosParse.word (words[i++], "SERIAL"); + record.serial = AltosParse.parse_int(words[i++]); + + if (record.version >= 2) { + AltosParse.word (words[i++], "FLIGHT"); + record.flight = AltosParse.parse_int(words[i++]); + } else + record.flight = 0; + + AltosParse.word(words[i++], "RSSI"); + record.rssi = AltosParse.parse_int(words[i++]); + + /* Older telemetry data had mis-computed RSSI value */ + if (record.version <= 2) + record.rssi = (record.rssi + 74) / 2 - 74; + + AltosParse.word(words[i++], "STATUS"); + record.status = AltosParse.parse_hex(words[i++]); + + AltosParse.word(words[i++], "STATE"); + record.state = Altos.state(words[i++]); + + record.tick = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a:"); + record.accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "p:"); + record.pres = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "t:"); + record.temp = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "v:"); + record.batt = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "d:"); + record.drogue = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "m:"); + record.main = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fa:"); + record.flight_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "ga:"); + record.ground_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fv:"); + record.flight_vel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fp:"); + record.flight_pres = AltosParse.parse_int(words[i++]); + + /* Old TeleDongle code with kalman-reporting TeleMetrum code */ + if ((record.flight_vel & 0xffff0000) == 0x80000000) { + record.speed = ((short) record.flight_vel) / 16.0; + record.acceleration = record.flight_accel / 16.0; + record.height = record.flight_pres; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + record.flight_accel = AltosRecord.MISSING; + } + + AltosParse.word(words[i++], "gp:"); + record.ground_pres = AltosParse.parse_int(words[i++]); + + if (record.version >= 1) { + AltosParse.word(words[i++], "a+:"); + record.accel_plus_g = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a-:"); + record.accel_minus_g = AltosParse.parse_int(words[i++]); + } else { + record.accel_plus_g = record.ground_accel; + record.accel_minus_g = record.ground_accel + 530; + } + + record.gps = new AltosGPS(words, i, record.version); + record.new_gps = true; + } + + public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { + String[] words = line.split("\\s+"); + int i = 0; + + record = new AltosRecord(); + + if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(words[i++], "RSSI"); + record.rssi = AltosParse.parse_int(words[i++]); + throw new AltosCRCException(record.rssi); + } + if (words[i].equals("CALL")) { + record.version = 0; + } else { + AltosParse.word (words[i++], "VERSION"); + record.version = AltosParse.parse_int(words[i++]); + } + + if (record.version < 4) + parse_legacy(words, i); + else + parse_v4(words, i); + } + + /* + * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that + */ + + int[] bytes; + int adjust; + + private int int8(int i) { + return Altos.int8(bytes, i + 1 + adjust); + } + private int uint8(int i) { + return Altos.uint8(bytes, i + 1 + adjust); + } + private int int16(int i) { + return Altos.int16(bytes, i + 1 + adjust); + } + private int uint16(int i) { + return Altos.uint16(bytes, i + 1 + adjust); + } + private int uint32(int i) { + return Altos.uint32(bytes, i + 1 + adjust); + } + private String string(int i, int l) { + return Altos.string(bytes, i + 1 + adjust, l); + } + + static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); + static final int AO_GPS_NUM_SAT_SHIFT = (0); + + static final int AO_GPS_VALID = (1 << 4); + static final int AO_GPS_RUNNING = (1 << 5); + static final int AO_GPS_DATE_VALID = (1 << 6); + static final int AO_GPS_COURSE_VALID = (1 << 7); + + public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { + record = new AltosRecord(); + + bytes = in_bytes; + record.version = 4; + adjust = 0; + + if (bytes.length == Altos.ao_telemetry_0_8_len + 4) { + record.serial = uint8(0); + adjust = -1; + } else + record.serial = uint16(0); + + record.seen = AltosRecord.seen_flight | AltosRecord.seen_sensor | AltosRecord.seen_temp_volt | AltosRecord.seen_deploy; + + record.callsign = string(62, 8); + record.flight = uint16(2); + record.rssi = in_rssi; + record.status = in_status; + record.state = uint8(4); + record.tick = uint16(21); + record.accel = int16(23); + record.pres = int16(25); + record.temp = int16(27); + record.batt = int16(29); + record.drogue = int16(31); + record.main = int16(33); + + record.ground_accel = int16(7); + record.ground_pres = int16(15); + record.accel_plus_g = int16(17); + record.accel_minus_g = int16(19); + + if (uint16(11) == 0x8000) { + record.acceleration = int16(5); + record.speed = int16(9); + record.height = int16(13); + record.flight_accel = AltosRecord.MISSING; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + } else { + record.flight_accel = int16(5); + record.flight_vel = uint32(9); + record.flight_pres = int16(13); + record.acceleration = AltosRecord.MISSING; + record.speed = AltosRecord.MISSING; + record.height = AltosRecord.MISSING; + } + + record.gps = null; + + int gps_flags = uint8(41); + + if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { + record.gps = new AltosGPS(); + record.new_gps = true; + + record.seen |= record.seen_gps_time | record.seen_gps_lat | record.seen_gps_lon; + record.gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); + record.gps.locked = (gps_flags & AO_GPS_VALID) != 0; + record.gps.connected = true; + record.gps.lat = uint32(42) / 1.0e7; + record.gps.lon = uint32(46) / 1.0e7; + record.gps.alt = int16(50); + record.gps.ground_speed = uint16(52) / 100.0; + record.gps.course = uint8(54) * 2; + record.gps.hdop = uint8(55) / 5.0; + record.gps.h_error = uint16(58); + record.gps.v_error = uint16(60); + + int n_tracking_reported = uint8(70); + if (n_tracking_reported > 12) + n_tracking_reported = 12; + int n_tracking_actual = 0; + for (int i = 0; i < n_tracking_reported; i++) { + if (uint8(71 + i*2) != 0) + n_tracking_actual++; + } + if (n_tracking_actual > 0) { + record.gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; + + n_tracking_actual = 0; + for (int i = 0; i < n_tracking_reported; i++) { + int svid = uint8(71 + i*2); + int c_n0 = uint8(72 + i*2); + if (svid != 0) + record.gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); + } + } + } + + record.time = 0.0; + } + + public AltosRecord update_state(AltosRecord previous) { + return record; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java new file mode 100644 index 00000000..80db454d --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java @@ -0,0 +1,93 @@ +/* + * 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 altosui; + + +public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { + int flags; + int altitude; + int latitude; + int longitude; + int year; + int month; + int day; + int hour; + int minute; + int second; + int pdop; + int hdop; + int vdop; + int mode; + int ground_speed; + int climb_rate; + int course; + + public AltosTelemetryRecordLocation(int[] in_bytes) { + super(in_bytes); + + flags = uint8(5); + altitude = int16(6); + latitude = uint32(8); + longitude = uint32(12); + year = uint8(16); + month = uint8(17); + day = uint8(18); + hour = uint8(19); + minute = uint8(20); + second = uint8(21); + pdop = uint8(22); + hdop = uint8(23); + vdop = uint8(24); + mode = uint8(25); + ground_speed = uint16(26); + climb_rate = int16(28); + course = uint8(30); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + next.gps.nsat = flags & 0xf; + next.gps.locked = (flags & (1 << 4)) != 0; + next.gps.connected = (flags & (1 << 5)) != 0; + + if (next.gps.locked) { + next.gps.lat = latitude * 1.0e-7; + next.gps.lon = longitude * 1.0e-7; + next.gps.alt = altitude; + next.gps.year = 2000 + year; + next.gps.month = month; + next.gps.day = day; + next.gps.hour = hour; + next.gps.minute = minute; + next.gps.second = second; + next.gps.ground_speed = ground_speed * 1.0e-2; + next.gps.course = course * 2; + next.gps.climb_rate = climb_rate * 1.0e-2; + next.gps.hdop = hdop; + next.gps.vdop = vdop; + next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon; + next.new_gps = true; + } + + return next; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java new file mode 100644 index 00000000..08c85e85 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java @@ -0,0 +1,77 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { + int[] bytes; + int serial; + int tick; + int type; + + long received_time; + + public int int8(int off) { + return Altos.int8(bytes, off + 1); + } + + public int uint8(int off) { + return Altos.uint8(bytes, off + 1); + } + + public int int16(int off) { + return Altos.int16(bytes, off + 1); + } + + public int uint16(int off) { + return Altos.uint16(bytes, off + 1); + } + + public int uint32(int off) { + return Altos.uint32(bytes, off + 1); + } + + public String string(int off, int l) { + return Altos.string(bytes, off + 1, l); + } + + public AltosTelemetryRecordRaw(int[] in_bytes) { + bytes = in_bytes; + serial = uint16(0); + tick = uint16(2); + type = uint8(4); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next; + if (previous != null) + next = new AltosRecord(previous); + else + next = new AltosRecord(); + next.serial = serial; + next.tick = tick; + return next; + } + + public long received_time() { + return received_time; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java new file mode 100644 index 00000000..2dd782ad --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java @@ -0,0 +1,52 @@ +/* + * 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 altosui; + +public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { + int channels; + AltosGPSSat[] sats; + + public AltosTelemetryRecordSatellite(int[] in_bytes) { + super(in_bytes); + + channels = uint8(5); + if (channels > 12) + channels = 12; + if (channels == 0) + sats = null; + else { + sats = new AltosGPSSat[channels]; + for (int i = 0; i < channels; i++) { + int svid = uint8(6 + i * 2 + 0); + int c_n_1 = uint8(6 + i * 2 + 1); + sats[i] = new AltosGPSSat(svid, c_n_1); + } + } + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + next.gps.cc_gps_sat = sats; + + return next; + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java new file mode 100644 index 00000000..96fee81f --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java @@ -0,0 +1,104 @@ +/* + * 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 altosui; + + +public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { + int state; + int accel; + int pres; + int temp; + int v_batt; + int sense_d; + int sense_m; + + int acceleration; + int speed; + int height; + + int ground_accel; + int ground_pres; + int accel_plus_g; + int accel_minus_g; + + int rssi; + + public AltosTelemetryRecordSensor(int[] in_bytes, int in_rssi) { + super(in_bytes); + state = uint8(5); + + accel = int16(6); + pres = int16(8); + temp = int16(10); + v_batt = int16(12); + sense_d = int16(14); + sense_m = int16(16); + + acceleration = int16(18); + speed = int16(20); + height = int16(22); + + ground_pres = int16(24); + ground_accel = int16(26); + accel_plus_g = int16(28); + accel_minus_g = int16(30); + + rssi = in_rssi; + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + next.state = state; + if (type == packet_type_TM_sensor) + next.accel = accel; + else + next.accel = AltosRecord.MISSING; + next.pres = pres; + next.temp = temp; + next.batt = v_batt; + if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) { + next.drogue = sense_d; + next.main = sense_m; + } else { + next.drogue = AltosRecord.MISSING; + next.main = AltosRecord.MISSING; + } + + next.acceleration = acceleration / 16.0; + next.speed = speed / 16.0; + next.height = height; + + next.ground_pres = ground_pres; + if (type == packet_type_TM_sensor) { + next.ground_accel = ground_accel; + next.accel_plus_g = accel_plus_g; + next.accel_minus_g = accel_minus_g; + } else { + next.ground_accel = AltosRecord.MISSING; + next.accel_plus_g = AltosRecord.MISSING; + next.accel_minus_g = AltosRecord.MISSING; + } + + next.rssi = rssi; + + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + + return next; + } +} diff --git a/configure.ac b/configure.ac index f84387d2..efccf714 100644 --- a/configure.ac +++ b/configure.ac @@ -113,6 +113,7 @@ AC_OUTPUT([ Makefile altosui/Makefile altosui/AltosVersion.java +altosui/altoslib/Makefile altosui/libaltos/Makefile ao-tools/Makefile ao-tools/lib/Makefile -- cgit v1.2.3 From 71636c1ed7cbe075921391605d1ac4edaa6ee52b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 16:13:46 -0800 Subject: move a file back --- altosui/AltosFontListener.java | 22 ++++++++++++++++++++++ .../altusmetrum/AltosLib/AltosCRCException.java | 2 +- .../src/org/altusmetrum/AltosLib/AltosConvert.java | 2 +- .../altusmetrum/AltosLib/AltosFontListener.java | 22 ---------------------- .../org/altusmetrum/AltosLib/AltosFrequency.java | 2 +- .../src/org/altusmetrum/AltosLib/AltosGPS.java | 2 +- .../src/org/altusmetrum/AltosLib/AltosGPSSat.java | 2 +- .../src/org/altusmetrum/AltosLib/AltosLine.java | 2 +- .../src/org/altusmetrum/AltosLib/AltosParse.java | 6 +++--- .../src/org/altusmetrum/AltosLib/AltosRecord.java | 6 +++--- .../altusmetrum/AltosLib/AltosRecordCompanion.java | 2 +- .../altusmetrum/AltosLib/AltosRecordIterable.java | 2 +- .../org/altusmetrum/AltosLib/AltosTelemetry.java | 2 +- .../AltosLib/AltosTelemetryIterable.java | 4 ++-- .../altusmetrum/AltosLib/AltosTelemetryMap.java | 2 +- .../altusmetrum/AltosLib/AltosTelemetryReader.java | 2 +- .../altusmetrum/AltosLib/AltosTelemetryRecord.java | 4 +--- .../AltosLib/AltosTelemetryRecordCompanion.java | 2 +- .../AltosTelemetryRecordConfiguration.java | 2 +- .../AltosLib/AltosTelemetryRecordGeneral.java | 2 +- .../AltosLib/AltosTelemetryRecordLegacy.java | 16 ++++++++-------- .../AltosLib/AltosTelemetryRecordLocation.java | 2 +- .../AltosLib/AltosTelemetryRecordRaw.java | 14 +++++++------- .../AltosLib/AltosTelemetryRecordSatellite.java | 2 +- .../AltosLib/AltosTelemetryRecordSensor.java | 2 +- 25 files changed, 63 insertions(+), 65 deletions(-) create mode 100644 altosui/AltosFontListener.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFontListener.java (limited to 'altosui') diff --git a/altosui/AltosFontListener.java b/altosui/AltosFontListener.java new file mode 100644 index 00000000..6fc214bc --- /dev/null +++ b/altosui/AltosFontListener.java @@ -0,0 +1,22 @@ +/* + * 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.AltosLib; + +public interface AltosFontListener { + void font_size_changed(int font_size); +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java index 4a529bcf..101c5363 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosCRCException extends Exception { public int rssi; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java index df41a522..6773ab7e 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java @@ -18,7 +18,7 @@ /* * Sensor data conversion functions */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosConvert { /* diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFontListener.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFontListener.java deleted file mode 100644 index 0dda0f29..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFontListener.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 altosui; - -public interface AltosFontListener { - void font_size_changed(int font_size); -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java index b748e460..4c0c7baa 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.awt.*; import java.awt.event.*; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java index b5df7c9a..8cc7aa69 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.lang.*; import java.text.*; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java index fb125651..5fa8f987 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosGPSSat { int svid; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java index 86e9d4c6..5627795a 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosLine { public String line; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java index fbfcaaee..4c0a59cb 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.text.*; import java.lang.*; @@ -27,7 +27,7 @@ public class AltosParse { static int parse_int(String v) throws ParseException { try { - return Altos.fromdec(v); + return AltosLib.fromdec(v); } catch (NumberFormatException e) { throw new ParseException("error parsing int " + v, 0); } @@ -35,7 +35,7 @@ public class AltosParse { static int parse_hex(String v) throws ParseException { try { - return Altos.fromhex(v); + return AltosLib.fromhex(v); } catch (NumberFormatException e) { throw new ParseException("error parsing hex " + v, 0); } diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java index 4643d69a..120004a7 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.lang.*; import java.text.*; @@ -229,7 +229,7 @@ public class AltosRecord implements Comparable { } public String state() { - return Altos.state_name(state); + return AltosLib.state_name(state); } public static String gets(FileInputStream s) throws IOException { @@ -292,7 +292,7 @@ public class AltosRecord implements Comparable { flight = 0; rssi = 0; status = 0; - state = Altos.ao_flight_startup; + state = AltosLib.ao_flight_startup; tick = 0; accel = MISSING; pres = MISSING; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java index 0a8f9f4b..4f8e80dc 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosRecordCompanion { final static int board_id_telescience = 0x0a; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java index 45843b92..abe67aaa 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.awt.*; import java.awt.event.*; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java index 0052ef04..04abb1f3 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.lang.*; import java.text.*; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java index a1b25332..f4b4029f 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.io.*; import java.util.*; @@ -62,7 +62,7 @@ public class AltosTelemetryIterable extends AltosRecordIterable { current_tick = tick; record.tick = current_tick; } - if (!saw_boost && record.state >= Altos.ao_flight_boost) + if (!saw_boost && record.state >= AltosLib.ao_flight_boost) { saw_boost = true; boost_tick = record.tick; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java index d906100f..003cb6a9 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.lang.*; import java.text.*; import java.util.HashMap; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java index dde60dc9..bd94ee36 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.lang.*; import java.text.*; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java index 2e6b5ead..367c148d 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java @@ -15,9 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; -import java.lang.*; -import java.text.*; +package org.altusmetrum.AltosLib; public abstract class AltosTelemetryRecord { diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java index 52d7f4cf..6ad17244 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java index b029d120..25242edc 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java index 722baba3..5e157a54 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.lang.*; import java.text.*; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java index a72ebb0f..8e3713cc 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.lang.*; import java.text.*; @@ -395,22 +395,22 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { int adjust; private int int8(int i) { - return Altos.int8(bytes, i + 1 + adjust); + return AltosLib.int8(bytes, i + 1 + adjust); } private int uint8(int i) { - return Altos.uint8(bytes, i + 1 + adjust); + return AltosLib.uint8(bytes, i + 1 + adjust); } private int int16(int i) { - return Altos.int16(bytes, i + 1 + adjust); + return AltosLib.int16(bytes, i + 1 + adjust); } private int uint16(int i) { - return Altos.uint16(bytes, i + 1 + adjust); + return AltosLib.uint16(bytes, i + 1 + adjust); } private int uint32(int i) { - return Altos.uint32(bytes, i + 1 + adjust); + return AltosLib.uint32(bytes, i + 1 + adjust); } private String string(int i, int l) { - return Altos.string(bytes, i + 1 + adjust, l); + return AltosLib.string(bytes, i + 1 + adjust, l); } static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); @@ -428,7 +428,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { record.version = 4; adjust = 0; - if (bytes.length == Altos.ao_telemetry_0_8_len + 4) { + if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { record.serial = uint8(0); adjust = -1; } else diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java index 80db454d..cddb773d 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java index 08c85e85..43d0f17a 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.lang.*; import java.text.*; @@ -30,27 +30,27 @@ public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { long received_time; public int int8(int off) { - return Altos.int8(bytes, off + 1); + return AltosLib.int8(bytes, off + 1); } public int uint8(int off) { - return Altos.uint8(bytes, off + 1); + return AltosLib.uint8(bytes, off + 1); } public int int16(int off) { - return Altos.int16(bytes, off + 1); + return AltosLib.int16(bytes, off + 1); } public int uint16(int off) { - return Altos.uint16(bytes, off + 1); + return AltosLib.uint16(bytes, off + 1); } public int uint32(int off) { - return Altos.uint32(bytes, off + 1); + return AltosLib.uint32(bytes, off + 1); } public String string(int off, int l) { - return Altos.string(bytes, off + 1, l); + return AltosLib.string(bytes, off + 1, l); } public AltosTelemetryRecordRaw(int[] in_bytes) { diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java index 2dd782ad..2526afb6 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { int channels; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java index 96fee81f..cfaf90b0 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { -- cgit v1.2.3 From 40ee170753f4fd422c848e34a8da104683b7c8a2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 16:16:51 -0800 Subject: altosui: Clean swing/awt bits out of altoslib Signed-off-by: Keith Packard --- .../altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java | 9 --------- .../src/org/altusmetrum/AltosLib/AltosRecordIterable.java | 8 -------- 2 files changed, 17 deletions(-) (limited to 'altosui') diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java index 4c0c7baa..6fd26dfd 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java @@ -17,18 +17,9 @@ package org.altusmetrum.AltosLib; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import javax.swing.event.*; -import javax.swing.plaf.basic.*; import java.io.*; import java.util.*; import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; public class AltosFrequency { double frequency; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java index abe67aaa..ed1787ed 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java @@ -17,16 +17,8 @@ package org.altusmetrum.AltosLib; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; import java.io.*; import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; public abstract class AltosRecordIterable implements Iterable { public abstract Iterator iterator(); -- cgit v1.2.3 From 3c2f601139d36761de6a8a2210545d082ef16133 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 17:26:59 -0800 Subject: altosui: Complete split out of separate java library Signed-off-by: Keith Packard --- altosui/Altos.java | 1 + altosui/AltosAscent.java | 1 + altosui/AltosBTManage.java | 1 + altosui/AltosCSV.java | 1 + altosui/AltosCSVUI.java | 1 + altosui/AltosChannelMenu.java | 1 + altosui/AltosCompanionInfo.java | 1 + altosui/AltosConfig.java | 1 + altosui/AltosConfigData.java | 1 + altosui/AltosConfigFreqUI.java | 1 + altosui/AltosConfigUI.java | 1 + altosui/AltosConfigureUI.java | 1 + altosui/AltosDataChooser.java | 1 + altosui/AltosDataPointReader.java | 1 + altosui/AltosDebug.java | 1 + altosui/AltosDescent.java | 1 + altosui/AltosDialog.java | 1 + altosui/AltosDisplayThread.java | 1 + altosui/AltosEepromChunk.java | 1 + altosui/AltosEepromDelete.java | 1 + altosui/AltosEepromDownload.java | 1 + altosui/AltosEepromIterable.java | 1 + altosui/AltosEepromList.java | 1 + altosui/AltosEepromLog.java | 1 + altosui/AltosEepromManage.java | 1 + altosui/AltosEepromMonitor.java | 1 + altosui/AltosEepromRecord.java | 1 + altosui/AltosEepromTeleScience.java | 1 + altosui/AltosFile.java | 1 + altosui/AltosFlash.java | 1 + altosui/AltosFlashUI.java | 1 + altosui/AltosFlightInfoTableModel.java | 1 + altosui/AltosFlightReader.java | 1 + altosui/AltosFlightStats.java | 1 + altosui/AltosFlightStatsTable.java | 1 + altosui/AltosFlightStatus.java | 1 + altosui/AltosFlightStatusTableModel.java | 1 + altosui/AltosFlightUI.java | 1 + altosui/AltosFrame.java | 1 + altosui/AltosFreqList.java | 1 + altosui/AltosGraph.java | 1 + altosui/AltosGraphTime.java | 1 + altosui/AltosGraphUI.java | 1 + altosui/AltosGreatCircle.java | 1 + altosui/AltosHexfile.java | 1 + altosui/AltosIdleMonitorUI.java | 1 + altosui/AltosIgnite.java | 1 + altosui/AltosIgniteUI.java | 1 + altosui/AltosInfoTable.java | 1 + altosui/AltosKML.java | 1 + altosui/AltosLanded.java | 1 + altosui/AltosLaunch.java | 1 + altosui/AltosLaunchUI.java | 1 + altosui/AltosLed.java | 1 + altosui/AltosLights.java | 1 + altosui/AltosLog.java | 1 + altosui/AltosPad.java | 1 + altosui/AltosPreferences.java | 383 --------------------- altosui/AltosReader.java | 1 + altosui/AltosReplayReader.java | 1 + altosui/AltosRomconfig.java | 1 + altosui/AltosRomconfigUI.java | 1 + altosui/AltosScanUI.java | 1 + altosui/AltosSerial.java | 1 + altosui/AltosSiteMap.java | 1 + altosui/AltosSiteMapCache.java | 1 + altosui/AltosSiteMapPreload.java | 1 + altosui/AltosSiteMapTile.java | 1 + altosui/AltosState.java | 2 + altosui/AltosTelemetryReader.java | 120 +++++++ altosui/AltosUI.java | 1 + altosui/AltosUIPreferences.java | 23 +- altosui/AltosWriter.java | 2 + altosui/GrabNDrag.java | 1 + altosui/Makefile.am | 53 ++- altosui/altoslib/Makefile.am | 3 +- .../src/org/altusmetrum/AltosLib/AltosConvert.java | 44 +-- .../org/altusmetrum/AltosLib/AltosFrequency.java | 4 +- .../src/org/altusmetrum/AltosLib/AltosGPS.java | 56 +-- .../src/org/altusmetrum/AltosLib/AltosGPSSat.java | 4 +- .../src/org/altusmetrum/AltosLib/AltosParse.java | 14 +- .../org/altusmetrum/AltosLib/AltosPreferences.java | 365 ++++++++++++++++++++ .../src/org/altusmetrum/AltosLib/AltosRecord.java | 128 +++---- .../altusmetrum/AltosLib/AltosRecordCompanion.java | 14 +- .../altusmetrum/AltosLib/AltosTelemetryReader.java | 119 ------- 85 files changed, 734 insertions(+), 669 deletions(-) delete mode 100644 altosui/AltosPreferences.java create mode 100644 altosui/AltosTelemetryReader.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index 3e2a7a40..380796cc 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -96,6 +96,7 @@ public class Altos extends AltosLib { static boolean map_initialized = false; static final int tab_elt_pad = 5; + static Font label_font; static Font value_font; static Font status_font; diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index c8e5f3af..38b3b30f 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosAscent extends JComponent implements AltosFlightDisplay { GridBagLayout layout; diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index 6d460701..d2899d65 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -29,6 +29,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index db398a61..be86a454 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -21,6 +21,7 @@ import java.lang.*; import java.io.*; import java.text.*; import java.util.*; +import org.altusmetrum.AltosLib.*; public class AltosCSV implements AltosWriter { File name; diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java index 6d3e9065..2702668b 100644 --- a/altosui/AltosCSVUI.java +++ b/altosui/AltosCSVUI.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosCSVUI extends AltosDialog diff --git a/altosui/AltosChannelMenu.java b/altosui/AltosChannelMenu.java index abbb86f4..0249a0bd 100644 --- a/altosui/AltosChannelMenu.java +++ b/altosui/AltosChannelMenu.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosChannelMenu extends JComboBox implements ActionListener { int channel; diff --git a/altosui/AltosCompanionInfo.java b/altosui/AltosCompanionInfo.java index 82bde623..4ba8fe98 100644 --- a/altosui/AltosCompanionInfo.java +++ b/altosui/AltosCompanionInfo.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosCompanionInfo extends JTable { private AltosFlightInfoTableModel model; diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index bd930206..35fef080 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java index 64d9f095..ef34dd3e 100644 --- a/altosui/AltosConfigData.java +++ b/altosui/AltosConfigData.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java index ecb55449..7958a21c 100644 --- a/altosui/AltosConfigFreqUI.java +++ b/altosui/AltosConfigFreqUI.java @@ -29,6 +29,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; class AltosEditFreqUI extends AltosDialog implements ActionListener { Frame frame; diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index eddb223f..62394fa6 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -28,6 +28,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index 1789cd25..deb179d6 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -30,6 +30,7 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; import javax.swing.plaf.basic.*; +import org.altusmetrum.AltosLib.*; class DelegatingRenderer implements ListCellRenderer { diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index c4a46d01..0d629b3c 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -26,6 +26,7 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.prefs.*; +import org.altusmetrum.AltosLib.*; public class AltosDataChooser extends JFileChooser { JFrame frame; diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index c3aabb0c..821b0771 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -9,6 +9,7 @@ import java.text.ParseException; import java.lang.UnsupportedOperationException; import java.util.NoSuchElementException; import java.util.Iterator; +import org.altusmetrum.AltosLib.*; class AltosDataPointReader implements Iterable { Iterator iter; diff --git a/altosui/AltosDebug.java b/altosui/AltosDebug.java index ce1cf5dd..23e38bc0 100644 --- a/altosui/AltosDebug.java +++ b/altosui/AltosDebug.java @@ -21,6 +21,7 @@ import java.lang.*; import java.io.*; import java.util.concurrent.*; import java.util.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 0fcd690b..664c5ea6 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosDescent extends JComponent implements AltosFlightDisplay { GridBagLayout layout; diff --git a/altosui/AltosDialog.java b/altosui/AltosDialog.java index 1e8e538c..ff38c3e4 100644 --- a/altosui/AltosDialog.java +++ b/altosui/AltosDialog.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java index ce8d9159..03ce4efd 100644 --- a/altosui/AltosDisplayThread.java +++ b/altosui/AltosDisplayThread.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosDisplayThread extends Thread { diff --git a/altosui/AltosEepromChunk.java b/altosui/AltosEepromChunk.java index 77707f7b..e4d11658 100644 --- a/altosui/AltosEepromChunk.java +++ b/altosui/AltosEepromChunk.java @@ -21,6 +21,7 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosEepromChunk { diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index fcce8155..73f3a00f 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 8f7a8544..080bfc99 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java index b8e21ece..11cb97e4 100644 --- a/altosui/AltosEepromIterable.java +++ b/altosui/AltosEepromIterable.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; /* * AltosRecords with an index field so they can be sorted by tick while preserving diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index 945746dd..6a656215 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index 475d7f12..a24e82c0 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index 1e06f4ca..563c90b3 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java index 34f5b891..75643442 100644 --- a/altosui/AltosEepromMonitor.java +++ b/altosui/AltosEepromMonitor.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosEepromMonitor extends AltosDialog { diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java index d8a07951..ea003a1e 100644 --- a/altosui/AltosEepromRecord.java +++ b/altosui/AltosEepromRecord.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosEepromTeleScience.java b/altosui/AltosEepromTeleScience.java index ee1840b0..0c237e11 100644 --- a/altosui/AltosEepromTeleScience.java +++ b/altosui/AltosEepromTeleScience.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosEepromTeleScience { int type; diff --git a/altosui/AltosFile.java b/altosui/AltosFile.java index e2b6d5a6..4cf7de3c 100644 --- a/altosui/AltosFile.java +++ b/altosui/AltosFile.java @@ -20,6 +20,7 @@ package altosui; import java.lang.*; import java.io.File; import java.util.*; +import org.altusmetrum.AltosLib.*; class AltosFile extends File { diff --git a/altosui/AltosFlash.java b/altosui/AltosFlash.java index e91e9806..bd0c8a50 100644 --- a/altosui/AltosFlash.java +++ b/altosui/AltosFlash.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosFlash { File file; diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index f91c542d..4ab73a6d 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosFlashUI extends AltosDialog diff --git a/altosui/AltosFlightInfoTableModel.java b/altosui/AltosFlightInfoTableModel.java index e23eff68..77969a89 100644 --- a/altosui/AltosFlightInfoTableModel.java +++ b/altosui/AltosFlightInfoTableModel.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosFlightInfoTableModel extends AbstractTableModel { final static private String[] columnNames = {"Field", "Value"}; diff --git a/altosui/AltosFlightReader.java b/altosui/AltosFlightReader.java index 3ddf171d..1ac9f848 100644 --- a/altosui/AltosFlightReader.java +++ b/altosui/AltosFlightReader.java @@ -21,6 +21,7 @@ import java.lang.*; import java.text.*; import java.io.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosFlightReader { String name; diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index 578be3f9..ab094c80 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosFlightStats { double max_height; diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index 2d34c6e2..c311b231 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosFlightStatsTable extends JComponent { GridBagLayout layout; diff --git a/altosui/AltosFlightStatus.java b/altosui/AltosFlightStatus.java index 45e55b4b..6a351004 100644 --- a/altosui/AltosFlightStatus.java +++ b/altosui/AltosFlightStatus.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosFlightStatus extends JComponent implements AltosFlightDisplay { GridBagLayout layout; diff --git a/altosui/AltosFlightStatusTableModel.java b/altosui/AltosFlightStatusTableModel.java index 4c24b6ac..75bf16eb 100644 --- a/altosui/AltosFlightStatusTableModel.java +++ b/altosui/AltosFlightStatusTableModel.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosFlightStatusTableModel extends AbstractTableModel { private String[] columnNames = {"Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" }; diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 5c6e0629..ddc54cbd 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosFlightUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { AltosVoice voice; diff --git a/altosui/AltosFrame.java b/altosui/AltosFrame.java index 36ddcae9..70598634 100644 --- a/altosui/AltosFrame.java +++ b/altosui/AltosFrame.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosFreqList.java b/altosui/AltosFreqList.java index e4135df7..1bbc97c6 100644 --- a/altosui/AltosFreqList.java +++ b/altosui/AltosFreqList.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosFreqList extends JComboBox { diff --git a/altosui/AltosGraph.java b/altosui/AltosGraph.java index fbcefd61..54d2bb0b 100644 --- a/altosui/AltosGraph.java +++ b/altosui/AltosGraph.java @@ -8,6 +8,7 @@ import java.io.*; import org.jfree.chart.JFreeChart; import org.jfree.chart.ChartUtilities; +import org.altusmetrum.AltosLib.*; abstract class AltosGraph { public String filename; diff --git a/altosui/AltosGraphTime.java b/altosui/AltosGraphTime.java index 6a084b2c..0955f6e6 100644 --- a/altosui/AltosGraphTime.java +++ b/altosui/AltosGraphTime.java @@ -12,6 +12,7 @@ import java.text.*; import java.awt.Color; import java.util.ArrayList; import java.util.HashMap; +import org.altusmetrum.AltosLib.*; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index c30dc476..527a7d28 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -12,6 +12,7 @@ import java.awt.event.*; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.*; +import org.altusmetrum.AltosLib.*; import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartUtilities; diff --git a/altosui/AltosGreatCircle.java b/altosui/AltosGreatCircle.java index fb1b6ab3..e4af3c18 100644 --- a/altosui/AltosGreatCircle.java +++ b/altosui/AltosGreatCircle.java @@ -18,6 +18,7 @@ package altosui; import java.lang.Math; +import org.altusmetrum.AltosLib.*; public class AltosGreatCircle { double distance; diff --git a/altosui/AltosHexfile.java b/altosui/AltosHexfile.java index 19e35ae1..d52b46c3 100644 --- a/altosui/AltosHexfile.java +++ b/altosui/AltosHexfile.java @@ -23,6 +23,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.LinkedList; import java.util.Iterator; import java.util.Arrays; +import org.altusmetrum.AltosLib.*; class HexFileInputStream extends PushbackInputStream { public int line; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 8eb0d520..02295ea9 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; class AltosADC { int tick; diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index 3e52ea36..c0cd44f1 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -25,6 +25,7 @@ import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.*; import javax.swing.event.*; +import org.altusmetrum.AltosLib.*; public class AltosIgnite { AltosDevice device; diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 8623cbef..076d99b2 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -28,6 +28,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosIgniteUI extends AltosDialog diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java index c023369e..aa6a6d4e 100644 --- a/altosui/AltosInfoTable.java +++ b/altosui/AltosInfoTable.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosInfoTable extends JTable { private AltosFlightInfoTableModel model; diff --git a/altosui/AltosKML.java b/altosui/AltosKML.java index 6bdbecca..2993607b 100644 --- a/altosui/AltosKML.java +++ b/altosui/AltosKML.java @@ -21,6 +21,7 @@ import java.lang.*; import java.io.*; import java.text.*; import java.util.*; +import org.altusmetrum.AltosLib.*; public class AltosKML implements AltosWriter { diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 4dd9a2dd..a47e1cbd 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosLanded extends JComponent implements AltosFlightDisplay, ActionListener { GridBagLayout layout; diff --git a/altosui/AltosLaunch.java b/altosui/AltosLaunch.java index 77f681b8..0e493b91 100644 --- a/altosui/AltosLaunch.java +++ b/altosui/AltosLaunch.java @@ -25,6 +25,7 @@ import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.*; import javax.swing.event.*; +import org.altusmetrum.AltosLib.*; public class AltosLaunch { AltosDevice device; diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index a6c36604..eb76243d 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -28,6 +28,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; class FireButton extends JButton { protected void processMouseEvent(MouseEvent e) { diff --git a/altosui/AltosLed.java b/altosui/AltosLed.java index e08e9960..1358cd48 100644 --- a/altosui/AltosLed.java +++ b/altosui/AltosLed.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosLed extends JLabel { ImageIcon on, off; diff --git a/altosui/AltosLights.java b/altosui/AltosLights.java index 2fa38412..8bd9e7de 100644 --- a/altosui/AltosLights.java +++ b/altosui/AltosLights.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosLights extends JComponent { diff --git a/altosui/AltosLog.java b/altosui/AltosLog.java index a5f1830d..740f0be6 100644 --- a/altosui/AltosLog.java +++ b/altosui/AltosLog.java @@ -22,6 +22,7 @@ import java.lang.*; import java.util.*; import java.text.ParseException; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; /* * This creates a thread to capture telemetry data and write it to diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index 6ef66f7a..0a3f3d65 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; public class AltosPad extends JComponent implements AltosFlightDisplay { GridBagLayout layout; diff --git a/altosui/AltosPreferences.java b/altosui/AltosPreferences.java deleted file mode 100644 index 7510c7c2..00000000 --- a/altosui/AltosPreferences.java +++ /dev/null @@ -1,383 +0,0 @@ -/* - * 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 altosui; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.awt.Component; -import javax.swing.*; -import javax.swing.filechooser.FileSystemView; - -class AltosPreferences { - public static Preferences preferences; - - /* logdir preference name */ - final static String logdirPreference = "LOGDIR"; - - /* channel preference name */ - final static String channelPreferenceFormat = "CHANNEL-%d"; - - /* frequency preference name */ - final static String frequencyPreferenceFormat = "FREQUENCY-%d"; - - /* telemetry format preference name */ - final static String telemetryPreferenceFormat = "TELEMETRY-%d"; - - /* voice preference name */ - final static String voicePreference = "VOICE"; - - /* callsign preference name */ - final static String callsignPreference = "CALLSIGN"; - - /* firmware directory preference name */ - final static String firmwaredirPreference = "FIRMWARE"; - - /* serial debug preference name */ - final static String serialDebugPreference = "SERIAL-DEBUG"; - - /* scanning telemetry preferences name */ - final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; - - /* Launcher serial preference name */ - final static String launcherSerialPreference = "LAUNCHER-SERIAL"; - - /* Launcher channel preference name */ - final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; - - /* Default logdir is ~/TeleMetrum */ - final static String logdirName = "TeleMetrum"; - - /* Log directory */ - static File logdir; - - /* Map directory -- hangs of logdir */ - static File mapdir; - - /* Frequency (map serial to frequency) */ - static Hashtable frequencies; - - /* Telemetry (map serial to telemetry format) */ - static Hashtable telemetries; - - /* Voice preference */ - static boolean voice; - - /* Callsign preference */ - static String callsign; - - /* Firmware directory */ - static File firmwaredir; - - /* Serial debug */ - static boolean serial_debug; - - /* Scanning telemetry */ - static int scanning_telemetry; - - /* List of frequencies */ - final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; - static AltosFrequency[] common_frequencies; - - final static String frequency_count = "COUNT"; - final static String frequency_format = "FREQUENCY-%d"; - final static String description_format = "DESCRIPTION-%d"; - - static AltosFrequency[] load_common_frequencies() { - AltosFrequency[] frequencies = null; - boolean existing = false; - try { - existing = preferences.nodeExists(common_frequencies_node_name); - } catch (BackingStoreException be) { - existing = false; - } - if (existing) { - Preferences node = preferences.node(common_frequencies_node_name); - int count = node.getInt(frequency_count, 0); - - frequencies = new AltosFrequency[count]; - for (int i = 0; i < count; i++) { - double frequency; - String description; - - frequency = node.getDouble(String.format(frequency_format, i), 0.0); - description = node.get(String.format(description_format, i), null); - frequencies[i] = new AltosFrequency(frequency, description); - } - } else { - frequencies = new AltosFrequency[10]; - for (int i = 0; i < 10; i++) { - frequencies[i] = new AltosFrequency(434.550 + i * .1, - String.format("Channel %d", i)); - } - } - return frequencies; - } - - static void save_common_frequencies(AltosFrequency[] frequencies) { - Preferences node = preferences.node(common_frequencies_node_name); - - node.putInt(frequency_count, frequencies.length); - for (int i = 0; i < frequencies.length; i++) { - node.putDouble(String.format(frequency_format, i), frequencies[i].frequency); - node.put(String.format(description_format, i), frequencies[i].description); - } - } - static int launcher_serial; - - static int launcher_channel; - - public static void init() { - preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); - - /* Initialize logdir from preferences */ - String logdir_string = preferences.get(logdirPreference, null); - if (logdir_string != null) - logdir = new File(logdir_string); - else { - /* Use the file system view default directory */ - logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName); - if (!logdir.exists()) - logdir.mkdirs(); - } - mapdir = new File(logdir, "maps"); - if (!mapdir.exists()) - mapdir.mkdirs(); - - frequencies = new Hashtable(); - - telemetries = new Hashtable(); - - voice = preferences.getBoolean(voicePreference, true); - - callsign = preferences.get(callsignPreference,"N0CALL"); - - scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << Altos.ao_telemetry_standard)); - - launcher_serial = preferences.getInt(launcherSerialPreference, 0); - - launcher_channel = preferences.getInt(launcherChannelPreference, 0); - - String firmwaredir_string = preferences.get(firmwaredirPreference, null); - if (firmwaredir_string != null) - firmwaredir = new File(firmwaredir_string); - else - firmwaredir = null; - - serial_debug = preferences.getBoolean(serialDebugPreference, false); - AltosSerial.set_debug(serial_debug); - - common_frequencies = load_common_frequencies(); - - } - - static { init(); } - - static void flush_preferences() { - try { - preferences.flush(); - } catch (BackingStoreException ee) { -/* - if (component != null) - JOptionPane.showMessageDialog(component, - preferences.absolutePath(), - "Cannot save prefernces", - JOptionPane.ERROR_MESSAGE); - else -*/ - System.err.printf("Cannot save preferences\n"); - } - } - - public static void set_logdir(File new_logdir) { - logdir = new_logdir; - mapdir = new File(logdir, "maps"); - if (!mapdir.exists()) - mapdir.mkdirs(); - synchronized (preferences) { - preferences.put(logdirPreference, logdir.getPath()); - flush_preferences(); - } - } - - public static File logdir() { - return logdir; - } - - public static File mapdir() { - return mapdir; - } - - public static void set_frequency(int serial, double new_frequency) { - frequencies.put(serial, new_frequency); - synchronized (preferences) { - preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); - flush_preferences(); - } - } - - public static double frequency(int serial) { - if (frequencies.containsKey(serial)) - return frequencies.get(serial); - double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); - if (frequency == 0.0) { - int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); - frequency = AltosConvert.radio_channel_to_frequency(channel); - } - frequencies.put(serial, frequency); - return frequency; - } - - public static void set_telemetry(int serial, int new_telemetry) { - telemetries.put(serial, new_telemetry); - synchronized (preferences) { - preferences.putInt(String.format(telemetryPreferenceFormat, serial), new_telemetry); - flush_preferences(); - } - } - - public static int telemetry(int serial) { - if (telemetries.containsKey(serial)) - return telemetries.get(serial); - int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), - Altos.ao_telemetry_standard); - telemetries.put(serial, telemetry); - return telemetry; - } - - public static void set_scanning_telemetry(int new_scanning_telemetry) { - scanning_telemetry = new_scanning_telemetry; - synchronized (preferences) { - preferences.putInt(scanningTelemetryPreference, scanning_telemetry); - flush_preferences(); - } - } - - public static int scanning_telemetry() { - return scanning_telemetry; - } - - public static void set_voice(boolean new_voice) { - voice = new_voice; - synchronized (preferences) { - preferences.putBoolean(voicePreference, voice); - flush_preferences(); - } - } - - public static boolean voice() { - return voice; - } - - public static void set_callsign(String new_callsign) { - callsign = new_callsign; - synchronized(preferences) { - preferences.put(callsignPreference, callsign); - flush_preferences(); - } - } - - public static String callsign() { - return callsign; - } - - public static void set_firmwaredir(File new_firmwaredir) { - firmwaredir = new_firmwaredir; - synchronized (preferences) { - preferences.put(firmwaredirPreference, firmwaredir.getPath()); - flush_preferences(); - } - } - - public static File firmwaredir() { - return firmwaredir; - } - - public static void set_serial_debug(boolean new_serial_debug) { - serial_debug = new_serial_debug; - AltosSerial.set_debug(serial_debug); - synchronized (preferences) { - preferences.putBoolean(serialDebugPreference, serial_debug); - flush_preferences(); - } - } - - public static boolean serial_debug() { - return serial_debug; - } - - public static void set_launcher_serial(int new_launcher_serial) { - launcher_serial = new_launcher_serial; - System.out.printf("set launcher serial to %d\n", new_launcher_serial); - synchronized (preferences) { - preferences.putInt(launcherSerialPreference, launcher_serial); - flush_preferences(); - } - } - - public static int launcher_serial() { - return launcher_serial; - } - - public static void set_launcher_channel(int new_launcher_channel) { - launcher_channel = new_launcher_channel; - System.out.printf("set launcher channel to %d\n", new_launcher_channel); - synchronized (preferences) { - preferences.putInt(launcherChannelPreference, launcher_channel); - flush_preferences(); - } - } - - public static int launcher_channel() { - return launcher_channel; - } - - public static Preferences bt_devices() { - return preferences.node("bt_devices"); - } - - public static AltosFrequency[] common_frequencies() { - return common_frequencies; - } - - public static void set_common_frequencies(AltosFrequency[] frequencies) { - common_frequencies = frequencies; - synchronized(preferences) { - save_common_frequencies(frequencies); - flush_preferences(); - } - } - - public static void add_common_frequency(AltosFrequency frequency) { - AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; - int i; - - for (i = 0; i < common_frequencies.length; i++) { - if (frequency.frequency == common_frequencies[i].frequency) - return; - if (frequency.frequency < common_frequencies[i].frequency) - break; - new_frequencies[i] = common_frequencies[i]; - } - new_frequencies[i] = frequency; - for (; i < common_frequencies.length; i++) - new_frequencies[i+1] = common_frequencies[i]; - set_common_frequencies(new_frequencies); - } -} diff --git a/altosui/AltosReader.java b/altosui/AltosReader.java index b9280a0c..aafd5f81 100644 --- a/altosui/AltosReader.java +++ b/altosui/AltosReader.java @@ -20,6 +20,7 @@ package altosui; import java.io.*; import java.util.*; import java.text.*; +import org.altusmetrum.AltosLib.*; public class AltosReader { public AltosRecord read() throws IOException, ParseException { return null; } diff --git a/altosui/AltosReplayReader.java b/altosui/AltosReplayReader.java index eed56cff..f92c0328 100644 --- a/altosui/AltosReplayReader.java +++ b/altosui/AltosReplayReader.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.LinkedBlockingQueue; +import org.altusmetrum.AltosLib.*; /* * Open an existing telemetry file and replay it in realtime diff --git a/altosui/AltosRomconfig.java b/altosui/AltosRomconfig.java index 55056b5e..0a283e51 100644 --- a/altosui/AltosRomconfig.java +++ b/altosui/AltosRomconfig.java @@ -17,6 +17,7 @@ package altosui; import java.io.*; +import org.altusmetrum.AltosLib.*; public class AltosRomconfig { public boolean valid; diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java index e4e38c9c..306b8623 100644 --- a/altosui/AltosRomconfigUI.java +++ b/altosui/AltosRomconfigUI.java @@ -27,6 +27,7 @@ import java.io.*; import java.util.*; import java.text.*; import java.util.prefs.*; +import org.altusmetrum.AltosLib.*; public class AltosRomconfigUI extends AltosDialog diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 2b9137d8..1be8aa26 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -28,6 +28,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; class AltosScanResult { String callsign; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index afb9f21a..74e945f3 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -31,6 +31,7 @@ import java.awt.event.*; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index 93c54d02..b57edcab 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -32,6 +32,7 @@ import java.lang.Math; import java.awt.geom.Point2D; import java.awt.geom.Line2D; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay { // preferred vertical step in a tile in naut. miles diff --git a/altosui/AltosSiteMapCache.java b/altosui/AltosSiteMapCache.java index 2e62cc45..f729a298 100644 --- a/altosui/AltosSiteMapCache.java +++ b/altosui/AltosSiteMapCache.java @@ -29,6 +29,7 @@ import java.text.*; import java.util.prefs.*; import java.net.URL; import java.net.URLConnection; +import org.altusmetrum.AltosLib.*; public class AltosSiteMapCache extends JLabel { public static boolean fetchMap(File file, String url) { diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 5de7a05e..676b0790 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -33,6 +33,7 @@ import java.awt.geom.Point2D; import java.awt.geom.Line2D; import java.net.URL; import java.net.URLConnection; +import org.altusmetrum.AltosLib.*; class AltosMapPos extends Box { AltosUI owner; diff --git a/altosui/AltosSiteMapTile.java b/altosui/AltosSiteMapTile.java index 9e62bb47..34550219 100644 --- a/altosui/AltosSiteMapTile.java +++ b/altosui/AltosSiteMapTile.java @@ -30,6 +30,7 @@ import java.util.prefs.*; import java.lang.Math; import java.awt.geom.Point2D; import java.awt.geom.Line2D; +import org.altusmetrum.AltosLib.*; public class AltosSiteMapTile extends JLayeredPane { JLabel mapLabel; diff --git a/altosui/AltosState.java b/altosui/AltosState.java index 9c6f85eb..403c74be 100644 --- a/altosui/AltosState.java +++ b/altosui/AltosState.java @@ -21,6 +21,8 @@ package altosui; +import org.altusmetrum.AltosLib.*; + public class AltosState { AltosRecord data; diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java new file mode 100644 index 00000000..dc7e4a75 --- /dev/null +++ b/altosui/AltosTelemetryReader.java @@ -0,0 +1,120 @@ +/* + * 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 altosui; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; + +class AltosTelemetryReader extends AltosFlightReader { + AltosDevice device; + AltosSerial serial; + AltosLog log; + AltosRecord previous; + double frequency; + int telemetry; + + LinkedBlockingQueue telem; + + AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { + AltosLine l = telem.take(); + if (l.line == null) + throw new IOException("IO error"); + AltosRecord next = AltosTelemetry.parse(l.line, previous); + previous = next; + return next; + } + + void flush() { + telem.clear(); + } + + void close(boolean interrupted) { + serial.remove_monitor(telem); + log.close(); + serial.close(); + } + + public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + serial.set_radio_frequency(frequency); + } + + public boolean supports_telemetry(int telemetry) { + + try { + /* Version 1.0 or later firmware supports all telemetry formats */ + if (serial.config_data().compare_version("1.0") >= 0) + return true; + + /* Version 0.9 firmware only supports 0.9 telemetry */ + if (serial.config_data().compare_version("0.9") >= 0) { + if (telemetry == Altos.ao_telemetry_0_9) + return true; + else + return false; + } + + /* Version 0.8 firmware only supports 0.8 telemetry */ + if (telemetry == Altos.ao_telemetry_0_8) + return true; + else + return false; + } catch (InterruptedException ie) { + return true; + } catch (TimeoutException te) { + return true; + } + } + + void save_frequency() { + AltosPreferences.set_frequency(device.getSerial(), frequency); + } + + void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + serial.set_telemetry(telemetry); + } + + void save_telemetry() { + AltosPreferences.set_telemetry(device.getSerial(), telemetry); + } + + File backing_file() { + return log.file(); + } + + public AltosTelemetryReader (AltosDevice in_device) + throws FileNotFoundException, AltosSerialInUseException, IOException, InterruptedException, TimeoutException { + device = in_device; + serial = new AltosSerial(device); + log = new AltosLog(serial); + name = device.toShortString(); + previous = null; + + telem = new LinkedBlockingQueue(); + frequency = AltosPreferences.frequency(device.getSerial()); + set_frequency(frequency); + telemetry = AltosPreferences.telemetry(device.getSerial()); + set_telemetry(telemetry); + serial.set_callsign(AltosUIPreferences.callsign()); + serial.add_monitor(telem); + } +} diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index a2816a3a..25c6c36b 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; import libaltosJNI.*; diff --git a/altosui/AltosUIPreferences.java b/altosui/AltosUIPreferences.java index da6c3968..38af734e 100644 --- a/altosui/AltosUIPreferences.java +++ b/altosui/AltosUIPreferences.java @@ -25,10 +25,9 @@ import java.util.concurrent.LinkedBlockingQueue; import java.awt.Component; import javax.swing.*; import javax.swing.filechooser.FileSystemView; +import org.altusmetrum.AltosLib.*; -/* import org.altusmetrum.AltosLib.*; */ - -class AltosUIPreferences extends AltosPreferences { +public class AltosUIPreferences extends AltosPreferences { /* font size preferences name */ final static String fontSizePreference = "FONT-SIZE"; @@ -47,6 +46,9 @@ class AltosUIPreferences extends AltosPreferences { static String look_and_feel = null; + /* Serial debug */ + static boolean serial_debug; + public static void init() { font_listeners = new LinkedList(); @@ -55,6 +57,8 @@ class AltosUIPreferences extends AltosPreferences { look_and_feel = preferences.get(lookAndFeelPreference, UIManager.getSystemLookAndFeelClassName()); ui_listeners = new LinkedList(); + serial_debug = preferences.getBoolean(serialDebugPreference, false); + AltosSerial.set_debug(serial_debug); } static { init(); } @@ -156,4 +160,17 @@ class AltosUIPreferences extends AltosPreferences { ui_listeners.remove(l); } } + public static void set_serial_debug(boolean new_serial_debug) { + serial_debug = new_serial_debug; + AltosSerial.set_debug(serial_debug); + synchronized (preferences) { + preferences.putBoolean(serialDebugPreference, serial_debug); + flush_preferences(); + } + } + + public static boolean serial_debug() { + return serial_debug; + } + } \ No newline at end of file diff --git a/altosui/AltosWriter.java b/altosui/AltosWriter.java index a172dff0..b7375204 100644 --- a/altosui/AltosWriter.java +++ b/altosui/AltosWriter.java @@ -21,6 +21,8 @@ import java.lang.*; import java.io.*; import java.text.*; import java.util.*; +import org.altusmetrum.AltosLib.*; + public interface AltosWriter { diff --git a/altosui/GrabNDrag.java b/altosui/GrabNDrag.java index e6b87b58..c350efec 100644 --- a/altosui/GrabNDrag.java +++ b/altosui/GrabNDrag.java @@ -27,6 +27,7 @@ import javax.swing.table.*; import java.io.*; import java.util.*; import java.text.*; +import org.altusmetrum.AltosLib.*; class GrabNDrag extends MouseInputAdapter { private JComponent scroll; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index c3fd6bb6..cfe45302 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -6,7 +6,7 @@ man_MANS=altosui.1 altoslibdir=$(libdir)/altos -CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:libaltos:$(FREETTS)/*:/usr/share/java/*" +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:altoslib/bin:libaltos:$(FREETTS)/*:/usr/share/java/*" bin_SCRIPTS=altosui @@ -66,10 +66,7 @@ altosui_JAVA = \ AltosFlightStatusUpdate.java \ AltosFlightUI.java \ AltosFontListener.java \ - AltosFrequency.java \ AltosFreqList.java \ - AltosGPS.java \ - AltosGPSSat.java \ AltosGreatCircle.java \ AltosHexfile.java \ Altos.java \ @@ -83,27 +80,11 @@ altosui_JAVA = \ AltosLanded.java \ AltosLed.java \ AltosLights.java \ - AltosLine.java \ AltosLog.java \ AltosPad.java \ - AltosParse.java \ - AltosUIPreferences.java \ - AltosPreferences.java \ AltosUIPreferences.java \ AltosReader.java \ - AltosRecord.java \ - AltosRecordCompanion.java \ - AltosRecordIterable.java \ AltosTelemetryReader.java \ - AltosTelemetryRecord.java \ - AltosTelemetryRecordRaw.java \ - AltosTelemetryRecordSensor.java \ - AltosTelemetryRecordConfiguration.java \ - AltosTelemetryRecordLocation.java \ - AltosTelemetryRecordSatellite.java \ - AltosTelemetryRecordCompanion.java \ - AltosTelemetryRecordLegacy.java \ - AltosTelemetryMap.java \ AltosReplayReader.java \ AltosRomconfig.java \ AltosRomconfigUI.java \ @@ -116,8 +97,7 @@ altosui_JAVA = \ AltosSiteMapCache.java \ AltosSiteMapTile.java \ AltosState.java \ - AltosTelemetry.java \ - AltosTelemetryIterable.java \ + AltosTelemetryReader.java \ AltosUI.java \ AltosUIListener.java \ AltosFrame.java \ @@ -148,6 +128,9 @@ FREETTS_CLASS= \ en_us.jar \ freetts.jar +ALTOSLIB_CLASS=\ + AltosLib.jar + LIBALTOS= \ libaltos.so \ libaltos.dylib \ @@ -200,7 +183,7 @@ LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2 MACOSX_DIST=Altos-Mac-$(VERSION).zip WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe -FAT_FILES=$(FATJAR) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) +FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC) LINUX_EXTRA=altosui-fat @@ -214,7 +197,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) $(FREETTS_CLASS) \ + $(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(ALTOSLIB_CLASS) $(FREETTS_CLASS) \ $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log \ altosui altosui-test altosui-jdb macosx linux @@ -256,13 +239,13 @@ install-altosuiJAVA: altosui.jar classes/altosui: mkdir -p classes/altosui -$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICON) +$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICON) $(ALTOSLIB_CLASS) jar cfm $@ Manifest.txt \ $(ICONJAR) \ -C classes altosui \ -C libaltos libaltosJNI -$(FATJAR): classaltosui.stamp Manifest-fat.txt $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICON) +$(FATJAR): classaltosui.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICON) jar cfm $@ Manifest-fat.txt \ $(ICONJAR) \ -C classes altosui \ @@ -270,11 +253,11 @@ $(FATJAR): classaltosui.stamp Manifest-fat.txt $(FREETTS_CLASS) $(JFREECHART_CLA Manifest.txt: Makefile echo 'Main-Class: altosui.AltosUI' > $@ - echo "Class-Path: $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@ + echo "Class-Path: altoslib.jar $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@ Manifest-fat.txt: echo 'Main-Class: altosui.AltosUI' > $@ - echo "Class-Path: freetts.jar jfreechart.jar jcommon.jar" >> $@ + echo "Class-Path: altoslib.jar freetts.jar jfreechart.jar jcommon.jar" >> $@ altosui: Makefile echo "#!/bin/sh" > $@ @@ -283,7 +266,7 @@ altosui: Makefile altosui-test: Makefile echo "#!/bin/sh" > $@ - echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@ + echo 'exec java -cp ":altoslib/*:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@ chmod +x $@ altosui-jdb: Makefile @@ -317,6 +300,10 @@ build-altos-dll: build-altos64-dll: +cd libaltos && make altos64.dll +$(ALTOSLIB_CLASS): + -rm -f "$@" + $(LN_S) altoslib/"$@" . + $(FREETTS_CLASS): -rm -f "$@" $(LN_S) "$(FREETTS)"/"$@" . @@ -345,9 +332,11 @@ $(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) cp -a AltosUI.app macosx/ mkdir -p macosx/AltOS macosx/AltosUI.app/Contents/Resources/Java cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar - cp -p $(FREETTS_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java - cp -p $(JFREECHART_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java - cp -p $(JCOMMON_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java + cp -p libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java + cp -p $(ALTOSLIB_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 diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index 9c655131..967c8d06 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -18,11 +18,12 @@ AltosLib_JAVA = \ $(SRC)/AltosGPSSat.java \ $(SRC)/AltosLine.java \ $(SRC)/AltosParse.java \ + $(SRC)/AltosPreferences.java \ $(SRC)/AltosRecordCompanion.java \ $(SRC)/AltosRecordIterable.java \ $(SRC)/AltosRecord.java \ - $(SRC)/AltosTelemetryIterable.java \ $(SRC)/AltosTelemetry.java \ + $(SRC)/AltosTelemetryIterable.java \ $(SRC)/AltosTelemetryMap.java \ $(SRC)/AltosTelemetryRecordCompanion.java \ $(SRC)/AltosTelemetryRecordConfiguration.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java index 6773ab7e..3527b575 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java @@ -41,27 +41,27 @@ public class AltosConvert { * in Joules/(kilogram-Kelvin). */ - static final double GRAVITATIONAL_ACCELERATION = -9.80665; - static final double AIR_GAS_CONSTANT = 287.053; - static final double NUMBER_OF_LAYERS = 7; - static final double MAXIMUM_ALTITUDE = 84852.0; - static final double MINIMUM_PRESSURE = 0.3734; - static final double LAYER0_BASE_TEMPERATURE = 288.15; - static final double LAYER0_BASE_PRESSURE = 101325; + public static final double GRAVITATIONAL_ACCELERATION = -9.80665; + public static final double AIR_GAS_CONSTANT = 287.053; + public static final double NUMBER_OF_LAYERS = 7; + public static final double MAXIMUM_ALTITUDE = 84852.0; + public static final double MINIMUM_PRESSURE = 0.3734; + public static final double LAYER0_BASE_TEMPERATURE = 288.15; + public static final double LAYER0_BASE_PRESSURE = 101325; /* lapse rate and base altitude for each layer in the atmosphere */ - static final double[] lapse_rate = { + public static final double[] lapse_rate = { -0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002 }; - static final int[] base_altitude = { + public static final int[] base_altitude = { 0, 11000, 20000, 32000, 47000, 51000, 71000 }; /* outputs atmospheric pressure associated with the given altitude. * altitudes are measured with respect to the mean sea level */ - static double + public static double altitude_to_pressure(double altitude) { double base_temperature = LAYER0_BASE_TEMPERATURE; @@ -114,7 +114,7 @@ public class AltosConvert { /* outputs the altitude associated with the given pressure. the altitude returned is measured with respect to the mean sea level */ - static double + public static double pressure_to_altitude(double pressure) { @@ -178,19 +178,19 @@ public class AltosConvert { return altitude; } - static double + public static double cc_battery_to_voltage(double battery) { return battery / 32767.0 * 5.0; } - static double + public static double cc_ignitor_to_voltage(double ignite) { return ignite / 32767 * 15.0; } - static double radio_to_frequency(int freq, int setting, int cal, int channel) { + public static double radio_to_frequency(int freq, int setting, int cal, int channel) { double f; if (freq > 0) @@ -205,13 +205,13 @@ public class AltosConvert { return f + channel * 0.100; } - static int radio_frequency_to_setting(double frequency, int cal) { + public static int radio_frequency_to_setting(double frequency, int cal) { double set = frequency / 434.550 * cal; return (int) Math.floor (set + 0.5); } - static int radio_frequency_to_channel(double frequency) { + public static int radio_frequency_to_channel(double frequency) { int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); if (channel < 0) @@ -221,11 +221,11 @@ public class AltosConvert { return channel; } - static double radio_channel_to_frequency(int channel) { + public static double radio_channel_to_frequency(int channel) { return 434.550 + channel * 0.100; } - static int[] ParseHex(String line) { + public static int[] ParseHex(String line) { String[] tokens = line.split("\\s+"); int[] array = new int[tokens.length]; @@ -238,19 +238,19 @@ public class AltosConvert { return array; } - static double meters_to_feet(double meters) { + public static double meters_to_feet(double meters) { return meters * (100 / (2.54 * 12)); } - static double meters_to_mach(double meters) { + public static double meters_to_mach(double meters) { return meters / 343; /* something close to mach at usual rocket sites */ } - static double meters_to_g(double meters) { + public static double meters_to_g(double meters) { return meters / 9.80665; } - static int checksum(int[] data, int start, int length) { + public static int checksum(int[] data, int start, int length) { int csum = 0x5a; for (int i = 0; i < length; i++) csum += data[i + start]; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java index 6fd26dfd..f08ff116 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java @@ -22,8 +22,8 @@ import java.util.*; import java.text.*; public class AltosFrequency { - double frequency; - String description; + public double frequency; + public String description; public String toString() { return String.format("%7.3f MHz %-20s", diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java index 8cc7aa69..f078a469 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java @@ -22,32 +22,32 @@ import java.text.*; public class AltosGPS { - final static int MISSING = AltosRecord.MISSING; - - int nsat; - boolean locked; - boolean connected; - double lat; /* degrees (+N -S) */ - double lon; /* degrees (+E -W) */ - int alt; /* m */ - int year; - int month; - int day; - int hour; - int minute; - int second; - - double ground_speed; /* m/s */ - int course; /* degrees */ - double climb_rate; /* m/s */ - double hdop; /* unitless */ - double vdop; /* unitless */ - int h_error; /* m */ - int v_error; /* m */ - - AltosGPSSat[] cc_gps_sat; /* tracking data */ - - void ParseGPSDate(String date) throws ParseException { + public final static int MISSING = AltosRecord.MISSING; + + public int nsat; + public boolean locked; + public boolean connected; + public double lat; /* degrees (+N -S) */ + public double lon; /* degrees (+E -W) */ + public int alt; /* m */ + public int year; + public int month; + public int day; + public int hour; + public int minute; + public int second; + + public double ground_speed; /* m/s */ + public int course; /* degrees */ + public double climb_rate; /* m/s */ + public double hdop; /* unitless */ + public double vdop; /* unitless */ + public int h_error; /* m */ + public int v_error; /* m */ + + public AltosGPSSat[] cc_gps_sat; /* tracking data */ + + public void ParseGPSDate(String date) throws ParseException { String[] ymd = date.split("-"); if (ymd.length != 3) throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); @@ -56,7 +56,7 @@ public class AltosGPS { day = AltosParse.parse_int(ymd[2]); } - void ParseGPSTime(String time) throws ParseException { + public void ParseGPSTime(String time) throws ParseException { String[] hms = time.split(":"); if (hms.length != 3) throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); @@ -65,7 +65,7 @@ public class AltosGPS { second = AltosParse.parse_int(hms[2]); } - void ClearGPSTime() { + public void ClearGPSTime() { year = month = day = 0; hour = minute = second = 0; } diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java index 5fa8f987..faa1ec8d 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java @@ -18,8 +18,8 @@ package org.altusmetrum.AltosLib; public class AltosGPSSat { - int svid; - int c_n0; + public int svid; + public int c_n0; public AltosGPSSat(int s, int c) { svid = s; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java index 4c0a59cb..7d832f1a 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java @@ -21,11 +21,11 @@ import java.text.*; import java.lang.*; public class AltosParse { - static boolean isdigit(char c) { + public static boolean isdigit(char c) { return '0' <= c && c <= '9'; } - static int parse_int(String v) throws ParseException { + public static int parse_int(String v) throws ParseException { try { return AltosLib.fromdec(v); } catch (NumberFormatException e) { @@ -33,7 +33,7 @@ public class AltosParse { } } - static int parse_hex(String v) throws ParseException { + public static int parse_hex(String v) throws ParseException { try { return AltosLib.fromhex(v); } catch (NumberFormatException e) { @@ -41,7 +41,7 @@ public class AltosParse { } } - static double parse_double(String v) throws ParseException { + public static double parse_double(String v) throws ParseException { try { return Double.parseDouble(v); } catch (NumberFormatException e) { @@ -49,7 +49,7 @@ public class AltosParse { } } - static double parse_coord(String coord) throws ParseException { + public static double parse_coord(String coord) throws ParseException { String[] dsf = coord.split("\\D+"); if (dsf.length != 3) { @@ -65,13 +65,13 @@ public class AltosParse { return r; } - static String strip_suffix(String v, String suffix) { + public static String strip_suffix(String v, String suffix) { if (v.endsWith(suffix)) return v.substring(0, v.length() - suffix.length()); return v; } - static void word(String v, String m) throws ParseException { + public static void word(String v, String m) throws ParseException { if (!v.equals(m)) { throw new ParseException("error matching '" + v + "' '" + m + "'", 0); } diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java new file mode 100644 index 00000000..43c7088d --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java @@ -0,0 +1,365 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.awt.Component; +import javax.swing.*; +import javax.swing.filechooser.FileSystemView; + +public class AltosPreferences { + public static Preferences preferences; + + /* logdir preference name */ + public final static String logdirPreference = "LOGDIR"; + + /* channel preference name */ + public final static String channelPreferenceFormat = "CHANNEL-%d"; + + /* frequency preference name */ + public final static String frequencyPreferenceFormat = "FREQUENCY-%d"; + + /* telemetry format preference name */ + public final static String telemetryPreferenceFormat = "TELEMETRY-%d"; + + /* voice preference name */ + public final static String voicePreference = "VOICE"; + + /* callsign preference name */ + public final static String callsignPreference = "CALLSIGN"; + + /* firmware directory preference name */ + public final static String firmwaredirPreference = "FIRMWARE"; + + /* serial debug preference name */ + public final static String serialDebugPreference = "SERIAL-DEBUG"; + + /* scanning telemetry preferences name */ + public final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; + + /* Launcher serial preference name */ + public final static String launcherSerialPreference = "LAUNCHER-SERIAL"; + + /* Launcher channel preference name */ + public final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; + + /* Default logdir is ~/TeleMetrum */ + public final static String logdirName = "TeleMetrum"; + + /* Log directory */ + public static File logdir; + + /* Map directory -- hangs of logdir */ + public static File mapdir; + + /* Frequency (map serial to frequency) */ + public static Hashtable frequencies; + + /* Telemetry (map serial to telemetry format) */ + public static Hashtable telemetries; + + /* Voice preference */ + public static boolean voice; + + /* Callsign preference */ + public static String callsign; + + /* Firmware directory */ + public static File firmwaredir; + + /* Scanning telemetry */ + public static int scanning_telemetry; + + /* List of frequencies */ + public final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; + public static AltosFrequency[] common_frequencies; + + public final static String frequency_count = "COUNT"; + public final static String frequency_format = "FREQUENCY-%d"; + public final static String description_format = "DESCRIPTION-%d"; + + public static AltosFrequency[] load_common_frequencies() { + AltosFrequency[] frequencies = null; + boolean existing = false; + try { + existing = preferences.nodeExists(common_frequencies_node_name); + } catch (BackingStoreException be) { + existing = false; + } + if (existing) { + Preferences node = preferences.node(common_frequencies_node_name); + int count = node.getInt(frequency_count, 0); + + frequencies = new AltosFrequency[count]; + for (int i = 0; i < count; i++) { + double frequency; + String description; + + frequency = node.getDouble(String.format(frequency_format, i), 0.0); + description = node.get(String.format(description_format, i), null); + frequencies[i] = new AltosFrequency(frequency, description); + } + } else { + frequencies = new AltosFrequency[10]; + for (int i = 0; i < 10; i++) { + frequencies[i] = new AltosFrequency(434.550 + i * .1, + String.format("Channel %d", i)); + } + } + return frequencies; + } + + public static void save_common_frequencies(AltosFrequency[] frequencies) { + Preferences node = preferences.node(common_frequencies_node_name); + + node.putInt(frequency_count, frequencies.length); + for (int i = 0; i < frequencies.length; i++) { + node.putDouble(String.format(frequency_format, i), frequencies[i].frequency); + node.put(String.format(description_format, i), frequencies[i].description); + } + } + public static int launcher_serial; + + public static int launcher_channel; + + public static void init() { + preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); + + /* Initialize logdir from preferences */ + String logdir_string = preferences.get(logdirPreference, null); + if (logdir_string != null) + logdir = new File(logdir_string); + else { + /* Use the file system view default directory */ + logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName); + if (!logdir.exists()) + logdir.mkdirs(); + } + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); + + frequencies = new Hashtable(); + + telemetries = new Hashtable(); + + voice = preferences.getBoolean(voicePreference, true); + + callsign = preferences.get(callsignPreference,"N0CALL"); + + scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << AltosLib.ao_telemetry_standard)); + + launcher_serial = preferences.getInt(launcherSerialPreference, 0); + + launcher_channel = preferences.getInt(launcherChannelPreference, 0); + + String firmwaredir_string = preferences.get(firmwaredirPreference, null); + if (firmwaredir_string != null) + firmwaredir = new File(firmwaredir_string); + else + firmwaredir = null; + + common_frequencies = load_common_frequencies(); + + } + + static { init(); } + + public static void flush_preferences() { + try { + preferences.flush(); + } catch (BackingStoreException ee) { +/* + if (component != null) + JOptionPane.showMessageDialog(component, + preferences.absolutePath(), + "Cannot save prefernces", + JOptionPane.ERROR_MESSAGE); + else +*/ + System.err.printf("Cannot save preferences\n"); + } + } + + public static void set_logdir(File new_logdir) { + logdir = new_logdir; + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); + synchronized (preferences) { + preferences.put(logdirPreference, logdir.getPath()); + flush_preferences(); + } + } + + public static File logdir() { + return logdir; + } + + public static File mapdir() { + return mapdir; + } + + public static void set_frequency(int serial, double new_frequency) { + frequencies.put(serial, new_frequency); + synchronized (preferences) { + preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); + flush_preferences(); + } + } + + public static double frequency(int serial) { + if (frequencies.containsKey(serial)) + return frequencies.get(serial); + double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); + if (frequency == 0.0) { + int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); + frequency = AltosConvert.radio_channel_to_frequency(channel); + } + frequencies.put(serial, frequency); + return frequency; + } + + public static void set_telemetry(int serial, int new_telemetry) { + telemetries.put(serial, new_telemetry); + synchronized (preferences) { + preferences.putInt(String.format(telemetryPreferenceFormat, serial), new_telemetry); + flush_preferences(); + } + } + + public static int telemetry(int serial) { + if (telemetries.containsKey(serial)) + return telemetries.get(serial); + int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), + AltosLib.ao_telemetry_standard); + telemetries.put(serial, telemetry); + return telemetry; + } + + public static void set_scanning_telemetry(int new_scanning_telemetry) { + scanning_telemetry = new_scanning_telemetry; + synchronized (preferences) { + preferences.putInt(scanningTelemetryPreference, scanning_telemetry); + flush_preferences(); + } + } + + public static int scanning_telemetry() { + return scanning_telemetry; + } + + public static void set_voice(boolean new_voice) { + voice = new_voice; + synchronized (preferences) { + preferences.putBoolean(voicePreference, voice); + flush_preferences(); + } + } + + public static boolean voice() { + return voice; + } + + public static void set_callsign(String new_callsign) { + callsign = new_callsign; + synchronized(preferences) { + preferences.put(callsignPreference, callsign); + flush_preferences(); + } + } + + public static String callsign() { + return callsign; + } + + public static void set_firmwaredir(File new_firmwaredir) { + firmwaredir = new_firmwaredir; + synchronized (preferences) { + preferences.put(firmwaredirPreference, firmwaredir.getPath()); + flush_preferences(); + } + } + + public static File firmwaredir() { + return firmwaredir; + } + + public static void set_launcher_serial(int new_launcher_serial) { + launcher_serial = new_launcher_serial; + System.out.printf("set launcher serial to %d\n", new_launcher_serial); + synchronized (preferences) { + preferences.putInt(launcherSerialPreference, launcher_serial); + flush_preferences(); + } + } + + public static int launcher_serial() { + return launcher_serial; + } + + public static void set_launcher_channel(int new_launcher_channel) { + launcher_channel = new_launcher_channel; + System.out.printf("set launcher channel to %d\n", new_launcher_channel); + synchronized (preferences) { + preferences.putInt(launcherChannelPreference, launcher_channel); + flush_preferences(); + } + } + + public static int launcher_channel() { + return launcher_channel; + } + + public static Preferences bt_devices() { + return preferences.node("bt_devices"); + } + + public static AltosFrequency[] common_frequencies() { + return common_frequencies; + } + + public static void set_common_frequencies(AltosFrequency[] frequencies) { + common_frequencies = frequencies; + synchronized(preferences) { + save_common_frequencies(frequencies); + flush_preferences(); + } + } + + public static void add_common_frequency(AltosFrequency frequency) { + AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; + int i; + + for (i = 0; i < common_frequencies.length; i++) { + if (frequency.frequency == common_frequencies[i].frequency) + return; + if (frequency.frequency < common_frequencies[i].frequency) + break; + new_frequencies[i] = common_frequencies[i]; + } + new_frequencies[i] = frequency; + for (; i < common_frequencies.length; i++) + new_frequencies[i+1] = common_frequencies[i]; + set_common_frequencies(new_frequencies); + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java index 120004a7..e4915af0 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java @@ -23,64 +23,66 @@ import java.util.HashMap; import java.io.*; public class AltosRecord implements Comparable { - final static int MISSING = 0x7fffffff; - - static final int seen_flight = 1; - static final int seen_sensor = 2; - static final int seen_temp_volt = 4; - static final int seen_deploy = 8; - static final int seen_gps_time = 16; - static final int seen_gps_lat = 32; - static final int seen_gps_lon = 64; - static final int seen_companion = 128; - int seen; - - int version; - String callsign; - int serial; - int flight; - int rssi; - int status; - int state; - int tick; - - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; - - int ground_accel; - int ground_pres; - int accel_plus_g; - int accel_minus_g; - - double acceleration; - double speed; - double height; - - int flight_accel; - int flight_vel; - int flight_pres; - - AltosGPS gps; - boolean new_gps; - - AltosIMU imu; - AltosMag mag; - - double time; /* seconds since boost */ - - int device_type; - int config_major; - int config_minor; - int apogee_delay; - int main_deploy; - int flight_log_max; - String firmware_version; - - AltosRecordCompanion companion; + public final static int MISSING = 0x7fffffff; + + public static final int seen_flight = 1; + public static final int seen_sensor = 2; + public static final int seen_temp_volt = 4; + public static final int seen_deploy = 8; + public static final int seen_gps_time = 16; + public static final int seen_gps_lat = 32; + public static final int seen_gps_lon = 64; + public static final int seen_companion = 128; + public int seen; + + public int version; + public String callsign; + public int serial; + public int flight; + public int rssi; + public int status; + public int state; + public int tick; + + public int accel; + public int pres; + public int temp; + public int batt; + public int drogue; + public int main; + + public int ground_accel; + public int ground_pres; + public int accel_plus_g; + public int accel_minus_g; + + public double acceleration; + public double speed; + public double height; + + public int flight_accel; + public int flight_vel; + public int flight_pres; + + public AltosGPS gps; + public boolean new_gps; + + public AltosIMU imu; + public AltosMag mag; + + public double time; /* seconds since boost */ + + public int device_type; + public int config_major; + public int config_minor; + public int apogee_delay; + public int main_deploy; + public int flight_log_max; + public String firmware_version; + + public AltosRecordCompanion companion; + +>>>>>>> 5a249bc... altosui: Complete split out of separate java library /* * Values for our MP3H6115A pressure sensor * @@ -95,10 +97,10 @@ public class AltosRecord implements Comparable { * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa */ - static final double counts_per_kPa = 27 * 2047 / 3300; - static final double counts_at_101_3kPa = 1674.0; + public static final double counts_per_kPa = 27 * 2047 / 3300; + public static final double counts_at_101_3kPa = 1674.0; - static double + public static double barometer_to_pressure(double count) { return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; @@ -193,7 +195,7 @@ public class AltosRecord implements Comparable { * = (value - 19791.268) / 32768 * 1.25 / 0.00247 */ - static double + public static double thermometer_to_temperature(double thermo) { return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; @@ -205,7 +207,7 @@ public class AltosRecord implements Comparable { return thermometer_to_temperature(temp); } - double accel_counts_per_mss() { + public double accel_counts_per_mss() { double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; return counts_per_g / 9.80665; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java index 4f8e80dc..c8cc6cac 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java @@ -18,14 +18,14 @@ package org.altusmetrum.AltosLib; public class AltosRecordCompanion { - final static int board_id_telescience = 0x0a; - final static int MAX_CHANNELS = 12; + public final static int board_id_telescience = 0x0a; + public final static int MAX_CHANNELS = 12; - int tick; - int board_id; - int update_period; - int channels; - int[] companion_data; + public int tick; + public int board_id; + public int update_period; + public int channels; + public int[] companion_data; public AltosRecordCompanion(int in_channels) { channels = in_channels; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java deleted file mode 100644 index bd94ee36..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; -import java.io.*; -import java.util.concurrent.*; - -class AltosTelemetryReader extends AltosFlightReader { - AltosDevice device; - AltosSerial serial; - AltosLog log; - AltosRecord previous; - double frequency; - int telemetry; - - LinkedBlockingQueue telem; - - AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { - AltosLine l = telem.take(); - if (l.line == null) - throw new IOException("IO error"); - AltosRecord next = AltosTelemetry.parse(l.line, previous); - previous = next; - return next; - } - - void flush() { - telem.clear(); - } - - void close(boolean interrupted) { - serial.remove_monitor(telem); - log.close(); - serial.close(); - } - - public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - serial.set_radio_frequency(frequency); - } - - public boolean supports_telemetry(int telemetry) { - - try { - /* Version 1.0 or later firmware supports all telemetry formats */ - if (serial.config_data().compare_version("1.0") >= 0) - return true; - - /* Version 0.9 firmware only supports 0.9 telemetry */ - if (serial.config_data().compare_version("0.9") >= 0) { - if (telemetry == Altos.ao_telemetry_0_9) - return true; - else - return false; - } - - /* Version 0.8 firmware only supports 0.8 telemetry */ - if (telemetry == Altos.ao_telemetry_0_8) - return true; - else - return false; - } catch (InterruptedException ie) { - return true; - } catch (TimeoutException te) { - return true; - } - } - - void save_frequency() { - AltosUIPreferences.set_frequency(device.getSerial(), frequency); - } - - void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - serial.set_telemetry(telemetry); - } - - void save_telemetry() { - AltosUIPreferences.set_telemetry(device.getSerial(), telemetry); - } - - File backing_file() { - return log.file(); - } - - public AltosTelemetryReader (AltosDevice in_device) - throws FileNotFoundException, AltosSerialInUseException, IOException, InterruptedException, TimeoutException { - device = in_device; - serial = new AltosSerial(device); - log = new AltosLog(serial); - name = device.toShortString(); - previous = null; - - telem = new LinkedBlockingQueue(); - frequency = AltosUIPreferences.frequency(device.getSerial()); - set_frequency(frequency); - telemetry = AltosUIPreferences.telemetry(device.getSerial()); - set_telemetry(telemetry); - serial.set_callsign(AltosUIPreferences.callsign()); - serial.add_monitor(telem); - } -} -- cgit v1.2.3 From ead8f1cfca2c454d18dce56479899f2b423d8bdd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 20:32:35 -0800 Subject: altosui: Add back in the split-out Altos constants as AltosLib These were pulled out of Altos.java, but not added back to git Signed-off-by: Keith Packard --- altosui/AltosConfigData.java | 191 ----------- .../org/altusmetrum/AltosLib/AltosConfigData.java | 191 +++++++++++ .../src/org/altusmetrum/AltosLib/AltosLib.java | 348 +++++++++++++++++++++ 3 files changed, 539 insertions(+), 191 deletions(-) delete mode 100644 altosui/AltosConfigData.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java (limited to 'altosui') diff --git a/altosui/AltosConfigData.java b/altosui/AltosConfigData.java deleted file mode 100644 index ef34dd3e..00000000 --- a/altosui/AltosConfigData.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -import libaltosJNI.*; - -public class AltosConfigData implements Iterable { - - /* Version information */ - String manufacturer; - String product; - String version; - int log_format; - int serial; - - /* Strings returned */ - LinkedList lines; - - /* Config information */ - int config_major; - int config_minor; - int main_deploy; - int apogee_delay; - int radio_channel; - int radio_setting; - int radio_frequency; - String callsign; - int accel_cal_plus, accel_cal_minus; - int radio_calibration; - int flight_log_max; - int ignite_mode; - int stored_flight; - int storage_size; - int storage_erase_unit; - - static String get_string(String line, String label) throws ParseException { - if (line.startsWith(label)) { - String quoted = line.substring(label.length()).trim(); - - if (quoted.startsWith("\"")) - quoted = quoted.substring(1); - if (quoted.endsWith("\"")) - quoted = quoted.substring(0,quoted.length()-1); - return quoted; - } - throw new ParseException("mismatch", 0); - } - - static int get_int(String line, String label) throws NumberFormatException, ParseException { - if (line.startsWith(label)) { - String tail = line.substring(label.length()).trim(); - String[] tokens = tail.split("\\s+"); - if (tokens.length > 0) - return Integer.parseInt(tokens[0]); - } - throw new ParseException("mismatch", 0); - } - - public Iterator iterator() { - return lines.iterator(); - } - - public int log_available() { - switch (log_format) { - case Altos.AO_LOG_FORMAT_TINY: - if (stored_flight == 0) - return 1; - return 0; - default: - if (flight_log_max <= 0) - return 1; - int log_space = storage_size - storage_erase_unit; - int log_used = stored_flight * flight_log_max; - - if (log_used >= log_space) - return 0; - return (log_space - log_used) / flight_log_max; - } - } - - int[] parse_version(String v) { - String[] parts = v.split("\\."); - int r[] = new int[parts.length]; - - for (int i = 0; i < parts.length; i++) { - try { - r[i] = Altos.fromdec(parts[i]); - } catch (NumberFormatException n) { - r[i] = 0; - } - } - - return r; - } - - public int compare_version(String other) { - int[] me = parse_version(version); - int[] them = parse_version(other); - - int l = Math.min(me.length, them.length); - - for (int i = 0; i < l; i++) { - int d = me[i] - them[i]; - if (d != 0) - return d; - } - if (me.length > l) - return 1; - if (them.length > l) - return -1; - return 0; - } - - public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { - serial_line.printf("c s\np\nf\nl\nv\n"); - lines = new LinkedList(); - radio_setting = 0; - radio_frequency = 0; - stored_flight = 0; - for (;;) { - String line = serial_line.get_reply(); - if (line == null) - throw new TimeoutException(); - if (line.contains("Syntax error")) - continue; - lines.add(line); - try { serial = get_int(line, "serial-number"); } catch (Exception e) {} - try { log_format = get_int(line, "log-format"); } catch (Exception e) {} - try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} - try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} - try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} - try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} - try { - radio_frequency = get_int(line, "Frequency:"); - if (radio_frequency < 0) - radio_frequency = 434550; - } catch (Exception e) {} - try { - if (line.startsWith("Accel cal")) { - String[] bits = line.split("\\s+"); - if (bits.length >= 6) { - accel_cal_plus = Integer.parseInt(bits[3]); - accel_cal_minus = Integer.parseInt(bits[5]); - } - } - } catch (Exception e) {} - try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} - try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} - try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} - try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} - try { version = get_string(line,"software-version"); } catch (Exception e) {} - try { product = get_string(line,"product"); } catch (Exception e) {} - - try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} - try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} - try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} - - /* signals the end of the version info */ - if (line.startsWith("software-version")) - break; - } - } - -} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java new file mode 100644 index 00000000..ef34dd3e --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java @@ -0,0 +1,191 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; + +import libaltosJNI.*; + +public class AltosConfigData implements Iterable { + + /* Version information */ + String manufacturer; + String product; + String version; + int log_format; + int serial; + + /* Strings returned */ + LinkedList lines; + + /* Config information */ + int config_major; + int config_minor; + int main_deploy; + int apogee_delay; + int radio_channel; + int radio_setting; + int radio_frequency; + String callsign; + int accel_cal_plus, accel_cal_minus; + int radio_calibration; + int flight_log_max; + int ignite_mode; + int stored_flight; + int storage_size; + int storage_erase_unit; + + static String get_string(String line, String label) throws ParseException { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + return quoted; + } + throw new ParseException("mismatch", 0); + } + + static int get_int(String line, String label) throws NumberFormatException, ParseException { + if (line.startsWith(label)) { + String tail = line.substring(label.length()).trim(); + String[] tokens = tail.split("\\s+"); + if (tokens.length > 0) + return Integer.parseInt(tokens[0]); + } + throw new ParseException("mismatch", 0); + } + + public Iterator iterator() { + return lines.iterator(); + } + + public int log_available() { + switch (log_format) { + case Altos.AO_LOG_FORMAT_TINY: + if (stored_flight == 0) + return 1; + return 0; + default: + if (flight_log_max <= 0) + return 1; + int log_space = storage_size - storage_erase_unit; + int log_used = stored_flight * flight_log_max; + + if (log_used >= log_space) + return 0; + return (log_space - log_used) / flight_log_max; + } + } + + int[] parse_version(String v) { + String[] parts = v.split("\\."); + int r[] = new int[parts.length]; + + for (int i = 0; i < parts.length; i++) { + try { + r[i] = Altos.fromdec(parts[i]); + } catch (NumberFormatException n) { + r[i] = 0; + } + } + + return r; + } + + public int compare_version(String other) { + int[] me = parse_version(version); + int[] them = parse_version(other); + + int l = Math.min(me.length, them.length); + + for (int i = 0; i < l; i++) { + int d = me[i] - them[i]; + if (d != 0) + return d; + } + if (me.length > l) + return 1; + if (them.length > l) + return -1; + return 0; + } + + public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { + serial_line.printf("c s\np\nf\nl\nv\n"); + lines = new LinkedList(); + radio_setting = 0; + radio_frequency = 0; + stored_flight = 0; + for (;;) { + String line = serial_line.get_reply(); + if (line == null) + throw new TimeoutException(); + if (line.contains("Syntax error")) + continue; + lines.add(line); + try { serial = get_int(line, "serial-number"); } catch (Exception e) {} + try { log_format = get_int(line, "log-format"); } catch (Exception e) {} + try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} + try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} + try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} + try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} + try { + radio_frequency = get_int(line, "Frequency:"); + if (radio_frequency < 0) + radio_frequency = 434550; + } catch (Exception e) {} + try { + if (line.startsWith("Accel cal")) { + String[] bits = line.split("\\s+"); + if (bits.length >= 6) { + accel_cal_plus = Integer.parseInt(bits[3]); + accel_cal_minus = Integer.parseInt(bits[5]); + } + } + } catch (Exception e) {} + try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} + try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} + try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} + try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} + try { version = get_string(line,"software-version"); } catch (Exception e) {} + try { product = get_string(line,"product"); } catch (Exception e) {} + + try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} + try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} + try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} + + /* signals the end of the version info */ + if (line.startsWith("software-version")) + break; + } + } + +} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java new file mode 100644 index 00000000..2921d040 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java @@ -0,0 +1,348 @@ +/* + * 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.AltosLib; + +import java.awt.*; +import java.util.*; +import java.text.*; +import java.nio.charset.Charset; + +public class AltosLib { + /* EEProm command letters */ + public static final int AO_LOG_FLIGHT = 'F'; + public static final int AO_LOG_SENSOR = 'A'; + public static final int AO_LOG_TEMP_VOLT = 'T'; + public static final int AO_LOG_DEPLOY = 'D'; + public static final int AO_LOG_STATE = 'S'; + public static final int AO_LOG_GPS_TIME = 'G'; + public static final int AO_LOG_GPS_LAT = 'N'; + public static final int AO_LOG_GPS_LON = 'W'; + public static final int AO_LOG_GPS_ALT = 'H'; + public static final int AO_LOG_GPS_SAT = 'V'; + public static final int AO_LOG_GPS_DATE = 'Y'; + public static final int AO_LOG_PRESSURE = 'P'; + + /* Added for header fields in eeprom files */ + public static final int AO_LOG_CONFIG_VERSION = 1000; + public static final int AO_LOG_MAIN_DEPLOY = 1001; + public static final int AO_LOG_APOGEE_DELAY = 1002; + public static final int AO_LOG_RADIO_CHANNEL = 1003; + public static final int AO_LOG_CALLSIGN = 1004; + public static final int AO_LOG_ACCEL_CAL = 1005; + public static final int AO_LOG_RADIO_CAL = 1006; + public static final int AO_LOG_MAX_FLIGHT_LOG = 1007; + public static final int AO_LOG_MANUFACTURER = 2000; + public static final int AO_LOG_PRODUCT = 2001; + public static final int AO_LOG_SERIAL_NUMBER = 2002; + public static final int AO_LOG_LOG_FORMAT = 2003; + public static final int AO_LOG_SOFTWARE_VERSION = 9999; + + /* Added to flag invalid records */ + public static final int AO_LOG_INVALID = -1; + + /* Flight state numbers and names */ + public static final int ao_flight_startup = 0; + public static final int ao_flight_idle = 1; + public static final int ao_flight_pad = 2; + public static final int ao_flight_boost = 3; + public static final int ao_flight_fast = 4; + public static final int ao_flight_coast = 5; + public static final int ao_flight_drogue = 6; + public static final int ao_flight_main = 7; + public static final int ao_flight_landed = 8; + public static final int ao_flight_invalid = 9; + + /* Telemetry modes */ + public static final int ao_telemetry_off = 0; + public static final int ao_telemetry_min = 1; + public static final int ao_telemetry_standard = 1; + public static final int ao_telemetry_0_9 = 2; + public static final int ao_telemetry_0_8 = 3; + public static final int ao_telemetry_max = 3; + + public static final String[] ao_telemetry_name = { + "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" + }; + + public static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; + + public static final int ao_telemetry_standard_len = 32; + public static final int ao_telemetry_0_9_len = 95; + public static final int ao_telemetry_0_8_len = 94; + + public static final int[] ao_telemetry_len = { + 0, 32, 95, 94 + }; + + public static HashMap string_to_state = new HashMap(); + + public static boolean map_initialized = false; + + public static void initialize_map() + { + string_to_state.put("startup", ao_flight_startup); + string_to_state.put("idle", ao_flight_idle); + string_to_state.put("pad", ao_flight_pad); + string_to_state.put("boost", ao_flight_boost); + string_to_state.put("fast", ao_flight_fast); + string_to_state.put("coast", ao_flight_coast); + string_to_state.put("drogue", ao_flight_drogue); + string_to_state.put("apogee", ao_flight_coast); + string_to_state.put("main", ao_flight_main); + string_to_state.put("landed", ao_flight_landed); + string_to_state.put("invalid", ao_flight_invalid); + map_initialized = true; + } + + public static int telemetry_len(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_len[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + public static String telemetry_name(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_name[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + public static String[] state_to_string = { + "startup", + "idle", + "pad", + "boost", + "fast", + "coast", + "drogue", + "main", + "landed", + "invalid", + }; + + public static String[] state_to_string_capital = { + "Startup", + "Idle", + "Pad", + "Boost", + "Fast", + "Coast", + "Drogue", + "Main", + "Landed", + "Invalid", + }; + + public static int state(String state) { + if (!map_initialized) + initialize_map(); + if (string_to_state.containsKey(state)) + return string_to_state.get(state); + return ao_flight_invalid; + } + + public static String state_name(int state) { + if (state < 0 || state_to_string.length <= state) + return "invalid"; + return state_to_string[state]; + } + + public static final int AO_GPS_VALID = (1 << 4); + public static final int AO_GPS_RUNNING = (1 << 5); + public static final int AO_GPS_DATE_VALID = (1 << 6); + public static final int AO_GPS_NUM_SAT_SHIFT = 0; + public static final int AO_GPS_NUM_SAT_MASK = 0xf; + + public static final int AO_LOG_FORMAT_UNKNOWN = 0; + public static final int AO_LOG_FORMAT_FULL = 1; + public static final int AO_LOG_FORMAT_TINY = 2; + public static final int AO_LOG_FORMAT_TELEMETRY = 3; + public static final int AO_LOG_FORMAT_TELESCIENCE = 4; + public static final int AO_LOG_FORMAT_NONE = 127; + + public static boolean isspace(int c) { + switch (c) { + case ' ': + case '\t': + return true; + } + return false; + } + + public static boolean ishex(int c) { + if ('0' <= c && c <= '9') + return true; + if ('a' <= c && c <= 'f') + return true; + if ('A' <= c && c <= 'F') + return true; + return false; + } + + public static boolean ishex(String s) { + for (int i = 0; i < s.length(); i++) + if (!ishex(s.charAt(i))) + return false; + return true; + } + + public static int fromhex(int c) { + 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; + return -1; + } + + public static int fromhex(String s) throws NumberFormatException { + int c, v = 0; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (!ishex(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + return v; + } + v = v * 16 + fromhex(c); + } + return v; + } + + public static boolean isdec(int c) { + if ('0' <= c && c <= '9') + return true; + return false; + } + + public static boolean isdec(String s) { + for (int i = 0; i < s.length(); i++) + if (!isdec(s.charAt(i))) + return false; + return true; + } + + public static int fromdec(int c) { + if ('0' <= c && c <= '9') + return c - '0'; + return -1; + } + + public static int int8(int[] bytes, int i) { + return (int) (byte) bytes[i]; + } + + public static int uint8(int[] bytes, int i) { + return bytes[i]; + } + + public static int int16(int[] bytes, int i) { + return (int) (short) (bytes[i] + (bytes[i+1] << 8)); + } + + public static int uint16(int[] bytes, int i) { + return bytes[i] + (bytes[i+1] << 8); + } + + public static int uint32(int[] bytes, int i) { + return bytes[i] + + (bytes[i+1] << 8) + + (bytes[i+2] << 16) + + (bytes[i+3] << 24); + } + + public static final Charset unicode_set = Charset.forName("UTF-8"); + + public static String string(int[] bytes, int s, int l) { + if (s + l > bytes.length) { + if (s > bytes.length) { + s = bytes.length; + l = 0; + } else { + l = bytes.length - s; + } + } + + int i; + for (i = l - 1; i >= 0; i--) + if (bytes[s+i] != 0) + break; + + l = i + 1; + byte[] b = new byte[l]; + + for (i = 0; i < l; i++) + b[i] = (byte) bytes[s+i]; + String n = new String(b, unicode_set); + return n; + } + + public static int hexbyte(String s, int i) { + int c0, c1; + + if (s.length() < i + 2) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + c0 = s.charAt(i); + if (!ishex(c0)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); + c1 = s.charAt(i+1); + if (!ishex(c1)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); + return fromhex(c0) * 16 + fromhex(c1); + } + + public static int[] hexbytes(String s) { + int n; + int[] r; + int i; + + if ((s.length() & 1) != 0) + throw new NumberFormatException(String.format("invalid line \"%s\"", s)); + n = s.length() / 2; + r = new int[n]; + for (i = 0; i < n; i++) + r[i] = hexbyte(s, i * 2); + return r; + } + + public static int fromdec(String s) throws NumberFormatException { + int c, v = 0; + int sign = 1; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (i == 0 && c == '-') { + sign = -1; + } else if (!isdec(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid number \"%s\"", s)); + return v; + } else + v = v * 10 + fromdec(c); + } + return v * sign; + } + + public static String replace_extension(String input, String extension) { + int dot = input.lastIndexOf("."); + if (dot > 0) + input = input.substring(0,dot); + return input.concat(extension); + } +} -- cgit v1.2.3 From 4c88b0ca96758b663c82395e63b338043d1c1a10 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 20:34:38 -0800 Subject: altosui: Move AltosConfigData.java to library Create a new 'AltosLink' which exposes how to talk to the remote device abstractly via 'get_reply' and 'printf' methods. Signed-off-by: Keith Packard --- altosui/AltosSerial.java | 2 +- altosui/altoslib/Makefile.am | 2 ++ .../org/altusmetrum/AltosLib/AltosConfigData.java | 13 +++-------- .../src/org/altusmetrum/AltosLib/AltosLink.java | 26 ++++++++++++++++++++++ 4 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java (limited to 'altosui') diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 74e945f3..161f0e90 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -41,7 +41,7 @@ import libaltosJNI.*; * threads. */ -public class AltosSerial implements Runnable { +public class AltosSerial implements Runnable, AltosLink { static java.util.List devices_opened = Collections.synchronizedList(new LinkedList()); diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index 967c8d06..cbf716b0 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -11,12 +11,14 @@ AltosLibdir = $(datadir)/java AltosLib_JAVA = \ $(SRC)/AltosLib.java \ + $(SRC)/AltosConfigData.java \ $(SRC)/AltosConvert.java \ $(SRC)/AltosCRCException.java \ $(SRC)/AltosFrequency.java \ $(SRC)/AltosGPS.java \ $(SRC)/AltosGPSSat.java \ $(SRC)/AltosLine.java \ + $(SRC)/AltosLink.java \ $(SRC)/AltosParse.java \ $(SRC)/AltosPreferences.java \ $(SRC)/AltosRecordCompanion.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java index ef34dd3e..0bc5d5a8 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java @@ -17,11 +17,6 @@ package altosui; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; import java.io.*; import java.util.*; import java.text.*; @@ -29,8 +24,6 @@ import java.util.prefs.*; import java.util.concurrent.*; import org.altusmetrum.AltosLib.*; -import libaltosJNI.*; - public class AltosConfigData implements Iterable { /* Version information */ @@ -138,14 +131,14 @@ public class AltosConfigData implements Iterable { return 0; } - public AltosConfigData(AltosSerial serial_line) throws InterruptedException, TimeoutException { - serial_line.printf("c s\np\nf\nl\nv\n"); + public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("c s\np\nf\nl\nv\n"); lines = new LinkedList(); radio_setting = 0; radio_frequency = 0; stored_flight = 0; for (;;) { - String line = serial_line.get_reply(); + String line = link.get_reply(); if (line == null) throw new TimeoutException(); if (line.contains("Syntax error")) diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java new file mode 100644 index 00000000..80f3d712 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java @@ -0,0 +1,26 @@ +/* + * 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.AltosLib; + +public interface AltosLink { + public void printf(String format, Object ... arguments) throws InterruptedException; + + public String get_reply() throws InterruptedException; + + public String get_reply(int timeout) throws InterruptedException; +} -- cgit v1.2.3 From b273b8b298540b1a6d0a87b1cf61df1fbf62e013 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 20:39:16 -0800 Subject: altosui: Finish moving AltosConfigData to altoslib Signed-off-by: Keith Packard --- altosui/Makefile.am | 1 - altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index cfe45302..4005d16d 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -22,7 +22,6 @@ altosui_JAVA = \ AltosChannelMenu.java \ AltosCompanionInfo.java \ AltosConfig.java \ - AltosConfigData.java \ AltosConfigFreqUI.java \ AltosConfigUI.java \ AltosConfigureUI.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java index 0bc5d5a8..fec1a042 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package org.altusmetrum.AltosLib; import java.io.*; import java.util.*; @@ -82,7 +82,7 @@ public class AltosConfigData implements Iterable { public int log_available() { switch (log_format) { - case Altos.AO_LOG_FORMAT_TINY: + case AltosLib.AO_LOG_FORMAT_TINY: if (stored_flight == 0) return 1; return 0; -- cgit v1.2.3 From 89aa06cfdcb02de1894ccb01aed97782f9eec9b2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 20:47:16 -0800 Subject: altosui: Move AltosEepromChunk.java to lib Also fixes install issues with split lib Signed-off-by: Keith Packard --- altosui/AltosEepromChunk.java | 103 --------------------- altosui/Makefile.am | 3 +- altosui/altoslib/Makefile.am | 11 +-- .../org/altusmetrum/AltosLib/AltosEepromChunk.java | 102 ++++++++++++++++++++ .../src/org/altusmetrum/AltosLib/AltosLink.java | 2 + 5 files changed, 110 insertions(+), 111 deletions(-) delete mode 100644 altosui/AltosEepromChunk.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java (limited to 'altosui') diff --git a/altosui/AltosEepromChunk.java b/altosui/AltosEepromChunk.java deleted file mode 100644 index e4d11658..00000000 --- a/altosui/AltosEepromChunk.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 altosui; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -public class AltosEepromChunk { - - static final int chunk_size = 256; - static final int per_line = 8; - - public int data[]; - public int address; - public ParseException parse_exception = null; - - int[] ParseHex(String line) { - String[] tokens = line.split("\\s+"); - int[] array = new int[tokens.length]; - - for (int i = 0; i < tokens.length; i++) - try { - array[i] = Integer.parseInt(tokens[i], 16); - } catch (NumberFormatException ne) { - return null; - } - return array; - } - - int data(int offset) { - return data[offset]; - } - - int data16(int offset) { - return data[offset] | (data[offset + 1] << 8); - } - - int data32(int offset) { - return data[offset] | (data[offset + 1] << 8) | - (data[offset+2] << 16) | (data[offset+3] << 24); - } - - boolean erased(int start, int len) { - for (int i = 0; i < len; i++) - if (data[start+i] != 0xff) - return false; - return true; - } - - public AltosEepromChunk(AltosSerial serial_line, int block, boolean flush) - throws TimeoutException, InterruptedException { - - int offset; - - data = new int[chunk_size]; - address = block * chunk_size; - if (flush) - serial_line.flush_input(); - serial_line.printf("e %x\n", block); - - for (offset = 0; offset < chunk_size; offset += per_line) { - try { - String line = serial_line.get_reply(5000); - - if (line == null) - throw new TimeoutException(); - - int[] values = ParseHex(line); - - if (values == null || values.length != per_line + 1) - throw new ParseException(String.format("invalid line %s", line), 0); - if (values[0] != offset) - throw new ParseException(String.format("data address out of sync at 0x%x", - address + offset), 0); - for (int i = 0; i < per_line; i++) - data[offset + i] = values[1 + i]; - } catch (ParseException pe) { - for (int i = 0; i < per_line; i++) - data[offset + i] = 0xff; - if (parse_exception == null) - parse_exception = pe; - } - } - } -} \ No newline at end of file diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 4005d16d..01732749 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -37,7 +37,6 @@ altosui_JAVA = \ AltosDevice.java \ AltosUSBDevice.java \ AltosDisplayThread.java \ - AltosEepromChunk.java \ AltosEepromDelete.java \ AltosEepromDownload.java \ AltosEepromList.java \ @@ -265,7 +264,7 @@ altosui: Makefile altosui-test: Makefile echo "#!/bin/sh" > $@ - echo 'exec java -cp ":altoslib/*:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@ + echo 'exec java -cp "./*:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@ chmod +x $@ altosui-jdb: Makefile diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index cbf716b0..cce9b4c4 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -14,6 +14,7 @@ AltosLib_JAVA = \ $(SRC)/AltosConfigData.java \ $(SRC)/AltosConvert.java \ $(SRC)/AltosCRCException.java \ + $(SRC)/AltosEepromChunk.java \ $(SRC)/AltosFrequency.java \ $(SRC)/AltosGPS.java \ $(SRC)/AltosGPSSat.java \ @@ -44,13 +45,11 @@ all-local: $(JAR) clean-local: -rm -rf bin $(JAR) -altosuidir=$(datadir)/java - -install-altosuiJAVA: $(JAR) +install-AltosLibJAVA: $(JAR) @$(NORMAL_INSTALL) - test -z "$(altosuidir)" || $(MKDIR_P) "$(DESTDIR)$(altosuidir)" - echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/$(JAR)"; \ - $(INSTALL_DATA) "$<" "$(DESTDIR)$(altosuidir)" + test -z "$(AltosLibdir)" || $(MKDIR_P) "$(DESTDIR)$(AltosLibdir)" + echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(AltosLibdir)/$(JAR)"; \ + $(INSTALL_DATA) "$<" "$(DESTDIR)$(AltosLibdir)" bin: mkdir -p bin diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java new file mode 100644 index 00000000..4a9a2679 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java @@ -0,0 +1,102 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +public class AltosEepromChunk { + + static final int chunk_size = 256; + static final int per_line = 8; + + public int data[]; + public int address; + public ParseException parse_exception = null; + + int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + int data(int offset) { + return data[offset]; + } + + int data16(int offset) { + return data[offset] | (data[offset + 1] << 8); + } + + int data32(int offset) { + return data[offset] | (data[offset + 1] << 8) | + (data[offset+2] << 16) | (data[offset+3] << 24); + } + + boolean erased(int start, int len) { + for (int i = 0; i < len; i++) + if (data[start+i] != 0xff) + return false; + return true; + } + + public AltosEepromChunk(AltosLink link, int block, boolean flush) + throws TimeoutException, InterruptedException { + + int offset; + + data = new int[chunk_size]; + address = block * chunk_size; + if (flush) + link.flush_input(); + link.printf("e %x\n", block); + + for (offset = 0; offset < chunk_size; offset += per_line) { + try { + String line = link.get_reply(5000); + + if (line == null) + throw new TimeoutException(); + + int[] values = ParseHex(line); + + if (values == null || values.length != per_line + 1) + throw new ParseException(String.format("invalid line %s", line), 0); + if (values[0] != offset) + throw new ParseException(String.format("data address out of sync at 0x%x", + address + offset), 0); + for (int i = 0; i < per_line; i++) + data[offset + i] = values[1 + i]; + } catch (ParseException pe) { + for (int i = 0; i < per_line; i++) + data[offset + i] = 0xff; + if (parse_exception == null) + parse_exception = pe; + } + } + } +} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java index 80f3d712..9a23b306 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java @@ -23,4 +23,6 @@ public interface AltosLink { public String get_reply() throws InterruptedException; public String get_reply(int timeout) throws InterruptedException; + + public void flush_input() throws InterruptedException; } -- cgit v1.2.3 From a4ccdd253a9873c16f194a63a79f0c26feaafa29 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 20:57:57 -0800 Subject: altosui: Move eeprom managment code to library Signed-off-by: Keith Packard --- altosui/AltosEepromIterable.java | 481 --------------------- altosui/AltosEepromRecord.java | 147 ------- altosui/Makefile.am | 2 - altosui/altoslib/Makefile.am | 2 + .../altusmetrum/AltosLib/AltosEepromIterable.java | 475 ++++++++++++++++++++ .../altusmetrum/AltosLib/AltosEepromRecord.java | 139 ++++++ 6 files changed, 616 insertions(+), 630 deletions(-) delete mode 100644 altosui/AltosEepromIterable.java delete mode 100644 altosui/AltosEepromRecord.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java (limited to 'altosui') diff --git a/altosui/AltosEepromIterable.java b/altosui/AltosEepromIterable.java deleted file mode 100644 index 11cb97e4..00000000 --- a/altosui/AltosEepromIterable.java +++ /dev/null @@ -1,481 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; -import org.altusmetrum.AltosLib.*; - -/* - * AltosRecords with an index field so they can be sorted by tick while preserving - * the original ordering for elements with matching ticks - */ -class AltosOrderedRecord extends AltosEepromRecord implements Comparable { - - public int index; - - public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) - throws ParseException { - super(line); - if (prev_tick_valid) { - tick |= (prev_tick & ~0xffff); - if (tick < prev_tick) { - if (prev_tick - tick > 0x8000) - tick += 0x10000; - } else { - if (tick - prev_tick > 0x8000) - tick -= 0x10000; - } - } - index = in_index; - } - - public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { - super(in_cmd, in_tick, in_a, in_b); - index = in_index; - } - - public String toString() { - return String.format("%d.%d %04x %04x %04x", - cmd, index, tick, a, b); - } - - public int compareTo(AltosOrderedRecord o) { - int tick_diff = tick - o.tick; - if (tick_diff != 0) - return tick_diff; - return index - o.index; - } -} - -public class AltosEepromIterable extends AltosRecordIterable { - - static final int seen_flight = 1; - static final int seen_sensor = 2; - static final int seen_temp_volt = 4; - static final int seen_deploy = 8; - static final int seen_gps_time = 16; - static final int seen_gps_lat = 32; - static final int seen_gps_lon = 64; - - static final int seen_basic = seen_flight|seen_sensor; - - boolean has_accel; - boolean has_gps; - boolean has_ignite; - - AltosEepromRecord flight_record; - AltosEepromRecord gps_date_record; - - TreeSet records; - - LinkedList list; - - class EepromState { - int seen; - int n_pad_samples; - double ground_pres; - int gps_tick; - int boost_tick; - int sensor_tick; - - EepromState() { - seen = 0; - n_pad_samples = 0; - ground_pres = 0.0; - gps_tick = 0; - } - } - - void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { - state.tick = record.tick; - switch (record.cmd) { - case Altos.AO_LOG_FLIGHT: - eeprom.seen |= seen_flight; - state.ground_accel = record.a; - state.flight_accel = record.a; - state.flight = record.b; - eeprom.boost_tick = record.tick; - break; - case Altos.AO_LOG_SENSOR: - state.accel = record.a; - state.pres = record.b; - if (state.state < Altos.ao_flight_boost) { - eeprom.n_pad_samples++; - eeprom.ground_pres += state.pres; - state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); - state.flight_pres = state.ground_pres; - } else { - state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; - } - state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; - if ((eeprom.seen & seen_sensor) == 0) - eeprom.sensor_tick = record.tick - 1; - state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick); - eeprom.seen |= seen_sensor; - eeprom.sensor_tick = record.tick; - has_accel = true; - break; - case Altos.AO_LOG_PRESSURE: - state.pres = record.b; - state.flight_pres = state.pres; - if (eeprom.n_pad_samples == 0) { - eeprom.n_pad_samples++; - state.ground_pres = state.pres; - } - eeprom.seen |= seen_sensor; - break; - case Altos.AO_LOG_TEMP_VOLT: - state.temp = record.a; - state.batt = record.b; - eeprom.seen |= seen_temp_volt; - break; - case Altos.AO_LOG_DEPLOY: - state.drogue = record.a; - state.main = record.b; - eeprom.seen |= seen_deploy; - has_ignite = true; - break; - case Altos.AO_LOG_STATE: - state.state = record.a; - break; - case Altos.AO_LOG_GPS_TIME: - eeprom.gps_tick = state.tick; - AltosGPS old = state.gps; - state.gps = new AltosGPS(); - - /* GPS date doesn't get repeated through the file */ - if (old != null) { - state.gps.year = old.year; - state.gps.month = old.month; - state.gps.day = old.day; - } - state.gps.hour = (record.a & 0xff); - state.gps.minute = (record.a >> 8); - state.gps.second = (record.b & 0xff); - - int flags = (record.b >> 8); - state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0; - state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0; - state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >> - Altos.AO_GPS_NUM_SAT_SHIFT; - state.new_gps = true; - has_gps = true; - break; - case Altos.AO_LOG_GPS_LAT: - int lat32 = record.a | (record.b << 16); - state.gps.lat = (double) lat32 / 1e7; - break; - case Altos.AO_LOG_GPS_LON: - int lon32 = record.a | (record.b << 16); - state.gps.lon = (double) lon32 / 1e7; - break; - case Altos.AO_LOG_GPS_ALT: - state.gps.alt = record.a; - break; - case Altos.AO_LOG_GPS_SAT: - if (state.tick == eeprom.gps_tick) { - int svid = record.a; - int c_n0 = record.b >> 8; - state.gps.add_sat(svid, c_n0); - } - break; - case Altos.AO_LOG_GPS_DATE: - state.gps.year = (record.a & 0xff) + 2000; - state.gps.month = record.a >> 8; - state.gps.day = record.b & 0xff; - break; - - case Altos.AO_LOG_CONFIG_VERSION: - break; - case Altos.AO_LOG_MAIN_DEPLOY: - break; - case Altos.AO_LOG_APOGEE_DELAY: - break; - case Altos.AO_LOG_RADIO_CHANNEL: - break; - case Altos.AO_LOG_CALLSIGN: - state.callsign = record.data; - break; - case Altos.AO_LOG_ACCEL_CAL: - state.accel_plus_g = record.a; - state.accel_minus_g = record.b; - break; - case Altos.AO_LOG_RADIO_CAL: - break; - case Altos.AO_LOG_MANUFACTURER: - break; - case Altos.AO_LOG_PRODUCT: - break; - case Altos.AO_LOG_SERIAL_NUMBER: - state.serial = record.a; - break; - case Altos.AO_LOG_SOFTWARE_VERSION: - break; - } - state.seen |= eeprom.seen; - } - - LinkedList make_list() { - LinkedList list = new LinkedList(); - Iterator iterator = records.iterator(); - AltosOrderedRecord record = null; - AltosRecord state = new AltosRecord(); - boolean last_reported = false; - EepromState eeprom = new EepromState(); - - state.state = Altos.ao_flight_pad; - state.accel_plus_g = 15758; - state.accel_minus_g = 16294; - - /* Pull in static data from the flight and gps_date records */ - if (flight_record != null) - update_state(state, flight_record, eeprom); - if (gps_date_record != null) - update_state(state, gps_date_record, eeprom); - - while (iterator.hasNext()) { - record = iterator.next(); - if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - } - update_state(state, record, eeprom); - } - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - return list; - } - - public Iterator iterator() { - if (list == null) - list = make_list(); - return list.iterator(); - } - - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; } - - public void write_comments(PrintStream out) { - Iterator iterator = records.iterator(); - out.printf("# Comments\n"); - while (iterator.hasNext()) { - AltosOrderedRecord record = iterator.next(); - switch (record.cmd) { - case Altos.AO_LOG_CONFIG_VERSION: - out.printf("# Config version: %s\n", record.data); - break; - case Altos.AO_LOG_MAIN_DEPLOY: - out.printf("# Main deploy: %s\n", record.a); - break; - case Altos.AO_LOG_APOGEE_DELAY: - out.printf("# Apogee delay: %s\n", record.a); - break; - case Altos.AO_LOG_RADIO_CHANNEL: - out.printf("# Radio channel: %s\n", record.a); - break; - case Altos.AO_LOG_CALLSIGN: - out.printf("# Callsign: %s\n", record.data); - break; - case Altos.AO_LOG_ACCEL_CAL: - out.printf ("# Accel cal: %d %d\n", record.a, record.b); - break; - case Altos.AO_LOG_RADIO_CAL: - out.printf ("# Radio cal: %d\n", record.a); - break; - case Altos.AO_LOG_MAX_FLIGHT_LOG: - out.printf ("# Max flight log: %d\n", record.a); - break; - case Altos.AO_LOG_MANUFACTURER: - out.printf ("# Manufacturer: %s\n", record.data); - break; - case Altos.AO_LOG_PRODUCT: - out.printf ("# Product: %s\n", record.data); - break; - case Altos.AO_LOG_SERIAL_NUMBER: - out.printf ("# Serial number: %d\n", record.a); - break; - case Altos.AO_LOG_SOFTWARE_VERSION: - out.printf ("# Software version: %s\n", record.data); - break; - case Altos.AO_LOG_BARO_RESERVED: - out.printf ("# Baro reserved: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_SENS: - out.printf ("# Baro sens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_OFF: - out.printf ("# Baro off: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCS: - out.printf ("# Baro tcs: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCO: - out.printf ("# Baro tco: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TREF: - out.printf ("# Baro tref: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TEMPSENS: - out.printf ("# Baro tempsens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_CRC: - out.printf ("# Baro crc: %d\n", record.a); - break; - } - } - } - - /* - * Given an AO_LOG_GPS_TIME record with correct time, and one - * missing time, rewrite the missing time values with the good - * ones, assuming that the difference between them is 'diff' seconds - */ - void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { - - int diff = (bad.tick - good.tick + 50) / 100; - - int hour = (good.a & 0xff); - int minute = (good.a >> 8); - int second = (good.b & 0xff); - int flags = (good.b >> 8); - int seconds = hour * 3600 + minute * 60 + second; - - /* Make sure this looks like a good GPS value */ - if ((flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT < 4) - flags = (flags & ~Altos.AO_GPS_NUM_SAT_MASK) | (4 << Altos.AO_GPS_NUM_SAT_SHIFT); - flags |= Altos.AO_GPS_RUNNING; - flags |= Altos.AO_GPS_VALID; - - int new_seconds = seconds + diff; - if (new_seconds < 0) - new_seconds += 24 * 3600; - int new_second = (new_seconds % 60); - int new_minutes = (new_seconds / 60); - int new_minute = (new_minutes % 60); - int new_hours = (new_minutes / 60); - int new_hour = (new_hours % 24); - - bad.a = new_hour + (new_minute << 8); - bad.b = new_second + (flags << 8); - } - - /* - * Read the whole file, dumping records into a RB tree so - * we can enumerate them in time order -- the eeprom data - * are sometimes out of order with GPS data getting timestamps - * matching the first packet out of the GPS unit but not - * written until the final GPS packet has been received. - */ - public AltosEepromIterable (FileInputStream input) { - records = new TreeSet(); - - AltosOrderedRecord last_gps_time = null; - - int index = 0; - int prev_tick = 0; - boolean prev_tick_valid = false; - boolean missing_time = false; - - try { - for (;;) { - String line = AltosRecord.gets(input); - if (line == null) - break; - AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); - if (record == null) - break; - if (record.cmd == Altos.AO_LOG_INVALID) - continue; - prev_tick = record.tick; - if (record.cmd < Altos.AO_LOG_CONFIG_VERSION) - prev_tick_valid = true; - if (record.cmd == Altos.AO_LOG_FLIGHT) { - flight_record = record; - continue; - } - - /* Two firmware bugs caused the loss of some GPS data. - * The flight date would never be recorded, and often - * the flight time would get overwritten by another - * record. Detect the loss of the GPS date and fix up the - * missing time records - */ - if (record.cmd == Altos.AO_LOG_GPS_DATE) { - gps_date_record = record; - continue; - } - - /* go back and fix up any missing time values */ - if (record.cmd == Altos.AO_LOG_GPS_TIME) { - last_gps_time = record; - if (missing_time) { - Iterator iterator = records.iterator(); - while (iterator.hasNext()) { - AltosOrderedRecord old = iterator.next(); - if (old.cmd == Altos.AO_LOG_GPS_TIME && - old.a == -1 && old.b == -1) - { - update_time(record, old); - } - } - missing_time = false; - } - } - - if (record.cmd == Altos.AO_LOG_GPS_LAT) { - if (last_gps_time == null || last_gps_time.tick != record.tick) { - AltosOrderedRecord add_gps_time = new AltosOrderedRecord(Altos.AO_LOG_GPS_TIME, - record.tick, - -1, -1, index-1); - if (last_gps_time != null) - update_time(last_gps_time, add_gps_time); - else - missing_time = true; - - records.add(add_gps_time); - record.index = index++; - } - } - records.add(record); - - /* Bail after reading the 'landed' record; we're all done */ - if (record.cmd == Altos.AO_LOG_STATE && - record.a == Altos.ao_flight_landed) - break; - } - } catch (IOException io) { - } catch (ParseException pe) { - } - try { - input.close(); - } catch (IOException ie) { - } - } -} diff --git a/altosui/AltosEepromRecord.java b/altosui/AltosEepromRecord.java deleted file mode 100644 index ea003a1e..00000000 --- a/altosui/AltosEepromRecord.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -import libaltosJNI.*; - -public class AltosEepromRecord { - public int cmd; - public int tick; - public int a; - public int b; - public String data; - public boolean tick_valid; - - static final int record_length = 8; - - public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException { - - cmd = chunk.data(start); - tick_valid = true; - - tick_valid = !chunk.erased(start, record_length); - if (tick_valid) { - if (AltosConvert.checksum(chunk.data, start, record_length) != 0) - throw new ParseException(String.format("invalid checksum at 0x%x", - chunk.address + start), 0); - } else { - cmd = Altos.AO_LOG_INVALID; - } - - tick = chunk.data16(start + 2); - a = chunk.data16(start + 4); - b = chunk.data16(start + 6); - - data = null; - } - - public AltosEepromRecord (String line) { - tick_valid = false; - tick = 0; - a = 0; - b = 0; - data = null; - if (line == null) { - cmd = Altos.AO_LOG_INVALID; - data = ""; - } else { - try { - String[] tokens = line.split("\\s+"); - - if (tokens[0].length() == 1) { - if (tokens.length != 4) { - cmd = Altos.AO_LOG_INVALID; - data = line; - } else { - cmd = tokens[0].codePointAt(0); - tick = Integer.parseInt(tokens[1],16); - tick_valid = true; - a = Integer.parseInt(tokens[2],16); - b = Integer.parseInt(tokens[3],16); - } - } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { - cmd = Altos.AO_LOG_CONFIG_VERSION; - data = tokens[2]; - } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { - cmd = Altos.AO_LOG_MAIN_DEPLOY; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { - cmd = Altos.AO_LOG_APOGEE_DELAY; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { - cmd = Altos.AO_LOG_RADIO_CHANNEL; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Callsign:")) { - cmd = Altos.AO_LOG_CALLSIGN; - data = tokens[1].replaceAll("\"",""); - } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { - cmd = Altos.AO_LOG_ACCEL_CAL; - a = Integer.parseInt(tokens[3]); - b = Integer.parseInt(tokens[5]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { - cmd = Altos.AO_LOG_RADIO_CAL; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { - cmd = Altos.AO_LOG_MAX_FLIGHT_LOG; - a = Integer.parseInt(tokens[3]); - } else if (tokens[0].equals("manufacturer")) { - cmd = Altos.AO_LOG_MANUFACTURER; - data = tokens[1]; - } else if (tokens[0].equals("product")) { - cmd = Altos.AO_LOG_PRODUCT; - data = tokens[1]; - } else if (tokens[0].equals("serial-number")) { - cmd = Altos.AO_LOG_SERIAL_NUMBER; - a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("log-format")) { - cmd = Altos.AO_LOG_LOG_FORMAT; - a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("software-version")) { - cmd = Altos.AO_LOG_SOFTWARE_VERSION; - data = tokens[1]; - } else { - cmd = Altos.AO_LOG_INVALID; - data = line; - } - } catch (NumberFormatException ne) { - cmd = Altos.AO_LOG_INVALID; - data = line; - } - } - } - - public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) { - tick_valid = true; - cmd = in_cmd; - tick = in_tick; - a = in_a; - b = in_b; - } -} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 01732749..a168b6fc 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -43,8 +43,6 @@ altosui_JAVA = \ AltosEepromLog.java \ AltosEepromManage.java \ AltosEepromMonitor.java \ - AltosEepromIterable.java \ - AltosEepromRecord.java \ AltosEepromTeleScience.java \ AltosEepromMega.java \ AltosEepromMegaIterable.java \ diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index cce9b4c4..ad4d2d98 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -15,6 +15,8 @@ AltosLib_JAVA = \ $(SRC)/AltosConvert.java \ $(SRC)/AltosCRCException.java \ $(SRC)/AltosEepromChunk.java \ + $(SRC)/AltosEepromIterable.java \ + $(SRC)/AltosEepromRecord.java \ $(SRC)/AltosFrequency.java \ $(SRC)/AltosGPS.java \ $(SRC)/AltosGPSSat.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java new file mode 100644 index 00000000..f1397c7b --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java @@ -0,0 +1,475 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * AltosRecords with an index field so they can be sorted by tick while preserving + * the original ordering for elements with matching ticks + */ +class AltosOrderedRecord extends AltosEepromRecord implements Comparable { + + public int index; + + public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) + throws ParseException { + super(line); + if (prev_tick_valid) { + tick |= (prev_tick & ~0xffff); + if (tick < prev_tick) { + if (prev_tick - tick > 0x8000) + tick += 0x10000; + } else { + if (tick - prev_tick > 0x8000) + tick -= 0x10000; + } + } + index = in_index; + } + + public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { + super(in_cmd, in_tick, in_a, in_b); + index = in_index; + } + + public String toString() { + return String.format("%d.%d %04x %04x %04x", + cmd, index, tick, a, b); + } + + public int compareTo(AltosOrderedRecord o) { + int tick_diff = tick - o.tick; + if (tick_diff != 0) + return tick_diff; + return index - o.index; + } +} + +public class AltosEepromIterable extends AltosRecordIterable { + + static final int seen_flight = 1; + static final int seen_sensor = 2; + static final int seen_temp_volt = 4; + static final int seen_deploy = 8; + static final int seen_gps_time = 16; + static final int seen_gps_lat = 32; + static final int seen_gps_lon = 64; + + static final int seen_basic = seen_flight|seen_sensor; + + boolean has_accel; + boolean has_gps; + boolean has_ignite; + + AltosEepromRecord flight_record; + AltosEepromRecord gps_date_record; + + TreeSet records; + + LinkedList list; + + class EepromState { + int seen; + int n_pad_samples; + double ground_pres; + int gps_tick; + int boost_tick; + int sensor_tick; + + EepromState() { + seen = 0; + n_pad_samples = 0; + ground_pres = 0.0; + gps_tick = 0; + } + } + + void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { + state.tick = record.tick; + switch (record.cmd) { + case AltosLib.AO_LOG_FLIGHT: + eeprom.seen |= seen_flight; + state.ground_accel = record.a; + state.flight_accel = record.a; + state.flight = record.b; + eeprom.boost_tick = record.tick; + break; + case AltosLib.AO_LOG_SENSOR: + state.accel = record.a; + state.pres = record.b; + if (state.state < AltosLib.ao_flight_boost) { + eeprom.n_pad_samples++; + eeprom.ground_pres += state.pres; + state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); + state.flight_pres = state.ground_pres; + } else { + state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; + } + state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; + if ((eeprom.seen & seen_sensor) == 0) + eeprom.sensor_tick = record.tick - 1; + state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick); + eeprom.seen |= seen_sensor; + eeprom.sensor_tick = record.tick; + has_accel = true; + break; + case AltosLib.AO_LOG_PRESSURE: + state.pres = record.b; + state.flight_pres = state.pres; + if (eeprom.n_pad_samples == 0) { + eeprom.n_pad_samples++; + state.ground_pres = state.pres; + } + eeprom.seen |= seen_sensor; + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.temp = record.a; + state.batt = record.b; + eeprom.seen |= seen_temp_volt; + break; + case AltosLib.AO_LOG_DEPLOY: + state.drogue = record.a; + state.main = record.b; + eeprom.seen |= seen_deploy; + has_ignite = true; + break; + case AltosLib.AO_LOG_STATE: + state.state = record.a; + break; + case AltosLib.AO_LOG_GPS_TIME: + eeprom.gps_tick = state.tick; + AltosGPS old = state.gps; + state.gps = new AltosGPS(); + + /* GPS date doesn't get repeated through the file */ + if (old != null) { + state.gps.year = old.year; + state.gps.month = old.month; + state.gps.day = old.day; + } + state.gps.hour = (record.a & 0xff); + state.gps.minute = (record.a >> 8); + state.gps.second = (record.b & 0xff); + + int flags = (record.b >> 8); + state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0; + state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0; + state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> + AltosLib.AO_GPS_NUM_SAT_SHIFT; + state.new_gps = true; + has_gps = true; + break; + case AltosLib.AO_LOG_GPS_LAT: + int lat32 = record.a | (record.b << 16); + state.gps.lat = (double) lat32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_LON: + int lon32 = record.a | (record.b << 16); + state.gps.lon = (double) lon32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_ALT: + state.gps.alt = record.a; + break; + case AltosLib.AO_LOG_GPS_SAT: + if (state.tick == eeprom.gps_tick) { + int svid = record.a; + int c_n0 = record.b >> 8; + state.gps.add_sat(svid, c_n0); + } + break; + case AltosLib.AO_LOG_GPS_DATE: + state.gps.year = (record.a & 0xff) + 2000; + state.gps.month = record.a >> 8; + state.gps.day = record.b & 0xff; + break; + + case AltosLib.AO_LOG_CONFIG_VERSION: + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + break; + case AltosLib.AO_LOG_CALLSIGN: + state.callsign = record.data; + break; + case AltosLib.AO_LOG_ACCEL_CAL: + state.accel_plus_g = record.a; + state.accel_minus_g = record.b; + break; + case AltosLib.AO_LOG_RADIO_CAL: + break; + case AltosLib.AO_LOG_MANUFACTURER: + break; + case AltosLib.AO_LOG_PRODUCT: + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + state.serial = record.a; + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + break; + } + state.seen |= eeprom.seen; + } + + LinkedList make_list() { + LinkedList list = new LinkedList(); + Iterator iterator = records.iterator(); + AltosOrderedRecord record = null; + AltosRecord state = new AltosRecord(); + boolean last_reported = false; + EepromState eeprom = new EepromState(); + + state.state = AltosLib.ao_flight_pad; + state.accel_plus_g = 15758; + state.accel_minus_g = 16294; + + /* Pull in static data from the flight and gps_date records */ + if (flight_record != null) + update_state(state, flight_record, eeprom); + if (gps_date_record != null) + update_state(state, gps_date_record, eeprom); + + while (iterator.hasNext()) { + record = iterator.next(); + if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + } + update_state(state, record, eeprom); + } + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + return list; + } + + public Iterator iterator() { + if (list == null) + list = make_list(); + return list.iterator(); + } + + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; } + + public void write_comments(PrintStream out) { + Iterator iterator = records.iterator(); + out.printf("# Comments\n"); + while (iterator.hasNext()) { + AltosOrderedRecord record = iterator.next(); + switch (record.cmd) { + case AltosLib.AO_LOG_CONFIG_VERSION: + out.printf("# Config version: %s\n", record.data); + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + out.printf("# Main deploy: %s\n", record.a); + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", record.a); + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", record.a); + break; + case AltosLib.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", record.data); + break; + case AltosLib.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", record.a, record.b); + break; + case AltosLib.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", record.a); + break; + case AltosLib.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", record.a); + break; + case AltosLib.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", record.data); + break; + case AltosLib.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", record.data); + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", record.a); + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", record.data); + break; + case Altos.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", record.a); + break; + } + } + } + + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + /* Make sure this looks like a good GPS value */ + if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) + flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); + flags |= AltosLib.AO_GPS_RUNNING; + flags |= AltosLib.AO_GPS_VALID; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + + /* + * Read the whole file, dumping records into a RB tree so + * we can enumerate them in time order -- the eeprom data + * are sometimes out of order with GPS data getting timestamps + * matching the first packet out of the GPS unit but not + * written until the final GPS packet has been received. + */ + public AltosEepromIterable (FileInputStream input) { + records = new TreeSet(); + + AltosOrderedRecord last_gps_time = null; + + int index = 0; + int prev_tick = 0; + boolean prev_tick_valid = false; + boolean missing_time = false; + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) + break; + AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); + if (record == null) + break; + if (record.cmd == AltosLib.AO_LOG_INVALID) + continue; + prev_tick = record.tick; + if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) + prev_tick_valid = true; + if (record.cmd == AltosLib.AO_LOG_FLIGHT) { + flight_record = record; + continue; + } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { + gps_date_record = record; + continue; + } + + /* go back and fix up any missing time values */ + if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedRecord old = iterator.next(); + if (old.cmd == AltosLib.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == AltosLib.AO_LOG_STATE && + record.a == AltosLib.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java new file mode 100644 index 00000000..b2f23c52 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java @@ -0,0 +1,139 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosEepromRecord { + public int cmd; + public int tick; + public int a; + public int b; + public String data; + public boolean tick_valid; + + static final int record_length = 8; + + public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException { + + cmd = chunk.data(start); + tick_valid = true; + + tick_valid = !chunk.erased(start, record_length); + if (tick_valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + cmd = AltosLib.AO_LOG_INVALID; + } + + tick = chunk.data16(start + 2); + a = chunk.data16(start + 4); + b = chunk.data16(start + 6); + + data = null; + } + + public AltosEepromRecord (String line) { + tick_valid = false; + tick = 0; + a = 0; + b = 0; + data = null; + if (line == null) { + cmd = AltosLib.AO_LOG_INVALID; + data = ""; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 4) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + tick_valid = true; + a = Integer.parseInt(tokens[2],16); + b = Integer.parseInt(tokens[3],16); + } + } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { + cmd = AltosLib.AO_LOG_CONFIG_VERSION; + data = tokens[2]; + } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { + cmd = AltosLib.AO_LOG_MAIN_DEPLOY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { + cmd = AltosLib.AO_LOG_APOGEE_DELAY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { + cmd = AltosLib.AO_LOG_RADIO_CHANNEL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Callsign:")) { + cmd = AltosLib.AO_LOG_CALLSIGN; + data = tokens[1].replaceAll("\"",""); + } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { + cmd = AltosLib.AO_LOG_ACCEL_CAL; + a = Integer.parseInt(tokens[3]); + b = Integer.parseInt(tokens[5]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { + cmd = AltosLib.AO_LOG_RADIO_CAL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { + cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG; + a = Integer.parseInt(tokens[3]); + } else if (tokens[0].equals("manufacturer")) { + cmd = AltosLib.AO_LOG_MANUFACTURER; + data = tokens[1]; + } else if (tokens[0].equals("product")) { + cmd = AltosLib.AO_LOG_PRODUCT; + data = tokens[1]; + } else if (tokens[0].equals("serial-number")) { + cmd = AltosLib.AO_LOG_SERIAL_NUMBER; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("log-format")) { + cmd = AltosLib.AO_LOG_LOG_FORMAT; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("software-version")) { + cmd = AltosLib.AO_LOG_SOFTWARE_VERSION; + data = tokens[1]; + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } catch (NumberFormatException ne) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } + } + + public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) { + tick_valid = true; + cmd = in_cmd; + tick = in_tick; + a = in_a; + b = in_b; + } +} -- cgit v1.2.3 From 346df410f570a67cda057550a067fa2b451b785d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 21:05:02 -0800 Subject: altosui: Move more eeprom stuff to altoslib Signed-off-by: Keith Packard --- altosui/AltosEepromLog.java | 108 --------------------- altosui/AltosEepromSelect.java | 1 + altosui/Makefile.am | 1 - altosui/altoslib/Makefile.am | 1 + .../org/altusmetrum/AltosLib/AltosConfigData.java | 48 ++++----- .../org/altusmetrum/AltosLib/AltosEepromChunk.java | 12 +-- .../org/altusmetrum/AltosLib/AltosEepromLog.java | 100 +++++++++++++++++++ .../altusmetrum/AltosLib/AltosEepromRecord.java | 2 +- 8 files changed, 133 insertions(+), 140 deletions(-) delete mode 100644 altosui/AltosEepromLog.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java (limited to 'altosui') diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java deleted file mode 100644 index a24e82c0..00000000 --- a/altosui/AltosEepromLog.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -import libaltosJNI.*; - -/* - * Extract a bit of information from an eeprom-stored flight log. - */ - -public class AltosEepromLog { - int serial; - boolean has_flight; - int flight; - int start_block; - int end_block; - - int year, month, day; - - boolean selected; - - public AltosEepromLog(AltosConfigData config_data, - AltosSerial serial_line, - int in_flight, int in_start_block, - int in_end_block) - throws InterruptedException, TimeoutException { - - int block; - boolean has_date = false; - - flight = in_flight; - if (flight != 0) - has_flight = true; - start_block = in_start_block; - end_block = in_end_block; - serial = config_data.serial; - - /* - * Select all flights for download - */ - selected = true; - - /* - * Look in TeleMetrum log data for date - */ - if (config_data.log_format == Altos.AO_LOG_FORMAT_UNKNOWN || - config_data.log_format == Altos.AO_LOG_FORMAT_FULL) - { - /* - * Only look in the first two blocks so that this - * process doesn't take a long time - */ - if (in_end_block > in_start_block + 2) - in_end_block = in_start_block + 2; - - for (block = in_start_block; block < in_end_block; block++) { - AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block, block == in_start_block); - - for (int i = 0; i < eechunk.chunk_size; i += AltosEepromRecord.record_length) { - try { - AltosEepromRecord r = new AltosEepromRecord(eechunk, i); - - if (r.cmd == Altos.AO_LOG_FLIGHT) { - flight = r.b; - has_flight = true; - } - if (r.cmd == Altos.AO_LOG_GPS_DATE) { - year = 2000 + (r.a & 0xff); - month = (r.a >> 8) & 0xff; - day = (r.b & 0xff); - has_date = true; - } - } catch (ParseException pe) { - } - } - if (has_date && has_flight) - break; - } - } - } -} diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index e0fbeead..4ad78896 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -27,6 +27,7 @@ import libaltosJNI.libaltos; import libaltosJNI.altos_device; import libaltosJNI.SWIGTYPE_p_altos_file; import libaltosJNI.SWIGTYPE_p_altos_list; +import org.altusmetrum.AltosLib.*; class AltosEepromItem implements ActionListener { AltosEepromLog log; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index a168b6fc..84482dc2 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -40,7 +40,6 @@ altosui_JAVA = \ AltosEepromDelete.java \ AltosEepromDownload.java \ AltosEepromList.java \ - AltosEepromLog.java \ AltosEepromManage.java \ AltosEepromMonitor.java \ AltosEepromTeleScience.java \ diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index ad4d2d98..32f0ecfb 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -16,6 +16,7 @@ AltosLib_JAVA = \ $(SRC)/AltosCRCException.java \ $(SRC)/AltosEepromChunk.java \ $(SRC)/AltosEepromIterable.java \ + $(SRC)/AltosEepromLog.java \ $(SRC)/AltosEepromRecord.java \ $(SRC)/AltosFrequency.java \ $(SRC)/AltosGPS.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java index fec1a042..4ad4e58a 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java @@ -27,33 +27,33 @@ import org.altusmetrum.AltosLib.*; public class AltosConfigData implements Iterable { /* Version information */ - String manufacturer; - String product; - String version; - int log_format; - int serial; + public String manufacturer; + public String product; + public String version; + public int log_format; + public int serial; /* Strings returned */ - LinkedList lines; + public LinkedList lines; /* Config information */ - int config_major; - int config_minor; - int main_deploy; - int apogee_delay; - int radio_channel; - int radio_setting; - int radio_frequency; - String callsign; - int accel_cal_plus, accel_cal_minus; - int radio_calibration; - int flight_log_max; - int ignite_mode; - int stored_flight; - int storage_size; - int storage_erase_unit; - - static String get_string(String line, String label) throws ParseException { + public int config_major; + public int config_minor; + public int main_deploy; + public int apogee_delay; + public int radio_channel; + public int radio_setting; + public int radio_frequency; + public String callsign; + public int accel_cal_plus, accel_cal_minus; + public int radio_calibration; + public int flight_log_max; + public int ignite_mode; + public int stored_flight; + public int storage_size; + public int storage_erase_unit; + + public static String get_string(String line, String label) throws ParseException { if (line.startsWith(label)) { String quoted = line.substring(label.length()).trim(); @@ -66,7 +66,7 @@ public class AltosConfigData implements Iterable { throw new ParseException("mismatch", 0); } - static int get_int(String line, String label) throws NumberFormatException, ParseException { + public static int get_int(String line, String label) throws NumberFormatException, ParseException { if (line.startsWith(label)) { String tail = line.substring(label.length()).trim(); String[] tokens = tail.split("\\s+"); diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java index 4a9a2679..6d889723 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java @@ -24,8 +24,8 @@ import java.util.concurrent.*; public class AltosEepromChunk { - static final int chunk_size = 256; - static final int per_line = 8; + public static final int chunk_size = 256; + public static final int per_line = 8; public int data[]; public int address; @@ -44,20 +44,20 @@ public class AltosEepromChunk { return array; } - int data(int offset) { + public int data(int offset) { return data[offset]; } - int data16(int offset) { + public int data16(int offset) { return data[offset] | (data[offset + 1] << 8); } - int data32(int offset) { + public int data32(int offset) { return data[offset] | (data[offset + 1] << 8) | (data[offset+2] << 16) | (data[offset+3] << 24); } - boolean erased(int start, int len) { + public boolean erased(int start, int len) { for (int i = 0; i < len; i++) if (data[start+i] != 0xff) return false; diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java new file mode 100644 index 00000000..7fca4bd9 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java @@ -0,0 +1,100 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +/* + * Extract a bit of information from an eeprom-stored flight log. + */ + +public class AltosEepromLog { + public int serial; + public boolean has_flight; + public int flight; + public int start_block; + public int end_block; + + public int year, month, day; + + public boolean selected; + + public AltosEepromLog(AltosConfigData config_data, + AltosLink link, + int in_flight, int in_start_block, + int in_end_block) + throws InterruptedException, TimeoutException { + + int block; + boolean has_date = false; + + flight = in_flight; + if (flight != 0) + has_flight = true; + start_block = in_start_block; + end_block = in_end_block; + serial = config_data.serial; + + /* + * Select all flights for download + */ + selected = true; + + /* + * Look in TeleMetrum log data for date + */ + if (config_data.log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN || + config_data.log_format == AltosLib.AO_LOG_FORMAT_FULL) + { + /* + * Only look in the first two blocks so that this + * process doesn't take a long time + */ + if (in_end_block > in_start_block + 2) + in_end_block = in_start_block + 2; + + for (block = in_start_block; block < in_end_block; block++) { + AltosEepromChunk eechunk = new AltosEepromChunk(link, block, block == in_start_block); + + for (int i = 0; i < eechunk.chunk_size; i += AltosEepromRecord.record_length) { + try { + AltosEepromRecord r = new AltosEepromRecord(eechunk, i); + + if (r.cmd == AltosLib.AO_LOG_FLIGHT) { + flight = r.b; + has_flight = true; + } + if (r.cmd == AltosLib.AO_LOG_GPS_DATE) { + year = 2000 + (r.a & 0xff); + month = (r.a >> 8) & 0xff; + day = (r.b & 0xff); + has_date = true; + } + } catch (ParseException pe) { + } + } + if (has_date && has_flight) + break; + } + } + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java index b2f23c52..1e845f46 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java @@ -31,7 +31,7 @@ public class AltosEepromRecord { public String data; public boolean tick_valid; - static final int record_length = 8; + public static final int record_length = 8; public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException { -- cgit v1.2.3 From 027863b737190bccc3b5cd032d77587396d0c5c4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 21:08:34 -0800 Subject: altosui: Move AltosEepromTeleScience.java to altoslib Signed-off-by: Keith Packard --- altosui/AltosEepromTeleScience.java | 65 ---------------------- altosui/altoslib/Makefile.am | 1 + .../AltosLib/AltosEepromTeleScience.java | 59 ++++++++++++++++++++ 3 files changed, 60 insertions(+), 65 deletions(-) delete mode 100644 altosui/AltosEepromTeleScience.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java (limited to 'altosui') diff --git a/altosui/AltosEepromTeleScience.java b/altosui/AltosEepromTeleScience.java deleted file mode 100644 index 0c237e11..00000000 --- a/altosui/AltosEepromTeleScience.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -public class AltosEepromTeleScience { - int type; - int tick; - int tm_state; - int tm_tick; - int[] data; - boolean valid; - - static final int AO_LOG_TELESCIENCE_START = 's'; - static final int AO_LOG_TELESCIENCE_DATA = 'd'; - - static final int max_data = 12; - static final int record_length = 32; - - public AltosEepromTeleScience (AltosEepromChunk chunk, int start) throws ParseException { - type = chunk.data(start); - - valid = !chunk.erased(start, record_length); - if (valid) { - if (AltosConvert.checksum(chunk.data, start, record_length) != 0) - throw new ParseException(String.format("invalid checksum at 0x%x", - chunk.address + start), 0); - } else { - type = Altos.AO_LOG_INVALID; - } - - tick = chunk.data16(start+2); - tm_tick = chunk.data16(start+4); - tm_state = chunk.data(start+6); - data = new int[max_data]; - for (int i = 0; i < max_data; i++) - data[i] = chunk.data16(start + 8 + i * 2); - } -} diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index 32f0ecfb..6f8c028a 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -18,6 +18,7 @@ AltosLib_JAVA = \ $(SRC)/AltosEepromIterable.java \ $(SRC)/AltosEepromLog.java \ $(SRC)/AltosEepromRecord.java \ + $(SRC)/AltosEepromTeleScience.java \ $(SRC)/AltosFrequency.java \ $(SRC)/AltosGPS.java \ $(SRC)/AltosGPSSat.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java new file mode 100644 index 00000000..1758fa34 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java @@ -0,0 +1,59 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosEepromTeleScience { + public int type; + public int tick; + public int tm_state; + public int tm_tick; + public int[] data; + public boolean valid; + + public static final int AO_LOG_TELESCIENCE_START = 's'; + public static final int AO_LOG_TELESCIENCE_DATA = 'd'; + + static final int max_data = 12; + public static final int record_length = 32; + + public AltosEepromTeleScience (AltosEepromChunk chunk, int start) throws ParseException { + type = chunk.data(start); + + valid = !chunk.erased(start, record_length); + if (valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + type = AltosLib.AO_LOG_INVALID; + } + + tick = chunk.data16(start+2); + tm_tick = chunk.data16(start+4); + tm_state = chunk.data(start+6); + data = new int[max_data]; + for (int i = 0; i < max_data; i++) + data[i] = chunk.data16(start + 8 + i * 2); + } +} -- cgit v1.2.3 From 18914b9a84bbd8c4364a1568bb07dcc2b04ad7ba Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 21:12:45 -0800 Subject: altosui: Move AltosGreatCircle.java to altoslib Signed-off-by: Keith Packard --- altosui/AltosGreatCircle.java | 101 --------------------- altosui/Makefile.am | 1 - altosui/altoslib/Makefile.am | 1 + .../org/altusmetrum/AltosLib/AltosGreatCircle.java | 101 +++++++++++++++++++++ 4 files changed, 102 insertions(+), 102 deletions(-) delete mode 100644 altosui/AltosGreatCircle.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java (limited to 'altosui') diff --git a/altosui/AltosGreatCircle.java b/altosui/AltosGreatCircle.java deleted file mode 100644 index e4af3c18..00000000 --- a/altosui/AltosGreatCircle.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 altosui; - -import java.lang.Math; -import org.altusmetrum.AltosLib.*; - -public class AltosGreatCircle { - double distance; - double bearing; - - double sqr(double a) { return a * a; } - - static final double rad = Math.PI / 180; - static final double earth_radius = 6371.2 * 1000; /* in meters */ - - static int BEARING_LONG = 0; - static int BEARING_SHORT = 1; - static int BEARING_VOICE = 2; - String bearing_words(int length) { - String [][] bearing_string = { - { - "North", "North North East", "North East", "East North East", - "East", "East South East", "South East", "South South East", - "South", "South South West", "South West", "West South West", - "West", "West North West", "North West", "North North West" - }, { - "N", "NNE", "NE", "ENE", - "E", "ESE", "SE", "SSE", - "S", "SSW", "SW", "WSW", - "W", "WNW", "NW", "NNW" - }, { - "north", "nor nor east", "north east", "east nor east", - "east", "east sow east", "south east", "sow sow east", - "south", "sow sow west", "south west", "west sow west", - "west", "west nor west", "north west", "nor nor west " - } - }; - return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16]; - } - - public AltosGreatCircle (double start_lat, double start_lon, - double end_lat, double end_lon) - { - double lat1 = rad * start_lat; - double lon1 = rad * -start_lon; - double lat2 = rad * end_lat; - double lon2 = rad * -end_lon; - - double d_lon = lon2 - lon1; - - /* From http://en.wikipedia.org/wiki/Great-circle_distance */ - double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) + - sqr(Math.cos(lat1) * Math.sin(lat2) - - Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon))); - double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon); - double d = Math.atan2(vdn,vdd); - double course; - - if (Math.cos(lat1) < 1e-20) { - if (lat1 > 0) - course = Math.PI; - else - course = -Math.PI; - } else { - if (d < 1e-10) - course = 0; - else - course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) / - (Math.sin(d)*Math.cos(lat1))); - if (Math.sin(lon2-lon1) > 0) - course = 2 * Math.PI-course; - } - distance = d * earth_radius; - bearing = course * 180/Math.PI; - } - - public AltosGreatCircle(AltosGPS start, AltosGPS end) { - this(start.lat, start.lon, end.lat, end.lon); - } - - public AltosGreatCircle() { - distance = 0; - bearing = 0; - } -} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 84482dc2..f8a886ba 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -62,7 +62,6 @@ altosui_JAVA = \ AltosFlightUI.java \ AltosFontListener.java \ AltosFreqList.java \ - AltosGreatCircle.java \ AltosHexfile.java \ Altos.java \ AltosIdleMonitorUI.java \ diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index 6f8c028a..e0647bd4 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -22,6 +22,7 @@ AltosLib_JAVA = \ $(SRC)/AltosFrequency.java \ $(SRC)/AltosGPS.java \ $(SRC)/AltosGPSSat.java \ + $(SRC)/AltosGreatCircle.java \ $(SRC)/AltosLine.java \ $(SRC)/AltosLink.java \ $(SRC)/AltosParse.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java new file mode 100644 index 00000000..76b71859 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java @@ -0,0 +1,101 @@ +/* + * 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.AltosLib; + +import java.lang.Math; + +public class AltosGreatCircle { + public double distance; + public double bearing; + + double sqr(double a) { return a * a; } + + static final double rad = Math.PI / 180; + static final double earth_radius = 6371.2 * 1000; /* in meters */ + + public static final int BEARING_LONG = 0; + public static final int BEARING_SHORT = 1; + public static final int BEARING_VOICE = 2; + + public String bearing_words(int length) { + String [][] bearing_string = { + { + "North", "North North East", "North East", "East North East", + "East", "East South East", "South East", "South South East", + "South", "South South West", "South West", "West South West", + "West", "West North West", "North West", "North North West" + }, { + "N", "NNE", "NE", "ENE", + "E", "ESE", "SE", "SSE", + "S", "SSW", "SW", "WSW", + "W", "WNW", "NW", "NNW" + }, { + "north", "nor nor east", "north east", "east nor east", + "east", "east sow east", "south east", "sow sow east", + "south", "sow sow west", "south west", "west sow west", + "west", "west nor west", "north west", "nor nor west " + } + }; + return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16]; + } + + public AltosGreatCircle (double start_lat, double start_lon, + double end_lat, double end_lon) + { + double lat1 = rad * start_lat; + double lon1 = rad * -start_lon; + double lat2 = rad * end_lat; + double lon2 = rad * -end_lon; + + double d_lon = lon2 - lon1; + + /* From http://en.wikipedia.org/wiki/Great-circle_distance */ + double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) + + sqr(Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon))); + double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon); + double d = Math.atan2(vdn,vdd); + double course; + + if (Math.cos(lat1) < 1e-20) { + if (lat1 > 0) + course = Math.PI; + else + course = -Math.PI; + } else { + if (d < 1e-10) + course = 0; + else + course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) / + (Math.sin(d)*Math.cos(lat1))); + if (Math.sin(lon2-lon1) > 0) + course = 2 * Math.PI-course; + } + distance = d * earth_radius; + bearing = course * 180/Math.PI; + } + + public AltosGreatCircle(AltosGPS start, AltosGPS end) { + this(start.lat, start.lon, end.lat, end.lon); + } + + public AltosGreatCircle() { + distance = 0; + bearing = 0; + } +} -- cgit v1.2.3 From a5ac5c37ea385e3a2b2703c6f125b4e3b55e867a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 22:05:47 -0800 Subject: altosui: Pull most of AltosSerial into AltosLink Share basic command processing across java users Signed-off-by: Keith Packard --- altosui/AltosFontListener.java | 2 +- altosui/AltosSerial.java | 103 ++-------- altosui/AltosUIPreferences.java | 4 +- altosui/Makefile.am | 4 +- .../src/org/altusmetrum/AltosLib/AltosLink.java | 219 ++++++++++++++++++++- 5 files changed, 233 insertions(+), 99 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosFontListener.java b/altosui/AltosFontListener.java index 6fc214bc..0dda0f29 100644 --- a/altosui/AltosFontListener.java +++ b/altosui/AltosFontListener.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.AltosLib; +package altosui; public interface AltosFontListener { void font_size_changed(int font_size); diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 161f0e90..cc384586 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -41,33 +41,22 @@ import libaltosJNI.*; * threads. */ -public class AltosSerial implements Runnable, AltosLink { +public class AltosSerial extends AltosLink implements Runnable { static java.util.List devices_opened = Collections.synchronizedList(new LinkedList()); AltosDevice device; SWIGTYPE_p_altos_file altos; - LinkedList> monitors; - LinkedBlockingQueue reply_queue; Thread input_thread; String line; byte[] line_bytes; int line_count; - boolean monitor_mode; - int telemetry; - double frequency; - public static boolean debug; - boolean remote; - LinkedList pending_output = new LinkedList(); Frame frame; - AltosConfigData config_data; - - static void set_debug(boolean new_debug) { - debug = new_debug; - } public void run () { int c; + byte[] line_bytes = null; + int line_count = 0; try { for (;;) { @@ -75,11 +64,8 @@ public class AltosSerial implements Runnable, AltosLink { if (Thread.interrupted()) break; if (c == libaltosConstants.LIBALTOS_ERROR) { - for (int e = 0; e < monitors.size(); e++) { - LinkedBlockingQueue q = monitors.get(e); - q.put(new AltosLine()); - } - reply_queue.put (new AltosLine()); + add_telem (new AltosLine()); + add_reply (new AltosLine()); break; } if (c == libaltosConstants.LIBALTOS_TIMEOUT) @@ -89,25 +75,8 @@ public class AltosSerial implements Runnable, AltosLink { synchronized(this) { if (c == '\n') { if (line_count != 0) { - try { - line = new String(line_bytes, 0, line_count, "UTF-8"); - } catch (UnsupportedEncodingException ue) { - line = ""; - for (int i = 0; i < line_count; i++) - line = line + line_bytes[i]; - } - if (debug) - System.out.printf("\t\t\t\t\t%s\n", line); - if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { - for (int e = 0; e < monitors.size(); e++) { - LinkedBlockingQueue q = monitors.get(e); - q.put(new AltosLine (line)); - } - } else { - reply_queue.put(new AltosLine (line)); - } + add_bytes(line_bytes, line_count); line_count = 0; - line = ""; } } else { if (line_bytes == null) { @@ -127,10 +96,8 @@ public class AltosSerial implements Runnable, AltosLink { } public void flush_output() { + super.flush_output(); if (altos != null) { - for (String s : pending_output) - System.out.print(s); - pending_output.clear(); libaltos.altos_flush(altos); } } @@ -189,22 +156,10 @@ public class AltosSerial implements Runnable, AltosLink { } public void flush_input() throws InterruptedException { - flush_output(); - boolean got_some; - - int timeout = 100; if (remote) - timeout = 500; - do { - Thread.sleep(timeout); - got_some = !reply_queue.isEmpty(); - synchronized(this) { - if (!"VERSION".startsWith(line) && - !line.startsWith("VERSION")) - line = ""; - reply_queue.clear(); - } - } while (got_some); + flush_input(500); + else + flush_input(100); } int in_reply; @@ -245,29 +200,6 @@ public class AltosSerial implements Runnable, AltosLink { return reply; } - public String get_reply() throws InterruptedException { - return get_reply(5000); - } - - public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { - flush_output(); - AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); - if (line != null) - return line.line; - return null; - } - - public void add_monitor(LinkedBlockingQueue q) { - set_monitor(true); - monitors.add(q); - } - - public void remove_monitor(LinkedBlockingQueue q) { - monitors.remove(q); - if (monitors.isEmpty()) - set_monitor(false); - } - public void close() { if (remote) { try { @@ -306,16 +238,10 @@ public class AltosSerial implements Runnable, AltosLink { } public void print(String data) { - if (debug) - pending_output.add(data); for (int i = 0; i < data.length(); i++) putc(data.charAt(i)); } - public void printf(String format, Object ... arguments) { - print(String.format(format, arguments)); - } - private void open() throws FileNotFoundException, AltosSerialInUseException { synchronized (devices_opened) { if (devices_opened.contains(device.getPath())) @@ -338,6 +264,7 @@ public class AltosSerial implements Runnable, AltosLink { flush_output(); } +<<<<<<< HEAD private int telemetry_len() { return Altos.telemetry_len(telemetry); } @@ -459,18 +386,16 @@ public class AltosSerial implements Runnable, AltosLink { remote = false; } +======= +>>>>>>> bc5e669... altosui: Pull most of AltosSerial into AltosLink public void set_frame(Frame in_frame) { frame = in_frame; } public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { device = in_device; - line = ""; - monitor_mode = false; frame = null; - telemetry = Altos.ao_telemetry_standard; - monitors = new LinkedList> (); - reply_queue = new LinkedBlockingQueue (); + serial = device.getSerial(); open(); } } diff --git a/altosui/AltosUIPreferences.java b/altosui/AltosUIPreferences.java index 38af734e..10ab26c3 100644 --- a/altosui/AltosUIPreferences.java +++ b/altosui/AltosUIPreferences.java @@ -58,7 +58,7 @@ public class AltosUIPreferences extends AltosPreferences { ui_listeners = new LinkedList(); serial_debug = preferences.getBoolean(serialDebugPreference, false); - AltosSerial.set_debug(serial_debug); + AltosLink.set_debug(serial_debug); } static { init(); } @@ -162,7 +162,7 @@ public class AltosUIPreferences extends AltosPreferences { } public static void set_serial_debug(boolean new_serial_debug) { serial_debug = new_serial_debug; - AltosSerial.set_debug(serial_debug); + AltosLink.set_debug(serial_debug); synchronized (preferences) { preferences.putBoolean(serialDebugPreference, serial_debug); flush_preferences(); diff --git a/altosui/Makefile.am b/altosui/Makefile.am index f8a886ba..913a8df1 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -247,11 +247,11 @@ $(FATJAR): classaltosui.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(FREETTS_CLASS Manifest.txt: Makefile echo 'Main-Class: altosui.AltosUI' > $@ - echo "Class-Path: altoslib.jar $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@ + echo "Class-Path: AltosLib.jar $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@ Manifest-fat.txt: echo 'Main-Class: altosui.AltosUI' > $@ - echo "Class-Path: altoslib.jar freetts.jar jfreechart.jar jcommon.jar" >> $@ + echo "Class-Path: AltosLib.jar freetts.jar jfreechart.jar jcommon.jar" >> $@ altosui: Makefile echo "#!/bin/sh" > $@ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java index 9a23b306..49585975 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java @@ -17,12 +17,221 @@ package org.altusmetrum.AltosLib; -public interface AltosLink { - public void printf(String format, Object ... arguments) throws InterruptedException; +import java.lang.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import java.text.*; - public String get_reply() throws InterruptedException; +public abstract class AltosLink { - public String get_reply(int timeout) throws InterruptedException; + public static boolean debug = false; + public static void set_debug(boolean in_debug) { debug = in_debug; } + LinkedList pending_output = new LinkedList(); - public void flush_input() throws InterruptedException; + public LinkedList> monitors = new LinkedList> ();; + public LinkedBlockingQueue reply_queue = new LinkedBlockingQueue(); + + public void add_monitor(LinkedBlockingQueue q) { + set_monitor(true); + monitors.add(q); + } + + public void remove_monitor(LinkedBlockingQueue q) { + monitors.remove(q); + if (monitors.isEmpty()) + set_monitor(false); + } + + public abstract void print(String data); + + public void printf(String format, Object ... arguments) { + String line = String.format(format, arguments); + if (debug) + pending_output.add(line); + print(line); + } + + public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { + flush_output(); + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) + return line.line; + return null; + } + + public String get_reply(int timeout) throws InterruptedException { + try { + return get_reply_no_dialog(timeout); + } catch (TimeoutException te) { + return null; + } + } + + public String get_reply() throws InterruptedException { + return get_reply(5000); + } + + public void add_telem(AltosLine line) throws InterruptedException { + for (int e = 0; e < monitors.size(); e++) { + LinkedBlockingQueue q = monitors.get(e); + q.put(line); + } + } + + public void add_reply(AltosLine line) throws InterruptedException { + reply_queue.put (line); + } + + public void add_string(String line) throws InterruptedException { + if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { + add_telem(new AltosLine(line)); + } else { + add_reply(new AltosLine(line)); + } + } + + public void add_bytes(byte[] bytes, int len) throws InterruptedException { + String line; + try { + line = new String(bytes, 0, len, "UTF-8"); + } catch (UnsupportedEncodingException ue) { + line = ""; + for (int i = 0; i < len; i++) + line = line + bytes[i]; + } + if (debug) + System.out.printf("\t\t\t\t\t%s\n", line); + add_string(line); + } + + public void flush_output() { + for (String s : pending_output) + System.out.print(s); + pending_output.clear(); + } + + public void flush_input(int timeout) throws InterruptedException { + flush_output(); + boolean got_some; + + do { + Thread.sleep(timeout); + got_some = !reply_queue.isEmpty(); + reply_queue.clear(); + } while (got_some); + } + + + public void flush_input() throws InterruptedException { + flush_input(100); + } + + + /* + * Various command-level operations on + * the link + */ + public boolean monitor_mode = false; + public int telemetry = AltosLib.ao_telemetry_standard; + public double frequency; + AltosConfigData config_data; + + private int telemetry_len() { + return AltosLib.telemetry_len(telemetry); + } + + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + if (monitor_mode) + printf("m 0\nm %x\n", telemetry_len()); + flush_output(); + } + + public void set_monitor(boolean monitor) { + monitor_mode = monitor; + if (monitor) + printf("m %x\n", telemetry_len()); + else + printf("m 0\n"); + flush_output(); + } + + private void set_channel(int channel) { + if (monitor_mode) + printf("m 0\nc r %d\nm %x\n", + channel, telemetry_len()); + else + printf("c r %d\n", channel); + flush_output(); + } + + private void set_radio_setting(int setting) { + if (monitor_mode) + printf("m 0\nc R %d\nm %x\n", + setting, telemetry_len()); + else + printf("c R %d\n", setting); + flush_output(); + } + + public void set_radio_frequency(double frequency, + boolean has_setting, + int cal) { + if (debug) + System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); + if (has_setting) + set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); + else + set_channel(AltosConvert.radio_frequency_to_channel(frequency)); + } + + public AltosConfigData config_data() throws InterruptedException, TimeoutException { + if (config_data == null) + config_data = new AltosConfigData(this); + return config_data; + } + + public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + config_data(); + set_radio_frequency(frequency, + config_data.radio_setting != 0, + config_data.radio_calibration); + } + + public void set_callsign(String callsign) { + printf ("c c %s\n", callsign); + flush_output(); + } + + public boolean remote; + public int serial; + + public void start_remote() throws TimeoutException, InterruptedException { + if (debug) + System.out.printf("start remote %7.3f\n", frequency); + if (frequency == 0.0) + frequency = AltosPreferences.frequency(serial); + set_radio_frequency(frequency); + set_callsign(AltosPreferences.callsign()); + printf("p\nE 0\n"); + flush_input(); + remote = true; + } + + public void stop_remote() throws InterruptedException { + if (debug) + System.out.printf("stop remote\n"); + try { + flush_input(); + } finally { + printf ("~\n"); + flush_output(); + } + remote = false; + } + + public AltosLink() { + } } -- cgit v1.2.3 From 93305717ac4c993c88d9144d797ca64d26db97c5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 22:13:38 -0800 Subject: altosui: Move AltosState.java to altoslib Signed-off-by: Keith Packard --- altosui/AltosFlightDisplay.java | 2 + altosui/AltosState.java | 216 --------------------- altosui/Makefile.am | 1 - altosui/altoslib/Makefile.am | 1 + .../src/org/altusmetrum/AltosLib/AltosState.java | 210 ++++++++++++++++++++ 5 files changed, 213 insertions(+), 217 deletions(-) delete mode 100644 altosui/AltosState.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosState.java (limited to 'altosui') diff --git a/altosui/AltosFlightDisplay.java b/altosui/AltosFlightDisplay.java index f633c8e6..826f9522 100644 --- a/altosui/AltosFlightDisplay.java +++ b/altosui/AltosFlightDisplay.java @@ -17,6 +17,8 @@ package altosui; +import org.altusmetrum.AltosLib.*; + public interface AltosFlightDisplay { void reset(); diff --git a/altosui/AltosState.java b/altosui/AltosState.java deleted file mode 100644 index 403c74be..00000000 --- a/altosui/AltosState.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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. - */ - -/* - * Track flight state from telemetry or eeprom data stream - */ - -package altosui; - -import org.altusmetrum.AltosLib.*; - -public class AltosState { - AltosRecord data; - - /* derived data */ - - long report_time; - - double time; - double time_change; - int tick; - - int state; - boolean landed; - boolean ascent; /* going up? */ - boolean boost; /* under power */ - - double ground_altitude; - double height; - double speed; - double acceleration; - double battery; - double temperature; - double main_sense; - double drogue_sense; - double baro_speed; - - double max_height; - double max_acceleration; - double max_speed; - double max_baro_speed; - - AltosGPS gps; - - AltosIMU imu; - AltosMag mag; - - double pad_lat; - double pad_lon; - double pad_alt; - - static final int MIN_PAD_SAMPLES = 10; - - int npad; - int ngps; - int gps_waiting; - boolean gps_ready; - - AltosGreatCircle from_pad; - double elevation; /* from pad */ - double range; /* total distance */ - - double gps_height; - - int speak_tick; - double speak_altitude; - - void init (AltosRecord cur, AltosState prev_state) { - int i; - AltosRecord prev; - - data = cur; - - ground_altitude = data.ground_altitude(); - height = data.filtered_height(); - - report_time = System.currentTimeMillis(); - - acceleration = data.acceleration(); - speed = data.accel_speed(); - temperature = data.temperature(); - drogue_sense = data.drogue_voltage(); - main_sense = data.main_voltage(); - battery = data.battery_voltage(); - tick = data.tick; - state = data.state; - - if (prev_state != null) { - - /* Preserve any existing gps data */ - npad = prev_state.npad; - ngps = prev_state.ngps; - gps = prev_state.gps; - pad_lat = prev_state.pad_lat; - pad_lon = prev_state.pad_lon; - pad_alt = prev_state.pad_alt; - max_height = prev_state.max_height; - max_acceleration = prev_state.max_acceleration; - max_speed = prev_state.max_speed; - max_baro_speed = prev_state.max_baro_speed; - imu = prev_state.imu; - mag = prev_state.mag; - - /* make sure the clock is monotonic */ - while (tick < prev_state.tick) - tick += 65536; - - time_change = (tick - prev_state.tick) / 100.0; - - /* compute barometric speed */ - - double height_change = height - prev_state.height; - if (data.speed != AltosRecord.MISSING) - baro_speed = data.speed; - else { - if (time_change > 0) - baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; - else - baro_speed = prev_state.baro_speed; - } - } else { - npad = 0; - ngps = 0; - gps = null; - baro_speed = 0; - time_change = 0; - } - - time = tick / 100.0; - - if (cur.new_gps && (state == Altos.ao_flight_pad || state == Altos.ao_flight_idle)) { - - /* Track consecutive 'good' gps reports, waiting for 10 of them */ - if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) - npad++; - else - npad = 0; - - /* Average GPS data while on the pad */ - if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) { - if (ngps > 1) { - /* filter pad position */ - pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0; - pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0; - pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0; - } else { - pad_lat = data.gps.lat; - pad_lon = data.gps.lon; - pad_alt = data.gps.alt; - } - ngps++; - } - } - - gps_waiting = MIN_PAD_SAMPLES - npad; - if (gps_waiting < 0) - gps_waiting = 0; - - gps_ready = gps_waiting == 0; - - ascent = (Altos.ao_flight_boost <= state && - state <= Altos.ao_flight_coast); - boost = (Altos.ao_flight_boost == state); - - /* Only look at accelerometer data under boost */ - if (boost && acceleration > max_acceleration) - max_acceleration = acceleration; - if (boost && speed > max_speed) - max_speed = speed; - if (boost && baro_speed > max_baro_speed) - max_baro_speed = baro_speed; - - if (height > max_height) - max_height = height; - if (data.gps != null) { - if (gps == null || !gps.locked || data.gps.locked) - gps = data.gps; - if (ngps > 0 && gps.locked) { - from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); - } - } - elevation = 0; - range = -1; - if (ngps > 0) { - gps_height = gps.alt - pad_alt; - if (from_pad != null) { - elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; - range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); - } - } else { - gps_height = 0; - } - } - - public AltosState(AltosRecord cur) { - init(cur, null); - } - - public AltosState (AltosRecord cur, AltosState prev) { - init(cur, prev); - } -} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 913a8df1..270fe114 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -90,7 +90,6 @@ altosui_JAVA = \ AltosSiteMapPreload.java \ AltosSiteMapCache.java \ AltosSiteMapTile.java \ - AltosState.java \ AltosTelemetryReader.java \ AltosUI.java \ AltosUIListener.java \ diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index e0647bd4..40ec3af8 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -30,6 +30,7 @@ AltosLib_JAVA = \ $(SRC)/AltosRecordCompanion.java \ $(SRC)/AltosRecordIterable.java \ $(SRC)/AltosRecord.java \ + $(SRC)/AltosState.java \ $(SRC)/AltosTelemetry.java \ $(SRC)/AltosTelemetryIterable.java \ $(SRC)/AltosTelemetryMap.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosState.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosState.java new file mode 100644 index 00000000..0645e448 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosState.java @@ -0,0 +1,210 @@ +/* + * 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. + */ + +/* + * Track flight state from telemetry or eeprom data stream + */ + +package org.altusmetrum.AltosLib; + +public class AltosState { + public AltosRecord data; + + /* derived data */ + + public long report_time; + + public double time; + public double time_change; + public int tick; + + public int state; + public boolean landed; + public boolean ascent; /* going up? */ + public boolean boost; /* under power */ + + public double ground_altitude; + public double height; + public double speed; + public double acceleration; + public double battery; + public double temperature; + public double main_sense; + public double drogue_sense; + public double baro_speed; + + public double max_height; + public double max_acceleration; + public double max_speed; + public double max_baro_speed; + + public AltosGPS gps; + + public AltosIMU imu; + public AltosMag mag; + + public static final int MIN_PAD_SAMPLES = 10; + + public int npad; + public int ngps; + public int gps_waiting; + public boolean gps_ready; + + public AltosGreatCircle from_pad; + public double elevation; /* from pad */ + public double range; /* total distance */ + + public double gps_height; + + public int speak_tick; + public double speak_altitude; + + public void init (AltosRecord cur, AltosState prev_state) { + int i; + AltosRecord prev; + + data = cur; + + ground_altitude = data.ground_altitude(); + height = data.filtered_height(); + + report_time = System.currentTimeMillis(); + + acceleration = data.acceleration(); + speed = data.accel_speed(); + temperature = data.temperature(); + drogue_sense = data.drogue_voltage(); + main_sense = data.main_voltage(); + battery = data.battery_voltage(); + tick = data.tick; + state = data.state; + + if (prev_state != null) { + + /* Preserve any existing gps data */ + npad = prev_state.npad; + ngps = prev_state.ngps; + gps = prev_state.gps; + pad_lat = prev_state.pad_lat; + pad_lon = prev_state.pad_lon; + pad_alt = prev_state.pad_alt; + max_height = prev_state.max_height; + max_acceleration = prev_state.max_acceleration; + max_speed = prev_state.max_speed; + max_baro_speed = prev_state.max_baro_speed; + imu = prev_state.imu; + mag = prev_state.mag; + + /* make sure the clock is monotonic */ + while (tick < prev_state.tick) + tick += 65536; + + time_change = (tick - prev_state.tick) / 100.0; + + /* compute barometric speed */ + + double height_change = height - prev_state.height; + if (data.speed != AltosRecord.MISSING) + baro_speed = data.speed; + else { + if (time_change > 0) + baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; + else + baro_speed = prev_state.baro_speed; + } + } else { + npad = 0; + ngps = 0; + gps = null; + baro_speed = 0; + time_change = 0; + } + + time = tick / 100.0; + + if (cur.new_gps && (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_idle)) { + + /* Track consecutive 'good' gps reports, waiting for 10 of them */ + if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) + npad++; + else + npad = 0; + + /* Average GPS data while on the pad */ + if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) { + if (ngps > 1) { + /* filter pad position */ + pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0; + pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0; + pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0; + } else { + pad_lat = data.gps.lat; + pad_lon = data.gps.lon; + pad_alt = data.gps.alt; + } + ngps++; + } + } + + gps_waiting = MIN_PAD_SAMPLES - npad; + if (gps_waiting < 0) + gps_waiting = 0; + + gps_ready = gps_waiting == 0; + + ascent = (AltosLib.ao_flight_boost <= state && + state <= AltosLib.ao_flight_coast); + boost = (AltosLib.ao_flight_boost == state); + + /* Only look at accelerometer data under boost */ + if (boost && acceleration > max_acceleration) + max_acceleration = acceleration; + if (boost && speed > max_speed) + max_speed = speed; + if (boost && baro_speed > max_baro_speed) + max_baro_speed = baro_speed; + + if (height > max_height) + max_height = height; + if (data.gps != null) { + if (gps == null || !gps.locked || data.gps.locked) + gps = data.gps; + if (ngps > 0 && gps.locked) { + from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); + } + } + elevation = 0; + range = -1; + if (ngps > 0) { + gps_height = gps.alt - pad_alt; + if (from_pad != null) { + elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; + range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); + } + } else { + gps_height = 0; + } + } + + public AltosState(AltosRecord cur) { + init(cur, null); + } + + public AltosState (AltosRecord cur, AltosState prev) { + init(cur, prev); + } +} -- cgit v1.2.3 From 5270a0f1416baef5fde08547c6c98d97f973ae95 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 22:35:41 -0800 Subject: altosui: Move telemetry reader &c to altoslib Move all of the device and file reading code into altoslib Signed-off-by: Keith Packard --- altosui/AltosFile.java | 45 -------- altosui/AltosFlightReader.java | 50 -------- altosui/AltosLog.java | 127 --------------------- altosui/AltosReplayReader.java | 62 ---------- altosui/AltosScanUI.java | 6 +- altosui/AltosSerial.java | 1 + altosui/AltosTelemetryReader.java | 120 ------------------- altosui/AltosUI.java | 2 +- altosui/Makefile.am | 6 - altosui/altoslib/Makefile.am | 5 + .../src/org/altusmetrum/AltosLib/AltosFile.java | 44 +++++++ .../altusmetrum/AltosLib/AltosFlightReader.java | 49 ++++++++ .../src/org/altusmetrum/AltosLib/AltosLink.java | 5 +- .../src/org/altusmetrum/AltosLib/AltosLog.java | 126 ++++++++++++++++++++ .../altusmetrum/AltosLib/AltosReplayReader.java | 56 +++++++++ .../altusmetrum/AltosLib/AltosTelemetryReader.java | 118 +++++++++++++++++++ 16 files changed, 406 insertions(+), 416 deletions(-) delete mode 100644 altosui/AltosFile.java delete mode 100644 altosui/AltosFlightReader.java delete mode 100644 altosui/AltosLog.java delete mode 100644 altosui/AltosReplayReader.java delete mode 100644 altosui/AltosTelemetryReader.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java create mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java (limited to 'altosui') diff --git a/altosui/AltosFile.java b/altosui/AltosFile.java deleted file mode 100644 index 4cf7de3c..00000000 --- a/altosui/AltosFile.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.io.File; -import java.util.*; -import org.altusmetrum.AltosLib.*; - -class AltosFile extends File { - - public AltosFile(int year, int month, int day, int serial, int flight, String extension) { - super (AltosUIPreferences.logdir(), - String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", - year, month, day, serial, flight, extension)); - } - - public AltosFile(int serial, int flight, String extension) { - this(Calendar.getInstance().get(Calendar.YEAR), - Calendar.getInstance().get(Calendar.MONTH) + 1, - Calendar.getInstance().get(Calendar.DAY_OF_MONTH), - serial, - flight, - extension); - } - - public AltosFile(AltosRecord telem) { - this(telem.serial, telem.flight, "telem"); - } -} diff --git a/altosui/AltosFlightReader.java b/altosui/AltosFlightReader.java deleted file mode 100644 index 1ac9f848..00000000 --- a/altosui/AltosFlightReader.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; -import java.io.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -public class AltosFlightReader { - String name; - - int serial; - - void init() { } - - AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } - - void close(boolean interrupted) { } - - void set_frequency(double frequency) throws InterruptedException, TimeoutException { } - - void save_frequency() { } - - void set_telemetry(int telemetry) { } - - void save_telemetry() { } - - void update(AltosState state) throws InterruptedException { } - - boolean supports_telemetry(int telemetry) { return false; } - - File backing_file() { return null; } -} diff --git a/altosui/AltosLog.java b/altosui/AltosLog.java deleted file mode 100644 index 740f0be6..00000000 --- a/altosui/AltosLog.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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 altosui; - -import java.io.*; -import java.lang.*; -import java.util.*; -import java.text.ParseException; -import java.util.concurrent.LinkedBlockingQueue; -import org.altusmetrum.AltosLib.*; - -/* - * This creates a thread to capture telemetry data and write it to - * a log file - */ -class AltosLog implements Runnable { - - LinkedBlockingQueue input_queue; - LinkedBlockingQueue pending_queue; - int serial; - int flight; - FileWriter log_file; - Thread log_thread; - AltosFile file; - - private void close_log_file() { - if (log_file != null) { - try { - log_file.close(); - } catch (IOException io) { - } - log_file = null; - } - } - - void close() { - close_log_file(); - if (log_thread != null) { - log_thread.interrupt(); - log_thread = null; - } - } - - File file() { - return file; - } - - boolean open (AltosRecord telem) throws IOException { - AltosFile a = new AltosFile(telem); - - System.out.printf("open %s\n", a.toString()); - log_file = new FileWriter(a, true); - if (log_file != null) { - while (!pending_queue.isEmpty()) { - try { - String s = pending_queue.take(); - log_file.write(s); - log_file.write('\n'); - } catch (InterruptedException ie) { - } - } - log_file.flush(); - file = a; - } - return log_file != null; - } - - public void run () { - try { - AltosRecord previous = null; - for (;;) { - AltosLine line = input_queue.take(); - if (line.line == null) - continue; - try { - AltosRecord telem = AltosTelemetry.parse(line.line, previous); - if (telem.serial != 0 && telem.flight != 0 && - (telem.serial != serial || telem.flight != flight || log_file == null)) - { - close_log_file(); - serial = telem.serial; - flight = telem.flight; - open(telem); - } - previous = telem; - } catch (ParseException pe) { - } catch (AltosCRCException ce) { - } - if (log_file != null) { - log_file.write(line.line); - log_file.write('\n'); - log_file.flush(); - } else - pending_queue.put(line.line); - } - } catch (InterruptedException ie) { - } catch (IOException ie) { - } - close(); - } - - public AltosLog (AltosSerial s) { - pending_queue = new LinkedBlockingQueue (); - input_queue = new LinkedBlockingQueue (); - s.add_monitor(input_queue); - serial = -1; - flight = -1; - log_file = null; - log_thread = new Thread(this); - log_thread.start(); - } -} diff --git a/altosui/AltosReplayReader.java b/altosui/AltosReplayReader.java deleted file mode 100644 index f92c0328..00000000 --- a/altosui/AltosReplayReader.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; -import org.altusmetrum.AltosLib.*; - -/* - * Open an existing telemetry file and replay it in realtime - */ - -public class AltosReplayReader extends AltosFlightReader { - Iterator iterator; - File file; - - public AltosRecord read() { - if (iterator.hasNext()) - return iterator.next(); - return null; - } - - public void close (boolean interrupted) { - } - - void update(AltosState state) throws InterruptedException { - /* Make it run in realtime after the rocket leaves the pad */ - if (state.state > Altos.ao_flight_pad) - Thread.sleep((int) (Math.min(state.time_change,10) * 1000)); - } - - public File backing_file() { return file; } - - public AltosReplayReader(Iterator in_iterator, File in_file) { - iterator = in_iterator; - file = in_file; - name = file.getName(); - } -} diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 1be8aa26..44eeda6d 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -208,7 +208,7 @@ public class AltosScanUI } void next() throws InterruptedException, TimeoutException { - reader.serial.set_monitor(false); + reader.set_monitor(false); Thread.sleep(100); ++frequency_index; if (frequency_index >= frequencies.length || @@ -224,7 +224,7 @@ public class AltosScanUI } set_frequency(); set_label(); - reader.serial.set_monitor(true); + reader.set_monitor(true); } @@ -312,7 +312,7 @@ public class AltosScanUI if (device == null) return false; try { - reader = new AltosTelemetryReader(device); + reader = new AltosTelemetryReader(new AltosSerial(device)); set_frequency(); set_telemetry(); try { diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index cc384586..54cdcba7 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -396,6 +396,7 @@ public class AltosSerial extends AltosLink implements Runnable { device = in_device; frame = null; serial = device.getSerial(); + name = device.toShortString(); open(); } } diff --git a/altosui/AltosTelemetryReader.java b/altosui/AltosTelemetryReader.java deleted file mode 100644 index dc7e4a75..00000000 --- a/altosui/AltosTelemetryReader.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 altosui; - -import java.lang.*; -import java.text.*; -import java.io.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -class AltosTelemetryReader extends AltosFlightReader { - AltosDevice device; - AltosSerial serial; - AltosLog log; - AltosRecord previous; - double frequency; - int telemetry; - - LinkedBlockingQueue telem; - - AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { - AltosLine l = telem.take(); - if (l.line == null) - throw new IOException("IO error"); - AltosRecord next = AltosTelemetry.parse(l.line, previous); - previous = next; - return next; - } - - void flush() { - telem.clear(); - } - - void close(boolean interrupted) { - serial.remove_monitor(telem); - log.close(); - serial.close(); - } - - public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - serial.set_radio_frequency(frequency); - } - - public boolean supports_telemetry(int telemetry) { - - try { - /* Version 1.0 or later firmware supports all telemetry formats */ - if (serial.config_data().compare_version("1.0") >= 0) - return true; - - /* Version 0.9 firmware only supports 0.9 telemetry */ - if (serial.config_data().compare_version("0.9") >= 0) { - if (telemetry == Altos.ao_telemetry_0_9) - return true; - else - return false; - } - - /* Version 0.8 firmware only supports 0.8 telemetry */ - if (telemetry == Altos.ao_telemetry_0_8) - return true; - else - return false; - } catch (InterruptedException ie) { - return true; - } catch (TimeoutException te) { - return true; - } - } - - void save_frequency() { - AltosPreferences.set_frequency(device.getSerial(), frequency); - } - - void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - serial.set_telemetry(telemetry); - } - - void save_telemetry() { - AltosPreferences.set_telemetry(device.getSerial(), telemetry); - } - - File backing_file() { - return log.file(); - } - - public AltosTelemetryReader (AltosDevice in_device) - throws FileNotFoundException, AltosSerialInUseException, IOException, InterruptedException, TimeoutException { - device = in_device; - serial = new AltosSerial(device); - log = new AltosLog(serial); - name = device.toShortString(); - previous = null; - - telem = new LinkedBlockingQueue(); - frequency = AltosPreferences.frequency(device.getSerial()); - set_frequency(frequency); - telemetry = AltosPreferences.telemetry(device.getSerial()); - set_telemetry(telemetry); - serial.set_callsign(AltosUIPreferences.callsign()); - serial.add_monitor(telem); - } -} diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 25c6c36b..538f8734 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -48,7 +48,7 @@ public class AltosUI extends AltosFrame { void telemetry_window(AltosDevice device) { try { - AltosFlightReader reader = new AltosTelemetryReader(device); + AltosFlightReader reader = new AltosTelemetryReader(new AltosSerial(device)); if (reader != null) new AltosFlightUI(voice, reader, device.getSerial()); } catch (FileNotFoundException ee) { diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 270fe114..2946890b 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -49,12 +49,10 @@ altosui_JAVA = \ AltosIMU.java \ AltosMag.java \ AltosEepromSelect.java \ - AltosFile.java \ AltosFlash.java \ AltosFlashUI.java \ AltosFlightDisplay.java \ AltosFlightInfoTableModel.java \ - AltosFlightReader.java \ AltosFlightStats.java \ AltosFlightStatsTable.java \ AltosFlightStatus.java \ @@ -74,12 +72,9 @@ altosui_JAVA = \ AltosLanded.java \ AltosLed.java \ AltosLights.java \ - AltosLog.java \ AltosPad.java \ AltosUIPreferences.java \ AltosReader.java \ - AltosTelemetryReader.java \ - AltosReplayReader.java \ AltosRomconfig.java \ AltosRomconfigUI.java \ AltosScanUI.java \ @@ -90,7 +85,6 @@ altosui_JAVA = \ AltosSiteMapPreload.java \ AltosSiteMapCache.java \ AltosSiteMapTile.java \ - AltosTelemetryReader.java \ AltosUI.java \ AltosUIListener.java \ AltosFrame.java \ diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am index 40ec3af8..2ddd24e6 100644 --- a/altosui/altoslib/Makefile.am +++ b/altosui/altoslib/Makefile.am @@ -19,21 +19,26 @@ AltosLib_JAVA = \ $(SRC)/AltosEepromLog.java \ $(SRC)/AltosEepromRecord.java \ $(SRC)/AltosEepromTeleScience.java \ + $(SRC)/AltosFile.java \ + $(SRC)/AltosFlightReader.java \ $(SRC)/AltosFrequency.java \ $(SRC)/AltosGPS.java \ $(SRC)/AltosGPSSat.java \ $(SRC)/AltosGreatCircle.java \ $(SRC)/AltosLine.java \ $(SRC)/AltosLink.java \ + $(SRC)/AltosLog.java \ $(SRC)/AltosParse.java \ $(SRC)/AltosPreferences.java \ $(SRC)/AltosRecordCompanion.java \ $(SRC)/AltosRecordIterable.java \ $(SRC)/AltosRecord.java \ + $(SRC)/AltosReplayReader.java \ $(SRC)/AltosState.java \ $(SRC)/AltosTelemetry.java \ $(SRC)/AltosTelemetryIterable.java \ $(SRC)/AltosTelemetryMap.java \ + $(SRC)/AltosTelemetryReader.java \ $(SRC)/AltosTelemetryRecordCompanion.java \ $(SRC)/AltosTelemetryRecordConfiguration.java \ $(SRC)/AltosTelemetryRecordGeneral.java \ diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java new file mode 100644 index 00000000..d2e4f2f7 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java @@ -0,0 +1,44 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.io.File; +import java.util.*; + +public class AltosFile extends File { + + public AltosFile(int year, int month, int day, int serial, int flight, String extension) { + super (AltosPreferences.logdir(), + String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", + year, month, day, serial, flight, extension)); + } + + public AltosFile(int serial, int flight, String extension) { + this(Calendar.getInstance().get(Calendar.YEAR), + Calendar.getInstance().get(Calendar.MONTH) + 1, + Calendar.getInstance().get(Calendar.DAY_OF_MONTH), + serial, + flight, + extension); + } + + public AltosFile(AltosRecord telem) { + this(telem.serial, telem.flight, "telem"); + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java new file mode 100644 index 00000000..3fdea469 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java @@ -0,0 +1,49 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +public class AltosFlightReader { + public String name; + + public int serial; + + public void init() { } + + public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } + + public void close(boolean interrupted) { } + + public void set_frequency(double frequency) throws InterruptedException, TimeoutException { } + + public void save_frequency() { } + + public void set_telemetry(int telemetry) { } + + public void save_telemetry() { } + + public void update(AltosState state) throws InterruptedException { } + + public boolean supports_telemetry(int telemetry) { return false; } + + public File backing_file() { return null; } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java index 49585975..9b80e916 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java @@ -24,6 +24,8 @@ import java.util.*; import java.text.*; public abstract class AltosLink { + public abstract void print(String data); + public abstract void close(); public static boolean debug = false; public static void set_debug(boolean in_debug) { debug = in_debug; } @@ -43,8 +45,6 @@ public abstract class AltosLink { set_monitor(false); } - public abstract void print(String data); - public void printf(String format, Object ... arguments) { String line = String.format(format, arguments); if (debug) @@ -207,6 +207,7 @@ public abstract class AltosLink { public boolean remote; public int serial; + public String name; public void start_remote() throws TimeoutException, InterruptedException { if (debug) diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java new file mode 100644 index 00000000..08c45ca8 --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java @@ -0,0 +1,126 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.text.ParseException; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * This creates a thread to capture telemetry data and write it to + * a log file + */ +class AltosLog implements Runnable { + + LinkedBlockingQueue input_queue; + LinkedBlockingQueue pending_queue; + int serial; + int flight; + FileWriter log_file; + Thread log_thread; + AltosFile file; + + private void close_log_file() { + if (log_file != null) { + try { + log_file.close(); + } catch (IOException io) { + } + log_file = null; + } + } + + void close() { + close_log_file(); + if (log_thread != null) { + log_thread.interrupt(); + log_thread = null; + } + } + + File file() { + return file; + } + + boolean open (AltosRecord telem) throws IOException { + AltosFile a = new AltosFile(telem); + + System.out.printf("open %s\n", a.toString()); + log_file = new FileWriter(a, true); + if (log_file != null) { + while (!pending_queue.isEmpty()) { + try { + String s = pending_queue.take(); + log_file.write(s); + log_file.write('\n'); + } catch (InterruptedException ie) { + } + } + log_file.flush(); + file = a; + } + return log_file != null; + } + + public void run () { + try { + AltosRecord previous = null; + for (;;) { + AltosLine line = input_queue.take(); + if (line.line == null) + continue; + try { + AltosRecord telem = AltosTelemetry.parse(line.line, previous); + if (telem.serial != 0 && telem.flight != 0 && + (telem.serial != serial || telem.flight != flight || log_file == null)) + { + close_log_file(); + serial = telem.serial; + flight = telem.flight; + open(telem); + } + previous = telem; + } catch (ParseException pe) { + } catch (AltosCRCException ce) { + } + if (log_file != null) { + log_file.write(line.line); + log_file.write('\n'); + log_file.flush(); + } else + pending_queue.put(line.line); + } + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + close(); + } + + public AltosLog (AltosLink link) { + pending_queue = new LinkedBlockingQueue (); + input_queue = new LinkedBlockingQueue (); + link.add_monitor(input_queue); + serial = -1; + flight = -1; + log_file = null; + log_thread = new Thread(this); + log_thread.start(); + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java new file mode 100644 index 00000000..1585f9eb --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java @@ -0,0 +1,56 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * Open an existing telemetry file and replay it in realtime + */ + +public class AltosReplayReader extends AltosFlightReader { + Iterator iterator; + File file; + + public AltosRecord read() { + if (iterator.hasNext()) + return iterator.next(); + return null; + } + + public void close (boolean interrupted) { + } + + public void update(AltosState state) throws InterruptedException { + /* Make it run in realtime after the rocket leaves the pad */ + if (state.state > AltosLib.ao_flight_pad) + Thread.sleep((int) (Math.min(state.time_change,10) * 1000)); + } + + public File backing_file() { return file; } + + public AltosReplayReader(Iterator in_iterator, File in_file) { + iterator = in_iterator; + file = in_file; + name = file.getName(); + } +} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java new file mode 100644 index 00000000..2cc2822a --- /dev/null +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java @@ -0,0 +1,118 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +public class AltosTelemetryReader extends AltosFlightReader { + AltosLink link; + AltosLog log; + AltosRecord previous; + double frequency; + int telemetry; + + LinkedBlockingQueue telem; + + public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { + AltosLine l = telem.take(); + if (l.line == null) + throw new IOException("IO error"); + AltosRecord next = AltosTelemetry.parse(l.line, previous); + previous = next; + return next; + } + + public void flush() { + telem.clear(); + } + + public void close(boolean interrupted) { + link.remove_monitor(telem); + log.close(); + link.close(); + } + + public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + link.set_radio_frequency(frequency); + } + + public boolean supports_telemetry(int telemetry) { + + try { + /* Version 1.0 or later firmware supports all telemetry formats */ + if (serial.config_data().compare_version("1.0") >= 0) + return true; + + /* Version 0.9 firmware only supports 0.9 telemetry */ + if (serial.config_data().compare_version("0.9") >= 0) { + if (telemetry == Altos.ao_telemetry_0_9) + return true; + else + return false; + } + + /* Version 0.8 firmware only supports 0.8 telemetry */ + if (telemetry == Altos.ao_telemetry_0_8) + return true; + else + return false; + } catch (InterruptedException ie) { + return true; + } catch (TimeoutException te) { + return true; + } + } + + public void save_frequency() { + AltosPreferences.set_frequency(link.serial, frequency); + } + + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + link.set_telemetry(telemetry); + } + + public void save_telemetry() { + AltosPreferences.set_telemetry(link.serial, telemetry); + } + + public void set_monitor(boolean monitor) { + link.set_monitor(monitor); + } + + public File backing_file() { + return log.file(); + } + + public AltosTelemetryReader (AltosLink in_link) + throws IOException, InterruptedException, TimeoutException { + log = new AltosLog(link); + name = link.name; + previous = null; + telem = new LinkedBlockingQueue(); + frequency = AltosPreferences.frequency(link.serial); + set_frequency(frequency); + telemetry = AltosPreferences.telemetry(link.serial); + set_telemetry(telemetry); + link.add_monitor(telem); + } +} -- cgit v1.2.3 From 9fb15d397890c7e78bf3c1438f142f62bfc2bd35 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 22:41:48 -0800 Subject: altosui: Remove unused files Left around from development, these aren't useful. Signed-off-by: Keith Packard --- altosui/AltosReader.java | 29 ----------------------------- altosui/AltosSerialMonitor.java | 22 ---------------------- altosui/Makefile.am | 2 -- 3 files changed, 53 deletions(-) delete mode 100644 altosui/AltosReader.java delete mode 100644 altosui/AltosSerialMonitor.java (limited to 'altosui') diff --git a/altosui/AltosReader.java b/altosui/AltosReader.java deleted file mode 100644 index aafd5f81..00000000 --- a/altosui/AltosReader.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 altosui; - -import java.io.*; -import java.util.*; -import java.text.*; -import org.altusmetrum.AltosLib.*; - -public class AltosReader { - public AltosRecord read() throws IOException, ParseException { return null; } - public void close() { } - public void write_comments(PrintStream out) { } -} diff --git a/altosui/AltosSerialMonitor.java b/altosui/AltosSerialMonitor.java deleted file mode 100644 index ad0e9295..00000000 --- a/altosui/AltosSerialMonitor.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 altosui; - -public interface AltosSerialMonitor { - void data(String data); -} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 2946890b..7a3c53e7 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -74,13 +74,11 @@ altosui_JAVA = \ AltosLights.java \ AltosPad.java \ AltosUIPreferences.java \ - AltosReader.java \ AltosRomconfig.java \ AltosRomconfigUI.java \ AltosScanUI.java \ AltosSerial.java \ AltosSerialInUseException.java \ - AltosSerialMonitor.java \ AltosSiteMap.java \ AltosSiteMapPreload.java \ AltosSiteMapCache.java \ -- cgit v1.2.3 From 02b53b7f592b78b2fec4f4a17b6b3e114d2bf3c5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 22:42:18 -0800 Subject: altosui: Fix AltosTelemetryReader move Lost the provided link value causing a crash. Signed-off-by: Keith Packard --- altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java index 2cc2822a..67ac1b65 100644 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java +++ b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java @@ -105,6 +105,7 @@ public class AltosTelemetryReader extends AltosFlightReader { public AltosTelemetryReader (AltosLink in_link) throws IOException, InterruptedException, TimeoutException { + link = in_link; log = new AltosLog(link); name = link.name; previous = null; -- cgit v1.2.3 From d6df16525927d8096d1c0cccf4c86bf4c6599d53 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Jan 2012 22:43:48 -0800 Subject: Add altoslib/.gitignore --- altosui/altoslib/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 altosui/altoslib/.gitignore (limited to 'altosui') diff --git a/altosui/altoslib/.gitignore b/altosui/altoslib/.gitignore new file mode 100644 index 00000000..ad2f8cbf --- /dev/null +++ b/altosui/altoslib/.gitignore @@ -0,0 +1 @@ +classAltosLib.stamp -- cgit v1.2.3 From 81465a20049da40cd8d3cda920d6585ffe87bfe3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 4 Jan 2012 20:28:42 -0800 Subject: altosui: Move java altoslib to top level This will be shared with other (android) java code. Signed-off-by: Keith Packard --- Makefile.am | 2 +- altoslib/.gitignore | 1 + altoslib/Makefile.am | 69 +++ .../altusmetrum/AltosLib/AltosCRCException.java | 26 + .../org/altusmetrum/AltosLib/AltosConfigData.java | 184 ++++++++ .../src/org/altusmetrum/AltosLib/AltosConvert.java | 259 ++++++++++ .../org/altusmetrum/AltosLib/AltosEepromChunk.java | 102 ++++ .../altusmetrum/AltosLib/AltosEepromIterable.java | 475 +++++++++++++++++++ .../org/altusmetrum/AltosLib/AltosEepromLog.java | 100 ++++ .../altusmetrum/AltosLib/AltosEepromRecord.java | 139 ++++++ .../AltosLib/AltosEepromTeleScience.java | 59 +++ .../src/org/altusmetrum/AltosLib/AltosFile.java | 44 ++ .../altusmetrum/AltosLib/AltosFlightReader.java | 49 ++ .../org/altusmetrum/AltosLib/AltosFrequency.java | 48 ++ .../src/org/altusmetrum/AltosLib/AltosGPS.java | 248 ++++++++++ .../src/org/altusmetrum/AltosLib/AltosGPSSat.java | 32 ++ .../org/altusmetrum/AltosLib/AltosGreatCircle.java | 101 ++++ .../src/org/altusmetrum/AltosLib/AltosLib.java | 348 ++++++++++++++ .../src/org/altusmetrum/AltosLib/AltosLine.java | 30 ++ .../src/org/altusmetrum/AltosLib/AltosLink.java | 238 ++++++++++ .../src/org/altusmetrum/AltosLib/AltosLog.java | 126 +++++ .../src/org/altusmetrum/AltosLib/AltosParse.java | 79 ++++ .../org/altusmetrum/AltosLib/AltosPreferences.java | 365 +++++++++++++++ .../src/org/altusmetrum/AltosLib/AltosRecord.java | 319 +++++++++++++ .../altusmetrum/AltosLib/AltosRecordCompanion.java | 38 ++ .../altusmetrum/AltosLib/AltosRecordIterable.java | 29 ++ .../altusmetrum/AltosLib/AltosReplayReader.java | 56 +++ .../src/org/altusmetrum/AltosLib/AltosState.java | 210 +++++++++ .../org/altusmetrum/AltosLib/AltosTelemetry.java | 241 ++++++++++ .../AltosLib/AltosTelemetryIterable.java | 109 +++++ .../altusmetrum/AltosLib/AltosTelemetryMap.java | 63 +++ .../altusmetrum/AltosLib/AltosTelemetryReader.java | 119 +++++ .../altusmetrum/AltosLib/AltosTelemetryRecord.java | 126 +++++ .../AltosLib/AltosTelemetryRecordCompanion.java | 52 ++ .../AltosTelemetryRecordConfiguration.java | 64 +++ .../AltosLib/AltosTelemetryRecordGeneral.java | 43 ++ .../AltosLib/AltosTelemetryRecordLegacy.java | 521 +++++++++++++++++++++ .../AltosLib/AltosTelemetryRecordLocation.java | 93 ++++ .../AltosLib/AltosTelemetryRecordRaw.java | 77 +++ .../AltosLib/AltosTelemetryRecordSatellite.java | 52 ++ .../AltosLib/AltosTelemetryRecordSensor.java | 104 ++++ altosui/Makefile.am | 8 +- altosui/altoslib/.gitignore | 1 - altosui/altoslib/Makefile.am | 69 --- .../altusmetrum/AltosLib/AltosCRCException.java | 26 - .../org/altusmetrum/AltosLib/AltosConfigData.java | 184 -------- .../src/org/altusmetrum/AltosLib/AltosConvert.java | 259 ---------- .../org/altusmetrum/AltosLib/AltosEepromChunk.java | 102 ---- .../altusmetrum/AltosLib/AltosEepromIterable.java | 475 ------------------- .../org/altusmetrum/AltosLib/AltosEepromLog.java | 100 ---- .../altusmetrum/AltosLib/AltosEepromRecord.java | 139 ------ .../AltosLib/AltosEepromTeleScience.java | 59 --- .../src/org/altusmetrum/AltosLib/AltosFile.java | 44 -- .../altusmetrum/AltosLib/AltosFlightReader.java | 49 -- .../org/altusmetrum/AltosLib/AltosFrequency.java | 48 -- .../src/org/altusmetrum/AltosLib/AltosGPS.java | 248 ---------- .../src/org/altusmetrum/AltosLib/AltosGPSSat.java | 32 -- .../org/altusmetrum/AltosLib/AltosGreatCircle.java | 101 ---- .../src/org/altusmetrum/AltosLib/AltosLib.java | 348 -------------- .../src/org/altusmetrum/AltosLib/AltosLine.java | 30 -- .../src/org/altusmetrum/AltosLib/AltosLink.java | 238 ---------- .../src/org/altusmetrum/AltosLib/AltosLog.java | 126 ----- .../src/org/altusmetrum/AltosLib/AltosParse.java | 79 ---- .../org/altusmetrum/AltosLib/AltosPreferences.java | 365 --------------- .../src/org/altusmetrum/AltosLib/AltosRecord.java | 319 ------------- .../altusmetrum/AltosLib/AltosRecordCompanion.java | 38 -- .../altusmetrum/AltosLib/AltosRecordIterable.java | 29 -- .../altusmetrum/AltosLib/AltosReplayReader.java | 56 --- .../src/org/altusmetrum/AltosLib/AltosState.java | 210 --------- .../org/altusmetrum/AltosLib/AltosTelemetry.java | 241 ---------- .../AltosLib/AltosTelemetryIterable.java | 109 ----- .../altusmetrum/AltosLib/AltosTelemetryMap.java | 63 --- .../altusmetrum/AltosLib/AltosTelemetryReader.java | 119 ----- .../altusmetrum/AltosLib/AltosTelemetryRecord.java | 126 ----- .../AltosLib/AltosTelemetryRecordCompanion.java | 52 -- .../AltosTelemetryRecordConfiguration.java | 64 --- .../AltosLib/AltosTelemetryRecordGeneral.java | 43 -- .../AltosLib/AltosTelemetryRecordLegacy.java | 521 --------------------- .../AltosLib/AltosTelemetryRecordLocation.java | 93 ---- .../AltosLib/AltosTelemetryRecordRaw.java | 77 --- .../AltosLib/AltosTelemetryRecordSatellite.java | 52 -- .../AltosLib/AltosTelemetryRecordSensor.java | 104 ---- configure.ac | 2 +- 83 files changed, 5444 insertions(+), 5444 deletions(-) create mode 100644 altoslib/.gitignore create mode 100644 altoslib/Makefile.am create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFile.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLib.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLine.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLink.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosLog.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosParse.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosState.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java create mode 100644 altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java delete mode 100644 altosui/altoslib/.gitignore delete mode 100644 altosui/altoslib/Makefile.am delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosState.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java delete mode 100644 altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java (limited to 'altosui') diff --git a/Makefile.am b/Makefile.am index e1ee30a3..18845551 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=src doc altosui ao-tools ao-utils +SUBDIRS=src doc altoslib altosui ao-tools ao-utils EXTRA_DIST = ChangeLog diff --git a/altoslib/.gitignore b/altoslib/.gitignore new file mode 100644 index 00000000..ad2f8cbf --- /dev/null +++ b/altoslib/.gitignore @@ -0,0 +1 @@ +classAltosLib.stamp diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am new file mode 100644 index 00000000..2ddd24e6 --- /dev/null +++ b/altoslib/Makefile.am @@ -0,0 +1,69 @@ +AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation + +JAVAROOT=bin + +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="bin:$(FREETTS)/*:/usr/share/java/*" + +SRC=src/org/altusmetrum/AltosLib +BIN=bin/org/altusmetrum/AltosLib + +AltosLibdir = $(datadir)/java + +AltosLib_JAVA = \ + $(SRC)/AltosLib.java \ + $(SRC)/AltosConfigData.java \ + $(SRC)/AltosConvert.java \ + $(SRC)/AltosCRCException.java \ + $(SRC)/AltosEepromChunk.java \ + $(SRC)/AltosEepromIterable.java \ + $(SRC)/AltosEepromLog.java \ + $(SRC)/AltosEepromRecord.java \ + $(SRC)/AltosEepromTeleScience.java \ + $(SRC)/AltosFile.java \ + $(SRC)/AltosFlightReader.java \ + $(SRC)/AltosFrequency.java \ + $(SRC)/AltosGPS.java \ + $(SRC)/AltosGPSSat.java \ + $(SRC)/AltosGreatCircle.java \ + $(SRC)/AltosLine.java \ + $(SRC)/AltosLink.java \ + $(SRC)/AltosLog.java \ + $(SRC)/AltosParse.java \ + $(SRC)/AltosPreferences.java \ + $(SRC)/AltosRecordCompanion.java \ + $(SRC)/AltosRecordIterable.java \ + $(SRC)/AltosRecord.java \ + $(SRC)/AltosReplayReader.java \ + $(SRC)/AltosState.java \ + $(SRC)/AltosTelemetry.java \ + $(SRC)/AltosTelemetryIterable.java \ + $(SRC)/AltosTelemetryMap.java \ + $(SRC)/AltosTelemetryReader.java \ + $(SRC)/AltosTelemetryRecordCompanion.java \ + $(SRC)/AltosTelemetryRecordConfiguration.java \ + $(SRC)/AltosTelemetryRecordGeneral.java \ + $(SRC)/AltosTelemetryRecord.java \ + $(SRC)/AltosTelemetryRecordLegacy.java \ + $(SRC)/AltosTelemetryRecordLocation.java \ + $(SRC)/AltosTelemetryRecordRaw.java \ + $(SRC)/AltosTelemetryRecordSatellite.java \ + $(SRC)/AltosTelemetryRecordSensor.java + +JAR=AltosLib.jar + +all-local: $(JAR) + +clean-local: + -rm -rf bin $(JAR) + +install-AltosLibJAVA: $(JAR) + @$(NORMAL_INSTALL) + test -z "$(AltosLibdir)" || $(MKDIR_P) "$(DESTDIR)$(AltosLibdir)" + echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(AltosLibdir)/$(JAR)"; \ + $(INSTALL_DATA) "$<" "$(DESTDIR)$(AltosLibdir)" + +bin: + mkdir -p bin + +$(JAR): classAltosLib.stamp + jar cf $@ -C bin org diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java b/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java new file mode 100644 index 00000000..101c5363 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java @@ -0,0 +1,26 @@ +/* + * 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.AltosLib; + +public class AltosCRCException extends Exception { + public int rssi; + + public AltosCRCException (int in_rssi) { + rssi = in_rssi; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java b/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java new file mode 100644 index 00000000..4ad4e58a --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java @@ -0,0 +1,184 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; + +public class AltosConfigData implements Iterable { + + /* Version information */ + public String manufacturer; + public String product; + public String version; + public int log_format; + public int serial; + + /* Strings returned */ + public LinkedList lines; + + /* Config information */ + public int config_major; + public int config_minor; + public int main_deploy; + public int apogee_delay; + public int radio_channel; + public int radio_setting; + public int radio_frequency; + public String callsign; + public int accel_cal_plus, accel_cal_minus; + public int radio_calibration; + public int flight_log_max; + public int ignite_mode; + public int stored_flight; + public int storage_size; + public int storage_erase_unit; + + public static String get_string(String line, String label) throws ParseException { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + return quoted; + } + throw new ParseException("mismatch", 0); + } + + public static int get_int(String line, String label) throws NumberFormatException, ParseException { + if (line.startsWith(label)) { + String tail = line.substring(label.length()).trim(); + String[] tokens = tail.split("\\s+"); + if (tokens.length > 0) + return Integer.parseInt(tokens[0]); + } + throw new ParseException("mismatch", 0); + } + + public Iterator iterator() { + return lines.iterator(); + } + + public int log_available() { + switch (log_format) { + case AltosLib.AO_LOG_FORMAT_TINY: + if (stored_flight == 0) + return 1; + return 0; + default: + if (flight_log_max <= 0) + return 1; + int log_space = storage_size - storage_erase_unit; + int log_used = stored_flight * flight_log_max; + + if (log_used >= log_space) + return 0; + return (log_space - log_used) / flight_log_max; + } + } + + int[] parse_version(String v) { + String[] parts = v.split("\\."); + int r[] = new int[parts.length]; + + for (int i = 0; i < parts.length; i++) { + try { + r[i] = Altos.fromdec(parts[i]); + } catch (NumberFormatException n) { + r[i] = 0; + } + } + + return r; + } + + public int compare_version(String other) { + int[] me = parse_version(version); + int[] them = parse_version(other); + + int l = Math.min(me.length, them.length); + + for (int i = 0; i < l; i++) { + int d = me[i] - them[i]; + if (d != 0) + return d; + } + if (me.length > l) + return 1; + if (them.length > l) + return -1; + return 0; + } + + public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("c s\np\nf\nl\nv\n"); + lines = new LinkedList(); + radio_setting = 0; + radio_frequency = 0; + stored_flight = 0; + for (;;) { + String line = link.get_reply(); + if (line == null) + throw new TimeoutException(); + if (line.contains("Syntax error")) + continue; + lines.add(line); + try { serial = get_int(line, "serial-number"); } catch (Exception e) {} + try { log_format = get_int(line, "log-format"); } catch (Exception e) {} + try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} + try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} + try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} + try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} + try { + radio_frequency = get_int(line, "Frequency:"); + if (radio_frequency < 0) + radio_frequency = 434550; + } catch (Exception e) {} + try { + if (line.startsWith("Accel cal")) { + String[] bits = line.split("\\s+"); + if (bits.length >= 6) { + accel_cal_plus = Integer.parseInt(bits[3]); + accel_cal_minus = Integer.parseInt(bits[5]); + } + } + } catch (Exception e) {} + try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} + try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} + try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} + try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} + try { version = get_string(line,"software-version"); } catch (Exception e) {} + try { product = get_string(line,"product"); } catch (Exception e) {} + + try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} + try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} + try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} + + /* signals the end of the version info */ + if (line.startsWith("software-version")) + break; + } + } + +} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java b/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java new file mode 100644 index 00000000..3527b575 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java @@ -0,0 +1,259 @@ +/* + * 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. + */ + +/* + * Sensor data conversion functions + */ +package org.altusmetrum.AltosLib; + +public class AltosConvert { + /* + * Pressure Sensor Model, version 1.1 + * + * written by Holly Grimes + * + * Uses the International Standard Atmosphere as described in + * "A Quick Derivation relating altitude to air pressure" (version 1.03) + * from the Portland State Aerospace Society, except that the atmosphere + * is divided into layers with each layer having a different lapse rate. + * + * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 + * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ + return 0; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted altitude */ + for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + base_pressure *= Math.pow(base, exponent); + } + base_temperature += delta_z * lapse_rate[layer_number]; + } + + /* calculate the pressure at the inputted altitude */ + delta_z = altitude - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + pressure = base_pressure * Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + pressure = base_pressure * Math.pow(base, exponent); + } + + return pressure; + } + + +/* outputs the altitude associated with the given pressure. the altitude + returned is measured with respect to the mean sea level */ + public static double + pressure_to_altitude(double pressure) + { + + double next_base_temperature = LAYER0_BASE_TEMPERATURE; + double next_base_pressure = LAYER0_BASE_PRESSURE; + + double altitude; + double base_pressure; + double base_temperature; + double base; /* base for function to determine base pressure of next layer */ + double exponent; /* exponent for function to determine base pressure + of next layer */ + double coefficient; + int layer_number; /* identifies layer in the atmosphere */ + int delta_z; /* difference between two altitudes */ + + if (pressure < 0) /* illegal pressure */ + return -1; + if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ + return MAXIMUM_ALTITUDE; + + /* calculate the base temperature and pressure for the atmospheric layer + associated with the inputted pressure. */ + layer_number = -1; + do { + layer_number++; + base_pressure = next_base_pressure; + base_temperature = next_base_temperature; + delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; + if (lapse_rate[layer_number] == 0.0) { + exponent = GRAVITATIONAL_ACCELERATION * delta_z + / AIR_GAS_CONSTANT / base_temperature; + next_base_pressure *= Math.exp(exponent); + } + else { + base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; + exponent = GRAVITATIONAL_ACCELERATION / + (AIR_GAS_CONSTANT * lapse_rate[layer_number]); + next_base_pressure *= Math.pow(base, exponent); + } + next_base_temperature += delta_z * lapse_rate[layer_number]; + } + while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); + + /* calculate the altitude associated with the inputted pressure */ + if (lapse_rate[layer_number] == 0.0) { + coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) + * base_temperature; + altitude = base_altitude[layer_number] + + coefficient * Math.log(pressure / base_pressure); + } + else { + base = pressure / base_pressure; + exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] + / GRAVITATIONAL_ACCELERATION; + coefficient = base_temperature / lapse_rate[layer_number]; + altitude = base_altitude[layer_number] + + coefficient * (Math.pow(base, exponent) - 1); + } + + return altitude; + } + + public static double + cc_battery_to_voltage(double battery) + { + return battery / 32767.0 * 5.0; + } + + public static double + cc_ignitor_to_voltage(double ignite) + { + return ignite / 32767 * 15.0; + } + + public static double radio_to_frequency(int freq, int setting, int cal, int channel) { + double f; + + if (freq > 0) + f = freq / 1000.0; + else { + if (setting <= 0) + setting = cal; + f = 434.550 * setting / cal; + /* Round to nearest 50KHz */ + f = Math.floor (20.0 * f + 0.5) / 20.0; + } + return f + channel * 0.100; + } + + public static int radio_frequency_to_setting(double frequency, int cal) { + double set = frequency / 434.550 * cal; + + return (int) Math.floor (set + 0.5); + } + + public static int radio_frequency_to_channel(double frequency) { + int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); + + if (channel < 0) + channel = 0; + if (channel > 9) + channel = 9; + return channel; + } + + public static double radio_channel_to_frequency(int channel) { + return 434.550 + channel * 0.100; + } + + public static int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + public static double meters_to_feet(double meters) { + return meters * (100 / (2.54 * 12)); + } + + public static double meters_to_mach(double meters) { + return meters / 343; /* something close to mach at usual rocket sites */ + } + + public static double meters_to_g(double meters) { + return meters / 9.80665; + } + + public static int checksum(int[] data, int start, int length) { + int csum = 0x5a; + for (int i = 0; i < length; i++) + csum += data[i + start]; + return csum & 0xff; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java new file mode 100644 index 00000000..6d889723 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java @@ -0,0 +1,102 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +public class AltosEepromChunk { + + public static final int chunk_size = 256; + public static final int per_line = 8; + + public int data[]; + public int address; + public ParseException parse_exception = null; + + int[] ParseHex(String line) { + String[] tokens = line.split("\\s+"); + int[] array = new int[tokens.length]; + + for (int i = 0; i < tokens.length; i++) + try { + array[i] = Integer.parseInt(tokens[i], 16); + } catch (NumberFormatException ne) { + return null; + } + return array; + } + + public int data(int offset) { + return data[offset]; + } + + public int data16(int offset) { + return data[offset] | (data[offset + 1] << 8); + } + + public int data32(int offset) { + return data[offset] | (data[offset + 1] << 8) | + (data[offset+2] << 16) | (data[offset+3] << 24); + } + + public boolean erased(int start, int len) { + for (int i = 0; i < len; i++) + if (data[start+i] != 0xff) + return false; + return true; + } + + public AltosEepromChunk(AltosLink link, int block, boolean flush) + throws TimeoutException, InterruptedException { + + int offset; + + data = new int[chunk_size]; + address = block * chunk_size; + if (flush) + link.flush_input(); + link.printf("e %x\n", block); + + for (offset = 0; offset < chunk_size; offset += per_line) { + try { + String line = link.get_reply(5000); + + if (line == null) + throw new TimeoutException(); + + int[] values = ParseHex(line); + + if (values == null || values.length != per_line + 1) + throw new ParseException(String.format("invalid line %s", line), 0); + if (values[0] != offset) + throw new ParseException(String.format("data address out of sync at 0x%x", + address + offset), 0); + for (int i = 0; i < per_line; i++) + data[offset + i] = values[1 + i]; + } catch (ParseException pe) { + for (int i = 0; i < per_line; i++) + data[offset + i] = 0xff; + if (parse_exception == null) + parse_exception = pe; + } + } + } +} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java new file mode 100644 index 00000000..f1397c7b --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java @@ -0,0 +1,475 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * AltosRecords with an index field so they can be sorted by tick while preserving + * the original ordering for elements with matching ticks + */ +class AltosOrderedRecord extends AltosEepromRecord implements Comparable { + + public int index; + + public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) + throws ParseException { + super(line); + if (prev_tick_valid) { + tick |= (prev_tick & ~0xffff); + if (tick < prev_tick) { + if (prev_tick - tick > 0x8000) + tick += 0x10000; + } else { + if (tick - prev_tick > 0x8000) + tick -= 0x10000; + } + } + index = in_index; + } + + public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { + super(in_cmd, in_tick, in_a, in_b); + index = in_index; + } + + public String toString() { + return String.format("%d.%d %04x %04x %04x", + cmd, index, tick, a, b); + } + + public int compareTo(AltosOrderedRecord o) { + int tick_diff = tick - o.tick; + if (tick_diff != 0) + return tick_diff; + return index - o.index; + } +} + +public class AltosEepromIterable extends AltosRecordIterable { + + static final int seen_flight = 1; + static final int seen_sensor = 2; + static final int seen_temp_volt = 4; + static final int seen_deploy = 8; + static final int seen_gps_time = 16; + static final int seen_gps_lat = 32; + static final int seen_gps_lon = 64; + + static final int seen_basic = seen_flight|seen_sensor; + + boolean has_accel; + boolean has_gps; + boolean has_ignite; + + AltosEepromRecord flight_record; + AltosEepromRecord gps_date_record; + + TreeSet records; + + LinkedList list; + + class EepromState { + int seen; + int n_pad_samples; + double ground_pres; + int gps_tick; + int boost_tick; + int sensor_tick; + + EepromState() { + seen = 0; + n_pad_samples = 0; + ground_pres = 0.0; + gps_tick = 0; + } + } + + void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { + state.tick = record.tick; + switch (record.cmd) { + case AltosLib.AO_LOG_FLIGHT: + eeprom.seen |= seen_flight; + state.ground_accel = record.a; + state.flight_accel = record.a; + state.flight = record.b; + eeprom.boost_tick = record.tick; + break; + case AltosLib.AO_LOG_SENSOR: + state.accel = record.a; + state.pres = record.b; + if (state.state < AltosLib.ao_flight_boost) { + eeprom.n_pad_samples++; + eeprom.ground_pres += state.pres; + state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); + state.flight_pres = state.ground_pres; + } else { + state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; + } + state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; + if ((eeprom.seen & seen_sensor) == 0) + eeprom.sensor_tick = record.tick - 1; + state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick); + eeprom.seen |= seen_sensor; + eeprom.sensor_tick = record.tick; + has_accel = true; + break; + case AltosLib.AO_LOG_PRESSURE: + state.pres = record.b; + state.flight_pres = state.pres; + if (eeprom.n_pad_samples == 0) { + eeprom.n_pad_samples++; + state.ground_pres = state.pres; + } + eeprom.seen |= seen_sensor; + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.temp = record.a; + state.batt = record.b; + eeprom.seen |= seen_temp_volt; + break; + case AltosLib.AO_LOG_DEPLOY: + state.drogue = record.a; + state.main = record.b; + eeprom.seen |= seen_deploy; + has_ignite = true; + break; + case AltosLib.AO_LOG_STATE: + state.state = record.a; + break; + case AltosLib.AO_LOG_GPS_TIME: + eeprom.gps_tick = state.tick; + AltosGPS old = state.gps; + state.gps = new AltosGPS(); + + /* GPS date doesn't get repeated through the file */ + if (old != null) { + state.gps.year = old.year; + state.gps.month = old.month; + state.gps.day = old.day; + } + state.gps.hour = (record.a & 0xff); + state.gps.minute = (record.a >> 8); + state.gps.second = (record.b & 0xff); + + int flags = (record.b >> 8); + state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0; + state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0; + state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> + AltosLib.AO_GPS_NUM_SAT_SHIFT; + state.new_gps = true; + has_gps = true; + break; + case AltosLib.AO_LOG_GPS_LAT: + int lat32 = record.a | (record.b << 16); + state.gps.lat = (double) lat32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_LON: + int lon32 = record.a | (record.b << 16); + state.gps.lon = (double) lon32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_ALT: + state.gps.alt = record.a; + break; + case AltosLib.AO_LOG_GPS_SAT: + if (state.tick == eeprom.gps_tick) { + int svid = record.a; + int c_n0 = record.b >> 8; + state.gps.add_sat(svid, c_n0); + } + break; + case AltosLib.AO_LOG_GPS_DATE: + state.gps.year = (record.a & 0xff) + 2000; + state.gps.month = record.a >> 8; + state.gps.day = record.b & 0xff; + break; + + case AltosLib.AO_LOG_CONFIG_VERSION: + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + break; + case AltosLib.AO_LOG_CALLSIGN: + state.callsign = record.data; + break; + case AltosLib.AO_LOG_ACCEL_CAL: + state.accel_plus_g = record.a; + state.accel_minus_g = record.b; + break; + case AltosLib.AO_LOG_RADIO_CAL: + break; + case AltosLib.AO_LOG_MANUFACTURER: + break; + case AltosLib.AO_LOG_PRODUCT: + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + state.serial = record.a; + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + break; + } + state.seen |= eeprom.seen; + } + + LinkedList make_list() { + LinkedList list = new LinkedList(); + Iterator iterator = records.iterator(); + AltosOrderedRecord record = null; + AltosRecord state = new AltosRecord(); + boolean last_reported = false; + EepromState eeprom = new EepromState(); + + state.state = AltosLib.ao_flight_pad; + state.accel_plus_g = 15758; + state.accel_minus_g = 16294; + + /* Pull in static data from the flight and gps_date records */ + if (flight_record != null) + update_state(state, flight_record, eeprom); + if (gps_date_record != null) + update_state(state, gps_date_record, eeprom); + + while (iterator.hasNext()) { + record = iterator.next(); + if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + } + update_state(state, record, eeprom); + } + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + return list; + } + + public Iterator iterator() { + if (list == null) + list = make_list(); + return list.iterator(); + } + + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; } + + public void write_comments(PrintStream out) { + Iterator iterator = records.iterator(); + out.printf("# Comments\n"); + while (iterator.hasNext()) { + AltosOrderedRecord record = iterator.next(); + switch (record.cmd) { + case AltosLib.AO_LOG_CONFIG_VERSION: + out.printf("# Config version: %s\n", record.data); + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + out.printf("# Main deploy: %s\n", record.a); + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", record.a); + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", record.a); + break; + case AltosLib.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", record.data); + break; + case AltosLib.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", record.a, record.b); + break; + case AltosLib.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", record.a); + break; + case AltosLib.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", record.a); + break; + case AltosLib.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", record.data); + break; + case AltosLib.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", record.data); + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", record.a); + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", record.data); + break; + case Altos.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", record.a); + break; + case Altos.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", record.a); + break; + } + } + } + + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + /* Make sure this looks like a good GPS value */ + if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) + flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); + flags |= AltosLib.AO_GPS_RUNNING; + flags |= AltosLib.AO_GPS_VALID; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + + /* + * Read the whole file, dumping records into a RB tree so + * we can enumerate them in time order -- the eeprom data + * are sometimes out of order with GPS data getting timestamps + * matching the first packet out of the GPS unit but not + * written until the final GPS packet has been received. + */ + public AltosEepromIterable (FileInputStream input) { + records = new TreeSet(); + + AltosOrderedRecord last_gps_time = null; + + int index = 0; + int prev_tick = 0; + boolean prev_tick_valid = false; + boolean missing_time = false; + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) + break; + AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); + if (record == null) + break; + if (record.cmd == AltosLib.AO_LOG_INVALID) + continue; + prev_tick = record.tick; + if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) + prev_tick_valid = true; + if (record.cmd == AltosLib.AO_LOG_FLIGHT) { + flight_record = record; + continue; + } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { + gps_date_record = record; + continue; + } + + /* go back and fix up any missing time values */ + if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedRecord old = iterator.next(); + if (old.cmd == AltosLib.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == AltosLib.AO_LOG_STATE && + record.a == AltosLib.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java new file mode 100644 index 00000000..7fca4bd9 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java @@ -0,0 +1,100 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +/* + * Extract a bit of information from an eeprom-stored flight log. + */ + +public class AltosEepromLog { + public int serial; + public boolean has_flight; + public int flight; + public int start_block; + public int end_block; + + public int year, month, day; + + public boolean selected; + + public AltosEepromLog(AltosConfigData config_data, + AltosLink link, + int in_flight, int in_start_block, + int in_end_block) + throws InterruptedException, TimeoutException { + + int block; + boolean has_date = false; + + flight = in_flight; + if (flight != 0) + has_flight = true; + start_block = in_start_block; + end_block = in_end_block; + serial = config_data.serial; + + /* + * Select all flights for download + */ + selected = true; + + /* + * Look in TeleMetrum log data for date + */ + if (config_data.log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN || + config_data.log_format == AltosLib.AO_LOG_FORMAT_FULL) + { + /* + * Only look in the first two blocks so that this + * process doesn't take a long time + */ + if (in_end_block > in_start_block + 2) + in_end_block = in_start_block + 2; + + for (block = in_start_block; block < in_end_block; block++) { + AltosEepromChunk eechunk = new AltosEepromChunk(link, block, block == in_start_block); + + for (int i = 0; i < eechunk.chunk_size; i += AltosEepromRecord.record_length) { + try { + AltosEepromRecord r = new AltosEepromRecord(eechunk, i); + + if (r.cmd == AltosLib.AO_LOG_FLIGHT) { + flight = r.b; + has_flight = true; + } + if (r.cmd == AltosLib.AO_LOG_GPS_DATE) { + year = 2000 + (r.a & 0xff); + month = (r.a >> 8) & 0xff; + day = (r.b & 0xff); + has_date = true; + } + } catch (ParseException pe) { + } + } + if (has_date && has_flight) + break; + } + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java new file mode 100644 index 00000000..1e845f46 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java @@ -0,0 +1,139 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosEepromRecord { + public int cmd; + public int tick; + public int a; + public int b; + public String data; + public boolean tick_valid; + + public static final int record_length = 8; + + public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException { + + cmd = chunk.data(start); + tick_valid = true; + + tick_valid = !chunk.erased(start, record_length); + if (tick_valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + cmd = AltosLib.AO_LOG_INVALID; + } + + tick = chunk.data16(start + 2); + a = chunk.data16(start + 4); + b = chunk.data16(start + 6); + + data = null; + } + + public AltosEepromRecord (String line) { + tick_valid = false; + tick = 0; + a = 0; + b = 0; + data = null; + if (line == null) { + cmd = AltosLib.AO_LOG_INVALID; + data = ""; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 4) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + tick_valid = true; + a = Integer.parseInt(tokens[2],16); + b = Integer.parseInt(tokens[3],16); + } + } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { + cmd = AltosLib.AO_LOG_CONFIG_VERSION; + data = tokens[2]; + } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { + cmd = AltosLib.AO_LOG_MAIN_DEPLOY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { + cmd = AltosLib.AO_LOG_APOGEE_DELAY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { + cmd = AltosLib.AO_LOG_RADIO_CHANNEL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Callsign:")) { + cmd = AltosLib.AO_LOG_CALLSIGN; + data = tokens[1].replaceAll("\"",""); + } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { + cmd = AltosLib.AO_LOG_ACCEL_CAL; + a = Integer.parseInt(tokens[3]); + b = Integer.parseInt(tokens[5]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { + cmd = AltosLib.AO_LOG_RADIO_CAL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { + cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG; + a = Integer.parseInt(tokens[3]); + } else if (tokens[0].equals("manufacturer")) { + cmd = AltosLib.AO_LOG_MANUFACTURER; + data = tokens[1]; + } else if (tokens[0].equals("product")) { + cmd = AltosLib.AO_LOG_PRODUCT; + data = tokens[1]; + } else if (tokens[0].equals("serial-number")) { + cmd = AltosLib.AO_LOG_SERIAL_NUMBER; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("log-format")) { + cmd = AltosLib.AO_LOG_LOG_FORMAT; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("software-version")) { + cmd = AltosLib.AO_LOG_SOFTWARE_VERSION; + data = tokens[1]; + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } catch (NumberFormatException ne) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } + } + + public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) { + tick_valid = true; + cmd = in_cmd; + tick = in_tick; + a = in_a; + b = in_b; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java new file mode 100644 index 00000000..1758fa34 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java @@ -0,0 +1,59 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosEepromTeleScience { + public int type; + public int tick; + public int tm_state; + public int tm_tick; + public int[] data; + public boolean valid; + + public static final int AO_LOG_TELESCIENCE_START = 's'; + public static final int AO_LOG_TELESCIENCE_DATA = 'd'; + + static final int max_data = 12; + public static final int record_length = 32; + + public AltosEepromTeleScience (AltosEepromChunk chunk, int start) throws ParseException { + type = chunk.data(start); + + valid = !chunk.erased(start, record_length); + if (valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + type = AltosLib.AO_LOG_INVALID; + } + + tick = chunk.data16(start+2); + tm_tick = chunk.data16(start+4); + tm_state = chunk.data(start+6); + data = new int[max_data]; + for (int i = 0; i < max_data; i++) + data[i] = chunk.data16(start + 8 + i * 2); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java new file mode 100644 index 00000000..d2e4f2f7 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java @@ -0,0 +1,44 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.io.File; +import java.util.*; + +public class AltosFile extends File { + + public AltosFile(int year, int month, int day, int serial, int flight, String extension) { + super (AltosPreferences.logdir(), + String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", + year, month, day, serial, flight, extension)); + } + + public AltosFile(int serial, int flight, String extension) { + this(Calendar.getInstance().get(Calendar.YEAR), + Calendar.getInstance().get(Calendar.MONTH) + 1, + Calendar.getInstance().get(Calendar.DAY_OF_MONTH), + serial, + flight, + extension); + } + + public AltosFile(AltosRecord telem) { + this(telem.serial, telem.flight, "telem"); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java new file mode 100644 index 00000000..3fdea469 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java @@ -0,0 +1,49 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +public class AltosFlightReader { + public String name; + + public int serial; + + public void init() { } + + public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } + + public void close(boolean interrupted) { } + + public void set_frequency(double frequency) throws InterruptedException, TimeoutException { } + + public void save_frequency() { } + + public void set_telemetry(int telemetry) { } + + public void save_telemetry() { } + + public void update(AltosState state) throws InterruptedException { } + + public boolean supports_telemetry(int telemetry) { return false; } + + public File backing_file() { return null; } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java b/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java new file mode 100644 index 00000000..f08ff116 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java @@ -0,0 +1,48 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosFrequency { + public double frequency; + public String description; + + public String toString() { + return String.format("%7.3f MHz %-20s", + frequency, description); + } + + public String toShortString() { + return String.format("%7.3f MHz %s", + frequency, description); + } + + public boolean close(double f) { + double diff = Math.abs(frequency - f); + + return diff < 0.010; + } + + public AltosFrequency(double f, String d) { + frequency = f; + description = d; + } +} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java new file mode 100644 index 00000000..f078a469 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java @@ -0,0 +1,248 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; + +public class AltosGPS { + + public final static int MISSING = AltosRecord.MISSING; + + public int nsat; + public boolean locked; + public boolean connected; + public double lat; /* degrees (+N -S) */ + public double lon; /* degrees (+E -W) */ + public int alt; /* m */ + public int year; + public int month; + public int day; + public int hour; + public int minute; + public int second; + + public double ground_speed; /* m/s */ + public int course; /* degrees */ + public double climb_rate; /* m/s */ + public double hdop; /* unitless */ + public double vdop; /* unitless */ + public int h_error; /* m */ + public int v_error; /* m */ + + public AltosGPSSat[] cc_gps_sat; /* tracking data */ + + public void ParseGPSDate(String date) throws ParseException { + String[] ymd = date.split("-"); + if (ymd.length != 3) + throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); + year = AltosParse.parse_int(ymd[0]); + month = AltosParse.parse_int(ymd[1]); + day = AltosParse.parse_int(ymd[2]); + } + + public void ParseGPSTime(String time) throws ParseException { + String[] hms = time.split(":"); + if (hms.length != 3) + throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); + hour = AltosParse.parse_int(hms[0]); + minute = AltosParse.parse_int(hms[1]); + second = AltosParse.parse_int(hms[2]); + } + + public void ClearGPSTime() { + year = month = day = 0; + hour = minute = second = 0; + } + + public AltosGPS(AltosTelemetryMap map) throws ParseException { + String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, + AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); + + nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0); + if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) { + connected = true; + locked = true; + lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); + lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); + alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING); + year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING); + if (year != MISSING) + year += 2000; + month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING); + day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING); + + hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0); + minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0); + second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0); + + ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, + AltosRecord.MISSING, 1/100.0); + course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, + AltosRecord.MISSING); + hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0); + vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0); + h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING); + v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING); + } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) { + connected = true; + locked = false; + } else { + connected = false; + locked = false; + } + } + + public AltosGPS(String[] words, int i, int version) throws ParseException { + AltosParse.word(words[i++], "GPS"); + nsat = AltosParse.parse_int(words[i++]); + AltosParse.word(words[i++], "sat"); + + connected = false; + locked = false; + lat = lon = 0; + alt = 0; + ClearGPSTime(); + if ((words[i]).equals("unlocked")) { + connected = true; + i++; + } else if ((words[i]).equals("not-connected")) { + i++; + } else if (words.length >= 40) { + locked = true; + connected = true; + + if (version > 1) + ParseGPSDate(words[i++]); + else + year = month = day = 0; + ParseGPSTime(words[i++]); + lat = AltosParse.parse_coord(words[i++]); + lon = AltosParse.parse_coord(words[i++]); + alt = AltosParse.parse_int(words[i++]); + if (version > 1 || (i < words.length && !words[i].equals("SAT"))) { + ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)")); + course = AltosParse.parse_int(words[i++]); + climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)")); + hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)")); + h_error = AltosParse.parse_int(words[i++]); + v_error = AltosParse.parse_int(words[i++]); + } + } else { + i++; + } + if (i < words.length) { + AltosParse.word(words[i++], "SAT"); + int tracking_channels = 0; + if (words[i].equals("not-connected")) + tracking_channels = 0; + else + tracking_channels = AltosParse.parse_int(words[i]); + i++; + cc_gps_sat = new AltosGPSSat[tracking_channels]; + for (int chan = 0; chan < tracking_channels; chan++) { + cc_gps_sat[chan] = new AltosGPSSat(); + cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); + /* Older versions included SiRF status bits */ + if (version < 2) + i++; + cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); + } + } else + cc_gps_sat = new AltosGPSSat[0]; + } + + public void set_latitude(int in_lat) { + lat = in_lat / 10.0e7; + } + + public void set_longitude(int in_lon) { + lon = in_lon / 10.0e7; + } + + public void set_time(int hour, int minute, int second) { + hour = hour; + minute = minute; + second = second; + } + + public void set_date(int year, int month, int day) { + year = year; + month = month; + day = day; + } + + public void set_flags(int flags) { + flags = flags; + } + + public void set_altitude(int altitude) { + altitude = altitude; + } + + public void add_sat(int svid, int c_n0) { + if (cc_gps_sat == null) { + cc_gps_sat = new AltosGPSSat[1]; + } else { + AltosGPSSat[] new_gps_sat = new AltosGPSSat[cc_gps_sat.length + 1]; + for (int i = 0; i < cc_gps_sat.length; i++) + new_gps_sat[i] = cc_gps_sat[i]; + cc_gps_sat = new_gps_sat; + } + AltosGPSSat sat = new AltosGPSSat(); + sat.svid = svid; + sat.c_n0 = c_n0; + cc_gps_sat[cc_gps_sat.length - 1] = sat; + } + + public AltosGPS() { + ClearGPSTime(); + cc_gps_sat = null; + } + + public AltosGPS(AltosGPS old) { + nsat = old.nsat; + locked = old.locked; + connected = old.connected; + lat = old.lat; /* degrees (+N -S) */ + lon = old.lon; /* degrees (+E -W) */ + alt = old.alt; /* m */ + year = old.year; + month = old.month; + day = old.day; + hour = old.hour; + minute = old.minute; + second = old.second; + + ground_speed = old.ground_speed; /* m/s */ + course = old.course; /* degrees */ + climb_rate = old.climb_rate; /* m/s */ + hdop = old.hdop; /* unitless? */ + h_error = old.h_error; /* m */ + v_error = old.v_error; /* m */ + + if (old.cc_gps_sat != null) { + cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; + for (int i = 0; i < old.cc_gps_sat.length; i++) { + cc_gps_sat[i] = new AltosGPSSat(); + cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; + cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; + } + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java new file mode 100644 index 00000000..faa1ec8d --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java @@ -0,0 +1,32 @@ +/* + * 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.AltosLib; + +public class AltosGPSSat { + public int svid; + public int c_n0; + + public AltosGPSSat(int s, int c) { + svid = s; + c_n0= c; + } + + public AltosGPSSat() { + } +} + diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java b/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java new file mode 100644 index 00000000..76b71859 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java @@ -0,0 +1,101 @@ +/* + * 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.AltosLib; + +import java.lang.Math; + +public class AltosGreatCircle { + public double distance; + public double bearing; + + double sqr(double a) { return a * a; } + + static final double rad = Math.PI / 180; + static final double earth_radius = 6371.2 * 1000; /* in meters */ + + public static final int BEARING_LONG = 0; + public static final int BEARING_SHORT = 1; + public static final int BEARING_VOICE = 2; + + public String bearing_words(int length) { + String [][] bearing_string = { + { + "North", "North North East", "North East", "East North East", + "East", "East South East", "South East", "South South East", + "South", "South South West", "South West", "West South West", + "West", "West North West", "North West", "North North West" + }, { + "N", "NNE", "NE", "ENE", + "E", "ESE", "SE", "SSE", + "S", "SSW", "SW", "WSW", + "W", "WNW", "NW", "NNW" + }, { + "north", "nor nor east", "north east", "east nor east", + "east", "east sow east", "south east", "sow sow east", + "south", "sow sow west", "south west", "west sow west", + "west", "west nor west", "north west", "nor nor west " + } + }; + return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16]; + } + + public AltosGreatCircle (double start_lat, double start_lon, + double end_lat, double end_lon) + { + double lat1 = rad * start_lat; + double lon1 = rad * -start_lon; + double lat2 = rad * end_lat; + double lon2 = rad * -end_lon; + + double d_lon = lon2 - lon1; + + /* From http://en.wikipedia.org/wiki/Great-circle_distance */ + double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) + + sqr(Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon))); + double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon); + double d = Math.atan2(vdn,vdd); + double course; + + if (Math.cos(lat1) < 1e-20) { + if (lat1 > 0) + course = Math.PI; + else + course = -Math.PI; + } else { + if (d < 1e-10) + course = 0; + else + course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) / + (Math.sin(d)*Math.cos(lat1))); + if (Math.sin(lon2-lon1) > 0) + course = 2 * Math.PI-course; + } + distance = d * earth_radius; + bearing = course * 180/Math.PI; + } + + public AltosGreatCircle(AltosGPS start, AltosGPS end) { + this(start.lat, start.lon, end.lat, end.lon); + } + + public AltosGreatCircle() { + distance = 0; + bearing = 0; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java new file mode 100644 index 00000000..2921d040 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java @@ -0,0 +1,348 @@ +/* + * 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.AltosLib; + +import java.awt.*; +import java.util.*; +import java.text.*; +import java.nio.charset.Charset; + +public class AltosLib { + /* EEProm command letters */ + public static final int AO_LOG_FLIGHT = 'F'; + public static final int AO_LOG_SENSOR = 'A'; + public static final int AO_LOG_TEMP_VOLT = 'T'; + public static final int AO_LOG_DEPLOY = 'D'; + public static final int AO_LOG_STATE = 'S'; + public static final int AO_LOG_GPS_TIME = 'G'; + public static final int AO_LOG_GPS_LAT = 'N'; + public static final int AO_LOG_GPS_LON = 'W'; + public static final int AO_LOG_GPS_ALT = 'H'; + public static final int AO_LOG_GPS_SAT = 'V'; + public static final int AO_LOG_GPS_DATE = 'Y'; + public static final int AO_LOG_PRESSURE = 'P'; + + /* Added for header fields in eeprom files */ + public static final int AO_LOG_CONFIG_VERSION = 1000; + public static final int AO_LOG_MAIN_DEPLOY = 1001; + public static final int AO_LOG_APOGEE_DELAY = 1002; + public static final int AO_LOG_RADIO_CHANNEL = 1003; + public static final int AO_LOG_CALLSIGN = 1004; + public static final int AO_LOG_ACCEL_CAL = 1005; + public static final int AO_LOG_RADIO_CAL = 1006; + public static final int AO_LOG_MAX_FLIGHT_LOG = 1007; + public static final int AO_LOG_MANUFACTURER = 2000; + public static final int AO_LOG_PRODUCT = 2001; + public static final int AO_LOG_SERIAL_NUMBER = 2002; + public static final int AO_LOG_LOG_FORMAT = 2003; + public static final int AO_LOG_SOFTWARE_VERSION = 9999; + + /* Added to flag invalid records */ + public static final int AO_LOG_INVALID = -1; + + /* Flight state numbers and names */ + public static final int ao_flight_startup = 0; + public static final int ao_flight_idle = 1; + public static final int ao_flight_pad = 2; + public static final int ao_flight_boost = 3; + public static final int ao_flight_fast = 4; + public static final int ao_flight_coast = 5; + public static final int ao_flight_drogue = 6; + public static final int ao_flight_main = 7; + public static final int ao_flight_landed = 8; + public static final int ao_flight_invalid = 9; + + /* Telemetry modes */ + public static final int ao_telemetry_off = 0; + public static final int ao_telemetry_min = 1; + public static final int ao_telemetry_standard = 1; + public static final int ao_telemetry_0_9 = 2; + public static final int ao_telemetry_0_8 = 3; + public static final int ao_telemetry_max = 3; + + public static final String[] ao_telemetry_name = { + "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" + }; + + public static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; + + public static final int ao_telemetry_standard_len = 32; + public static final int ao_telemetry_0_9_len = 95; + public static final int ao_telemetry_0_8_len = 94; + + public static final int[] ao_telemetry_len = { + 0, 32, 95, 94 + }; + + public static HashMap string_to_state = new HashMap(); + + public static boolean map_initialized = false; + + public static void initialize_map() + { + string_to_state.put("startup", ao_flight_startup); + string_to_state.put("idle", ao_flight_idle); + string_to_state.put("pad", ao_flight_pad); + string_to_state.put("boost", ao_flight_boost); + string_to_state.put("fast", ao_flight_fast); + string_to_state.put("coast", ao_flight_coast); + string_to_state.put("drogue", ao_flight_drogue); + string_to_state.put("apogee", ao_flight_coast); + string_to_state.put("main", ao_flight_main); + string_to_state.put("landed", ao_flight_landed); + string_to_state.put("invalid", ao_flight_invalid); + map_initialized = true; + } + + public static int telemetry_len(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_len[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + public static String telemetry_name(int telemetry) { + if (telemetry <= ao_telemetry_max) + return ao_telemetry_name[telemetry]; + throw new IllegalArgumentException(String.format("Invalid telemetry %d", + telemetry)); + } + + public static String[] state_to_string = { + "startup", + "idle", + "pad", + "boost", + "fast", + "coast", + "drogue", + "main", + "landed", + "invalid", + }; + + public static String[] state_to_string_capital = { + "Startup", + "Idle", + "Pad", + "Boost", + "Fast", + "Coast", + "Drogue", + "Main", + "Landed", + "Invalid", + }; + + public static int state(String state) { + if (!map_initialized) + initialize_map(); + if (string_to_state.containsKey(state)) + return string_to_state.get(state); + return ao_flight_invalid; + } + + public static String state_name(int state) { + if (state < 0 || state_to_string.length <= state) + return "invalid"; + return state_to_string[state]; + } + + public static final int AO_GPS_VALID = (1 << 4); + public static final int AO_GPS_RUNNING = (1 << 5); + public static final int AO_GPS_DATE_VALID = (1 << 6); + public static final int AO_GPS_NUM_SAT_SHIFT = 0; + public static final int AO_GPS_NUM_SAT_MASK = 0xf; + + public static final int AO_LOG_FORMAT_UNKNOWN = 0; + public static final int AO_LOG_FORMAT_FULL = 1; + public static final int AO_LOG_FORMAT_TINY = 2; + public static final int AO_LOG_FORMAT_TELEMETRY = 3; + public static final int AO_LOG_FORMAT_TELESCIENCE = 4; + public static final int AO_LOG_FORMAT_NONE = 127; + + public static boolean isspace(int c) { + switch (c) { + case ' ': + case '\t': + return true; + } + return false; + } + + public static boolean ishex(int c) { + if ('0' <= c && c <= '9') + return true; + if ('a' <= c && c <= 'f') + return true; + if ('A' <= c && c <= 'F') + return true; + return false; + } + + public static boolean ishex(String s) { + for (int i = 0; i < s.length(); i++) + if (!ishex(s.charAt(i))) + return false; + return true; + } + + public static int fromhex(int c) { + 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; + return -1; + } + + public static int fromhex(String s) throws NumberFormatException { + int c, v = 0; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (!ishex(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + return v; + } + v = v * 16 + fromhex(c); + } + return v; + } + + public static boolean isdec(int c) { + if ('0' <= c && c <= '9') + return true; + return false; + } + + public static boolean isdec(String s) { + for (int i = 0; i < s.length(); i++) + if (!isdec(s.charAt(i))) + return false; + return true; + } + + public static int fromdec(int c) { + if ('0' <= c && c <= '9') + return c - '0'; + return -1; + } + + public static int int8(int[] bytes, int i) { + return (int) (byte) bytes[i]; + } + + public static int uint8(int[] bytes, int i) { + return bytes[i]; + } + + public static int int16(int[] bytes, int i) { + return (int) (short) (bytes[i] + (bytes[i+1] << 8)); + } + + public static int uint16(int[] bytes, int i) { + return bytes[i] + (bytes[i+1] << 8); + } + + public static int uint32(int[] bytes, int i) { + return bytes[i] + + (bytes[i+1] << 8) + + (bytes[i+2] << 16) + + (bytes[i+3] << 24); + } + + public static final Charset unicode_set = Charset.forName("UTF-8"); + + public static String string(int[] bytes, int s, int l) { + if (s + l > bytes.length) { + if (s > bytes.length) { + s = bytes.length; + l = 0; + } else { + l = bytes.length - s; + } + } + + int i; + for (i = l - 1; i >= 0; i--) + if (bytes[s+i] != 0) + break; + + l = i + 1; + byte[] b = new byte[l]; + + for (i = 0; i < l; i++) + b[i] = (byte) bytes[s+i]; + String n = new String(b, unicode_set); + return n; + } + + public static int hexbyte(String s, int i) { + int c0, c1; + + if (s.length() < i + 2) + throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); + c0 = s.charAt(i); + if (!ishex(c0)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); + c1 = s.charAt(i+1); + if (!ishex(c1)) + throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); + return fromhex(c0) * 16 + fromhex(c1); + } + + public static int[] hexbytes(String s) { + int n; + int[] r; + int i; + + if ((s.length() & 1) != 0) + throw new NumberFormatException(String.format("invalid line \"%s\"", s)); + n = s.length() / 2; + r = new int[n]; + for (i = 0; i < n; i++) + r[i] = hexbyte(s, i * 2); + return r; + } + + public static int fromdec(String s) throws NumberFormatException { + int c, v = 0; + int sign = 1; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if (i == 0 && c == '-') { + sign = -1; + } else if (!isdec(c)) { + if (i == 0) + throw new NumberFormatException(String.format("invalid number \"%s\"", s)); + return v; + } else + v = v * 10 + fromdec(c); + } + return v * sign; + } + + public static String replace_extension(String input, String extension) { + int dot = input.lastIndexOf("."); + if (dot > 0) + input = input.substring(0,dot); + return input.concat(extension); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java new file mode 100644 index 00000000..5627795a --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java @@ -0,0 +1,30 @@ +/* + * 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.AltosLib; + +public class AltosLine { + public String line; + + public AltosLine() { + line = null; + } + + public AltosLine(String s) { + line = s; + } +} \ No newline at end of file diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java new file mode 100644 index 00000000..9b80e916 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java @@ -0,0 +1,238 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import java.text.*; + +public abstract class AltosLink { + public abstract void print(String data); + public abstract void close(); + + public static boolean debug = false; + public static void set_debug(boolean in_debug) { debug = in_debug; } + LinkedList pending_output = new LinkedList(); + + public LinkedList> monitors = new LinkedList> ();; + public LinkedBlockingQueue reply_queue = new LinkedBlockingQueue(); + + public void add_monitor(LinkedBlockingQueue q) { + set_monitor(true); + monitors.add(q); + } + + public void remove_monitor(LinkedBlockingQueue q) { + monitors.remove(q); + if (monitors.isEmpty()) + set_monitor(false); + } + + public void printf(String format, Object ... arguments) { + String line = String.format(format, arguments); + if (debug) + pending_output.add(line); + print(line); + } + + public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { + flush_output(); + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) + return line.line; + return null; + } + + public String get_reply(int timeout) throws InterruptedException { + try { + return get_reply_no_dialog(timeout); + } catch (TimeoutException te) { + return null; + } + } + + public String get_reply() throws InterruptedException { + return get_reply(5000); + } + + public void add_telem(AltosLine line) throws InterruptedException { + for (int e = 0; e < monitors.size(); e++) { + LinkedBlockingQueue q = monitors.get(e); + q.put(line); + } + } + + public void add_reply(AltosLine line) throws InterruptedException { + reply_queue.put (line); + } + + public void add_string(String line) throws InterruptedException { + if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { + add_telem(new AltosLine(line)); + } else { + add_reply(new AltosLine(line)); + } + } + + public void add_bytes(byte[] bytes, int len) throws InterruptedException { + String line; + try { + line = new String(bytes, 0, len, "UTF-8"); + } catch (UnsupportedEncodingException ue) { + line = ""; + for (int i = 0; i < len; i++) + line = line + bytes[i]; + } + if (debug) + System.out.printf("\t\t\t\t\t%s\n", line); + add_string(line); + } + + public void flush_output() { + for (String s : pending_output) + System.out.print(s); + pending_output.clear(); + } + + public void flush_input(int timeout) throws InterruptedException { + flush_output(); + boolean got_some; + + do { + Thread.sleep(timeout); + got_some = !reply_queue.isEmpty(); + reply_queue.clear(); + } while (got_some); + } + + + public void flush_input() throws InterruptedException { + flush_input(100); + } + + + /* + * Various command-level operations on + * the link + */ + public boolean monitor_mode = false; + public int telemetry = AltosLib.ao_telemetry_standard; + public double frequency; + AltosConfigData config_data; + + private int telemetry_len() { + return AltosLib.telemetry_len(telemetry); + } + + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + if (monitor_mode) + printf("m 0\nm %x\n", telemetry_len()); + flush_output(); + } + + public void set_monitor(boolean monitor) { + monitor_mode = monitor; + if (monitor) + printf("m %x\n", telemetry_len()); + else + printf("m 0\n"); + flush_output(); + } + + private void set_channel(int channel) { + if (monitor_mode) + printf("m 0\nc r %d\nm %x\n", + channel, telemetry_len()); + else + printf("c r %d\n", channel); + flush_output(); + } + + private void set_radio_setting(int setting) { + if (monitor_mode) + printf("m 0\nc R %d\nm %x\n", + setting, telemetry_len()); + else + printf("c R %d\n", setting); + flush_output(); + } + + public void set_radio_frequency(double frequency, + boolean has_setting, + int cal) { + if (debug) + System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); + if (has_setting) + set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); + else + set_channel(AltosConvert.radio_frequency_to_channel(frequency)); + } + + public AltosConfigData config_data() throws InterruptedException, TimeoutException { + if (config_data == null) + config_data = new AltosConfigData(this); + return config_data; + } + + public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + config_data(); + set_radio_frequency(frequency, + config_data.radio_setting != 0, + config_data.radio_calibration); + } + + public void set_callsign(String callsign) { + printf ("c c %s\n", callsign); + flush_output(); + } + + public boolean remote; + public int serial; + public String name; + + public void start_remote() throws TimeoutException, InterruptedException { + if (debug) + System.out.printf("start remote %7.3f\n", frequency); + if (frequency == 0.0) + frequency = AltosPreferences.frequency(serial); + set_radio_frequency(frequency); + set_callsign(AltosPreferences.callsign()); + printf("p\nE 0\n"); + flush_input(); + remote = true; + } + + public void stop_remote() throws InterruptedException { + if (debug) + System.out.printf("stop remote\n"); + try { + flush_input(); + } finally { + printf ("~\n"); + flush_output(); + } + remote = false; + } + + public AltosLink() { + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java b/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java new file mode 100644 index 00000000..08c45ca8 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java @@ -0,0 +1,126 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.text.ParseException; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * This creates a thread to capture telemetry data and write it to + * a log file + */ +class AltosLog implements Runnable { + + LinkedBlockingQueue input_queue; + LinkedBlockingQueue pending_queue; + int serial; + int flight; + FileWriter log_file; + Thread log_thread; + AltosFile file; + + private void close_log_file() { + if (log_file != null) { + try { + log_file.close(); + } catch (IOException io) { + } + log_file = null; + } + } + + void close() { + close_log_file(); + if (log_thread != null) { + log_thread.interrupt(); + log_thread = null; + } + } + + File file() { + return file; + } + + boolean open (AltosRecord telem) throws IOException { + AltosFile a = new AltosFile(telem); + + System.out.printf("open %s\n", a.toString()); + log_file = new FileWriter(a, true); + if (log_file != null) { + while (!pending_queue.isEmpty()) { + try { + String s = pending_queue.take(); + log_file.write(s); + log_file.write('\n'); + } catch (InterruptedException ie) { + } + } + log_file.flush(); + file = a; + } + return log_file != null; + } + + public void run () { + try { + AltosRecord previous = null; + for (;;) { + AltosLine line = input_queue.take(); + if (line.line == null) + continue; + try { + AltosRecord telem = AltosTelemetry.parse(line.line, previous); + if (telem.serial != 0 && telem.flight != 0 && + (telem.serial != serial || telem.flight != flight || log_file == null)) + { + close_log_file(); + serial = telem.serial; + flight = telem.flight; + open(telem); + } + previous = telem; + } catch (ParseException pe) { + } catch (AltosCRCException ce) { + } + if (log_file != null) { + log_file.write(line.line); + log_file.write('\n'); + log_file.flush(); + } else + pending_queue.put(line.line); + } + } catch (InterruptedException ie) { + } catch (IOException ie) { + } + close(); + } + + public AltosLog (AltosLink link) { + pending_queue = new LinkedBlockingQueue (); + input_queue = new LinkedBlockingQueue (); + link.add_monitor(input_queue); + serial = -1; + flight = -1; + log_file = null; + log_thread = new Thread(this); + log_thread.start(); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java b/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java new file mode 100644 index 00000000..7d832f1a --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java @@ -0,0 +1,79 @@ +/* + * 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.AltosLib; + +import java.text.*; +import java.lang.*; + +public class AltosParse { + public static boolean isdigit(char c) { + return '0' <= c && c <= '9'; + } + + public static int parse_int(String v) throws ParseException { + try { + return AltosLib.fromdec(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing int " + v, 0); + } + } + + public static int parse_hex(String v) throws ParseException { + try { + return AltosLib.fromhex(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing hex " + v, 0); + } + } + + public static double parse_double(String v) throws ParseException { + try { + return Double.parseDouble(v); + } catch (NumberFormatException e) { + throw new ParseException("error parsing double " + v, 0); + } + } + + public static double parse_coord(String coord) throws ParseException { + String[] dsf = coord.split("\\D+"); + + if (dsf.length != 3) { + throw new ParseException("error parsing coord " + coord, 0); + } + int deg = parse_int(dsf[0]); + int min = parse_int(dsf[1]); + int frac = parse_int(dsf[2]); + + double r = deg + (min + frac / 10000.0) / 60.0; + if (coord.endsWith("S") || coord.endsWith("W")) + r = -r; + return r; + } + + public static String strip_suffix(String v, String suffix) { + if (v.endsWith(suffix)) + return v.substring(0, v.length() - suffix.length()); + return v; + } + + public static void word(String v, String m) throws ParseException { + if (!v.equals(m)) { + throw new ParseException("error matching '" + v + "' '" + m + "'", 0); + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java b/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java new file mode 100644 index 00000000..43c7088d --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java @@ -0,0 +1,365 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.awt.Component; +import javax.swing.*; +import javax.swing.filechooser.FileSystemView; + +public class AltosPreferences { + public static Preferences preferences; + + /* logdir preference name */ + public final static String logdirPreference = "LOGDIR"; + + /* channel preference name */ + public final static String channelPreferenceFormat = "CHANNEL-%d"; + + /* frequency preference name */ + public final static String frequencyPreferenceFormat = "FREQUENCY-%d"; + + /* telemetry format preference name */ + public final static String telemetryPreferenceFormat = "TELEMETRY-%d"; + + /* voice preference name */ + public final static String voicePreference = "VOICE"; + + /* callsign preference name */ + public final static String callsignPreference = "CALLSIGN"; + + /* firmware directory preference name */ + public final static String firmwaredirPreference = "FIRMWARE"; + + /* serial debug preference name */ + public final static String serialDebugPreference = "SERIAL-DEBUG"; + + /* scanning telemetry preferences name */ + public final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; + + /* Launcher serial preference name */ + public final static String launcherSerialPreference = "LAUNCHER-SERIAL"; + + /* Launcher channel preference name */ + public final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; + + /* Default logdir is ~/TeleMetrum */ + public final static String logdirName = "TeleMetrum"; + + /* Log directory */ + public static File logdir; + + /* Map directory -- hangs of logdir */ + public static File mapdir; + + /* Frequency (map serial to frequency) */ + public static Hashtable frequencies; + + /* Telemetry (map serial to telemetry format) */ + public static Hashtable telemetries; + + /* Voice preference */ + public static boolean voice; + + /* Callsign preference */ + public static String callsign; + + /* Firmware directory */ + public static File firmwaredir; + + /* Scanning telemetry */ + public static int scanning_telemetry; + + /* List of frequencies */ + public final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; + public static AltosFrequency[] common_frequencies; + + public final static String frequency_count = "COUNT"; + public final static String frequency_format = "FREQUENCY-%d"; + public final static String description_format = "DESCRIPTION-%d"; + + public static AltosFrequency[] load_common_frequencies() { + AltosFrequency[] frequencies = null; + boolean existing = false; + try { + existing = preferences.nodeExists(common_frequencies_node_name); + } catch (BackingStoreException be) { + existing = false; + } + if (existing) { + Preferences node = preferences.node(common_frequencies_node_name); + int count = node.getInt(frequency_count, 0); + + frequencies = new AltosFrequency[count]; + for (int i = 0; i < count; i++) { + double frequency; + String description; + + frequency = node.getDouble(String.format(frequency_format, i), 0.0); + description = node.get(String.format(description_format, i), null); + frequencies[i] = new AltosFrequency(frequency, description); + } + } else { + frequencies = new AltosFrequency[10]; + for (int i = 0; i < 10; i++) { + frequencies[i] = new AltosFrequency(434.550 + i * .1, + String.format("Channel %d", i)); + } + } + return frequencies; + } + + public static void save_common_frequencies(AltosFrequency[] frequencies) { + Preferences node = preferences.node(common_frequencies_node_name); + + node.putInt(frequency_count, frequencies.length); + for (int i = 0; i < frequencies.length; i++) { + node.putDouble(String.format(frequency_format, i), frequencies[i].frequency); + node.put(String.format(description_format, i), frequencies[i].description); + } + } + public static int launcher_serial; + + public static int launcher_channel; + + public static void init() { + preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); + + /* Initialize logdir from preferences */ + String logdir_string = preferences.get(logdirPreference, null); + if (logdir_string != null) + logdir = new File(logdir_string); + else { + /* Use the file system view default directory */ + logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName); + if (!logdir.exists()) + logdir.mkdirs(); + } + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); + + frequencies = new Hashtable(); + + telemetries = new Hashtable(); + + voice = preferences.getBoolean(voicePreference, true); + + callsign = preferences.get(callsignPreference,"N0CALL"); + + scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << AltosLib.ao_telemetry_standard)); + + launcher_serial = preferences.getInt(launcherSerialPreference, 0); + + launcher_channel = preferences.getInt(launcherChannelPreference, 0); + + String firmwaredir_string = preferences.get(firmwaredirPreference, null); + if (firmwaredir_string != null) + firmwaredir = new File(firmwaredir_string); + else + firmwaredir = null; + + common_frequencies = load_common_frequencies(); + + } + + static { init(); } + + public static void flush_preferences() { + try { + preferences.flush(); + } catch (BackingStoreException ee) { +/* + if (component != null) + JOptionPane.showMessageDialog(component, + preferences.absolutePath(), + "Cannot save prefernces", + JOptionPane.ERROR_MESSAGE); + else +*/ + System.err.printf("Cannot save preferences\n"); + } + } + + public static void set_logdir(File new_logdir) { + logdir = new_logdir; + mapdir = new File(logdir, "maps"); + if (!mapdir.exists()) + mapdir.mkdirs(); + synchronized (preferences) { + preferences.put(logdirPreference, logdir.getPath()); + flush_preferences(); + } + } + + public static File logdir() { + return logdir; + } + + public static File mapdir() { + return mapdir; + } + + public static void set_frequency(int serial, double new_frequency) { + frequencies.put(serial, new_frequency); + synchronized (preferences) { + preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); + flush_preferences(); + } + } + + public static double frequency(int serial) { + if (frequencies.containsKey(serial)) + return frequencies.get(serial); + double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); + if (frequency == 0.0) { + int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); + frequency = AltosConvert.radio_channel_to_frequency(channel); + } + frequencies.put(serial, frequency); + return frequency; + } + + public static void set_telemetry(int serial, int new_telemetry) { + telemetries.put(serial, new_telemetry); + synchronized (preferences) { + preferences.putInt(String.format(telemetryPreferenceFormat, serial), new_telemetry); + flush_preferences(); + } + } + + public static int telemetry(int serial) { + if (telemetries.containsKey(serial)) + return telemetries.get(serial); + int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), + AltosLib.ao_telemetry_standard); + telemetries.put(serial, telemetry); + return telemetry; + } + + public static void set_scanning_telemetry(int new_scanning_telemetry) { + scanning_telemetry = new_scanning_telemetry; + synchronized (preferences) { + preferences.putInt(scanningTelemetryPreference, scanning_telemetry); + flush_preferences(); + } + } + + public static int scanning_telemetry() { + return scanning_telemetry; + } + + public static void set_voice(boolean new_voice) { + voice = new_voice; + synchronized (preferences) { + preferences.putBoolean(voicePreference, voice); + flush_preferences(); + } + } + + public static boolean voice() { + return voice; + } + + public static void set_callsign(String new_callsign) { + callsign = new_callsign; + synchronized(preferences) { + preferences.put(callsignPreference, callsign); + flush_preferences(); + } + } + + public static String callsign() { + return callsign; + } + + public static void set_firmwaredir(File new_firmwaredir) { + firmwaredir = new_firmwaredir; + synchronized (preferences) { + preferences.put(firmwaredirPreference, firmwaredir.getPath()); + flush_preferences(); + } + } + + public static File firmwaredir() { + return firmwaredir; + } + + public static void set_launcher_serial(int new_launcher_serial) { + launcher_serial = new_launcher_serial; + System.out.printf("set launcher serial to %d\n", new_launcher_serial); + synchronized (preferences) { + preferences.putInt(launcherSerialPreference, launcher_serial); + flush_preferences(); + } + } + + public static int launcher_serial() { + return launcher_serial; + } + + public static void set_launcher_channel(int new_launcher_channel) { + launcher_channel = new_launcher_channel; + System.out.printf("set launcher channel to %d\n", new_launcher_channel); + synchronized (preferences) { + preferences.putInt(launcherChannelPreference, launcher_channel); + flush_preferences(); + } + } + + public static int launcher_channel() { + return launcher_channel; + } + + public static Preferences bt_devices() { + return preferences.node("bt_devices"); + } + + public static AltosFrequency[] common_frequencies() { + return common_frequencies; + } + + public static void set_common_frequencies(AltosFrequency[] frequencies) { + common_frequencies = frequencies; + synchronized(preferences) { + save_common_frequencies(frequencies); + flush_preferences(); + } + } + + public static void add_common_frequency(AltosFrequency frequency) { + AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; + int i; + + for (i = 0; i < common_frequencies.length; i++) { + if (frequency.frequency == common_frequencies[i].frequency) + return; + if (frequency.frequency < common_frequencies[i].frequency) + break; + new_frequencies[i] = common_frequencies[i]; + } + new_frequencies[i] = frequency; + for (; i < common_frequencies.length; i++) + new_frequencies[i+1] = common_frequencies[i]; + set_common_frequencies(new_frequencies); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java new file mode 100644 index 00000000..e4915af0 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java @@ -0,0 +1,319 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; +import java.io.*; + +public class AltosRecord implements Comparable { + public final static int MISSING = 0x7fffffff; + + public static final int seen_flight = 1; + public static final int seen_sensor = 2; + public static final int seen_temp_volt = 4; + public static final int seen_deploy = 8; + public static final int seen_gps_time = 16; + public static final int seen_gps_lat = 32; + public static final int seen_gps_lon = 64; + public static final int seen_companion = 128; + public int seen; + + public int version; + public String callsign; + public int serial; + public int flight; + public int rssi; + public int status; + public int state; + public int tick; + + public int accel; + public int pres; + public int temp; + public int batt; + public int drogue; + public int main; + + public int ground_accel; + public int ground_pres; + public int accel_plus_g; + public int accel_minus_g; + + public double acceleration; + public double speed; + public double height; + + public int flight_accel; + public int flight_vel; + public int flight_pres; + + public AltosGPS gps; + public boolean new_gps; + + public AltosIMU imu; + public AltosMag mag; + + public double time; /* seconds since boost */ + + public int device_type; + public int config_major; + public int config_minor; + public int apogee_delay; + public int main_deploy; + public int flight_log_max; + public String firmware_version; + + public AltosRecordCompanion companion; + +>>>>>>> 5a249bc... altosui: Complete split out of separate java library + /* + * Values for our MP3H6115A pressure sensor + * + * From the data sheet: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * + * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa + * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa + */ + + public static final double counts_per_kPa = 27 * 2047 / 3300; + public static final double counts_at_101_3kPa = 1674.0; + + public static double + barometer_to_pressure(double count) + { + return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; + } + + public double raw_pressure() { + if (pres == MISSING) + return MISSING; + return barometer_to_pressure(pres); + } + + public double filtered_pressure() { + if (flight_pres == MISSING) + return MISSING; + return barometer_to_pressure(flight_pres); + } + + public double ground_pressure() { + if (ground_pres == MISSING) + return MISSING; + return barometer_to_pressure(ground_pres); + } + + public double raw_altitude() { + double p = raw_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double ground_altitude() { + double p = ground_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double filtered_altitude() { + if (height != MISSING && ground_pres != MISSING) + return height + ground_altitude(); + + double p = filtered_pressure(); + if (p == MISSING) + return MISSING; + return AltosConvert.pressure_to_altitude(p); + } + + public double filtered_height() { + if (height != MISSING) + return height; + + double f = filtered_altitude(); + double g = ground_altitude(); + if (f == MISSING || g == MISSING) + return MISSING; + return f - g; + } + + public double raw_height() { + double r = raw_altitude(); + double g = ground_altitude(); + + if (r == MISSING || g == MISSING) + return height; + return r - g; + } + + public double battery_voltage() { + if (batt == MISSING) + return MISSING; + return AltosConvert.cc_battery_to_voltage(batt); + } + + public double main_voltage() { + if (main == MISSING) + return MISSING; + return AltosConvert.cc_ignitor_to_voltage(main); + } + + public double drogue_voltage() { + if (drogue == MISSING) + return MISSING; + return AltosConvert.cc_ignitor_to_voltage(drogue); + } + + /* Value for the CC1111 built-in temperature sensor + * Output voltage at 0°C = 0.755V + * Coefficient = 0.00247V/°C + * Reference voltage = 1.25V + * + * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 + * = (value - 19791.268) / 32768 * 1.25 / 0.00247 + */ + + public static double + thermometer_to_temperature(double thermo) + { + return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; + } + + public double temperature() { + if (temp == MISSING) + return MISSING; + return thermometer_to_temperature(temp); + } + + public double accel_counts_per_mss() { + double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; + + return counts_per_g / 9.80665; + } + + public double acceleration() { + if (acceleration != MISSING) + return acceleration; + + if (ground_accel == MISSING || accel == MISSING) + return MISSING; + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public double accel_speed() { + if (speed != MISSING) + return speed; + if (flight_vel == MISSING) + return MISSING; + return flight_vel / (accel_counts_per_mss() * 100.0); + } + + public String state() { + return AltosLib.state_name(state); + } + + public static String gets(FileInputStream s) throws IOException { + int c; + String line = ""; + + while ((c = s.read()) != -1) { + if (c == '\r') + continue; + if (c == '\n') { + return line; + } + line = line + (char) c; + } + return null; + } + + public int compareTo(AltosRecord o) { + return tick - o.tick; + } + + public AltosRecord(AltosRecord old) { + version = old.version; + seen = old.seen; + callsign = old.callsign; + serial = old.serial; + flight = old.flight; + rssi = old.rssi; + status = old.status; + state = old.state; + tick = old.tick; + accel = old.accel; + pres = old.pres; + temp = old.temp; + batt = old.batt; + drogue = old.drogue; + main = old.main; + flight_accel = old.flight_accel; + ground_accel = old.ground_accel; + flight_vel = old.flight_vel; + flight_pres = old.flight_pres; + ground_pres = old.ground_pres; + accel_plus_g = old.accel_plus_g; + accel_minus_g = old.accel_minus_g; + acceleration = old.acceleration; + speed = old.speed; + height = old.height; + gps = new AltosGPS(old.gps); + new_gps = false; + companion = old.companion; + imu = old.imu; + mag = old.mag; + } + + public AltosRecord() { + version = 0; + seen = 0; + callsign = "N0CALL"; + serial = 0; + flight = 0; + rssi = 0; + status = 0; + state = AltosLib.ao_flight_startup; + tick = 0; + accel = MISSING; + pres = MISSING; + temp = MISSING; + batt = MISSING; + drogue = MISSING; + main = MISSING; + flight_accel = 0; + ground_accel = 0; + flight_vel = 0; + flight_pres = 0; + ground_pres = 0; + accel_plus_g = 0; + accel_minus_g = 0; + acceleration = MISSING; + speed = MISSING; + height = MISSING; + gps = new AltosGPS(); + new_gps = false; + companion = null; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java new file mode 100644 index 00000000..c8cc6cac --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java @@ -0,0 +1,38 @@ +/* + * 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.AltosLib; + +public class AltosRecordCompanion { + public final static int board_id_telescience = 0x0a; + public final static int MAX_CHANNELS = 12; + + public int tick; + public int board_id; + public int update_period; + public int channels; + public int[] companion_data; + + public AltosRecordCompanion(int in_channels) { + channels = in_channels; + if (channels < 0) + channels = 0; + if (channels > MAX_CHANNELS) + channels = MAX_CHANNELS; + companion_data = new int[channels]; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java new file mode 100644 index 00000000..ed1787ed --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java @@ -0,0 +1,29 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; + +public abstract class AltosRecordIterable implements Iterable { + public abstract Iterator iterator(); + public void write_comments(PrintStream out) { } + public boolean has_accel() { return false; } + public boolean has_gps() { return false; } + public boolean has_ignite() { return false; }; +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java new file mode 100644 index 00000000..1585f9eb --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java @@ -0,0 +1,56 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * Open an existing telemetry file and replay it in realtime + */ + +public class AltosReplayReader extends AltosFlightReader { + Iterator iterator; + File file; + + public AltosRecord read() { + if (iterator.hasNext()) + return iterator.next(); + return null; + } + + public void close (boolean interrupted) { + } + + public void update(AltosState state) throws InterruptedException { + /* Make it run in realtime after the rocket leaves the pad */ + if (state.state > AltosLib.ao_flight_pad) + Thread.sleep((int) (Math.min(state.time_change,10) * 1000)); + } + + public File backing_file() { return file; } + + public AltosReplayReader(Iterator in_iterator, File in_file) { + iterator = in_iterator; + file = in_file; + name = file.getName(); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosState.java b/altoslib/src/org/altusmetrum/AltosLib/AltosState.java new file mode 100644 index 00000000..0645e448 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosState.java @@ -0,0 +1,210 @@ +/* + * 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. + */ + +/* + * Track flight state from telemetry or eeprom data stream + */ + +package org.altusmetrum.AltosLib; + +public class AltosState { + public AltosRecord data; + + /* derived data */ + + public long report_time; + + public double time; + public double time_change; + public int tick; + + public int state; + public boolean landed; + public boolean ascent; /* going up? */ + public boolean boost; /* under power */ + + public double ground_altitude; + public double height; + public double speed; + public double acceleration; + public double battery; + public double temperature; + public double main_sense; + public double drogue_sense; + public double baro_speed; + + public double max_height; + public double max_acceleration; + public double max_speed; + public double max_baro_speed; + + public AltosGPS gps; + + public AltosIMU imu; + public AltosMag mag; + + public static final int MIN_PAD_SAMPLES = 10; + + public int npad; + public int ngps; + public int gps_waiting; + public boolean gps_ready; + + public AltosGreatCircle from_pad; + public double elevation; /* from pad */ + public double range; /* total distance */ + + public double gps_height; + + public int speak_tick; + public double speak_altitude; + + public void init (AltosRecord cur, AltosState prev_state) { + int i; + AltosRecord prev; + + data = cur; + + ground_altitude = data.ground_altitude(); + height = data.filtered_height(); + + report_time = System.currentTimeMillis(); + + acceleration = data.acceleration(); + speed = data.accel_speed(); + temperature = data.temperature(); + drogue_sense = data.drogue_voltage(); + main_sense = data.main_voltage(); + battery = data.battery_voltage(); + tick = data.tick; + state = data.state; + + if (prev_state != null) { + + /* Preserve any existing gps data */ + npad = prev_state.npad; + ngps = prev_state.ngps; + gps = prev_state.gps; + pad_lat = prev_state.pad_lat; + pad_lon = prev_state.pad_lon; + pad_alt = prev_state.pad_alt; + max_height = prev_state.max_height; + max_acceleration = prev_state.max_acceleration; + max_speed = prev_state.max_speed; + max_baro_speed = prev_state.max_baro_speed; + imu = prev_state.imu; + mag = prev_state.mag; + + /* make sure the clock is monotonic */ + while (tick < prev_state.tick) + tick += 65536; + + time_change = (tick - prev_state.tick) / 100.0; + + /* compute barometric speed */ + + double height_change = height - prev_state.height; + if (data.speed != AltosRecord.MISSING) + baro_speed = data.speed; + else { + if (time_change > 0) + baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; + else + baro_speed = prev_state.baro_speed; + } + } else { + npad = 0; + ngps = 0; + gps = null; + baro_speed = 0; + time_change = 0; + } + + time = tick / 100.0; + + if (cur.new_gps && (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_idle)) { + + /* Track consecutive 'good' gps reports, waiting for 10 of them */ + if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) + npad++; + else + npad = 0; + + /* Average GPS data while on the pad */ + if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) { + if (ngps > 1) { + /* filter pad position */ + pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0; + pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0; + pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0; + } else { + pad_lat = data.gps.lat; + pad_lon = data.gps.lon; + pad_alt = data.gps.alt; + } + ngps++; + } + } + + gps_waiting = MIN_PAD_SAMPLES - npad; + if (gps_waiting < 0) + gps_waiting = 0; + + gps_ready = gps_waiting == 0; + + ascent = (AltosLib.ao_flight_boost <= state && + state <= AltosLib.ao_flight_coast); + boost = (AltosLib.ao_flight_boost == state); + + /* Only look at accelerometer data under boost */ + if (boost && acceleration > max_acceleration) + max_acceleration = acceleration; + if (boost && speed > max_speed) + max_speed = speed; + if (boost && baro_speed > max_baro_speed) + max_baro_speed = baro_speed; + + if (height > max_height) + max_height = height; + if (data.gps != null) { + if (gps == null || !gps.locked || data.gps.locked) + gps = data.gps; + if (ngps > 0 && gps.locked) { + from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); + } + } + elevation = 0; + range = -1; + if (ngps > 0) { + gps_height = gps.alt - pad_alt; + if (from_pad != null) { + elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; + range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); + } + } else { + gps_height = 0; + } + } + + public AltosState(AltosRecord cur) { + init(cur, null); + } + + public AltosState (AltosRecord cur, AltosState prev) { + init(cur, prev); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java new file mode 100644 index 00000000..04abb1f3 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java @@ -0,0 +1,241 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * The packet format is a simple hex dump of the raw telemetry frame. + * It starts with 'TELEM', then contains hex digits with a checksum as the last + * byte on the line. + * + * Version 4 is a replacement with consistent syntax. Each telemetry line + * contains a sequence of space-separated names and values, the values are + * either integers or strings. The names are all unique. All values are + * optional + * + * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 + * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 + * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 + * + * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 + * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 + * + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + * + * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports + * in 1/2dB increments while this protocol provides only integers. So, + * the syntax didn't change just the interpretation of the RSSI + * values. + * + * Version 2 of the telemetry data stream is a bit of a mess, with no + * consistent formatting. In particular, the GPS data is formatted for + * viewing instead of parsing. However, the key feature is that every + * telemetry line contains all of the information necessary to + * describe the current rocket state, including the calibration values + * for accelerometer and barometer. + * + * GPS unlocked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ + * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ + * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 + * + * GPS locked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ + * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ + * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ + * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ + * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ + * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 + * + */ + +public class AltosTelemetry extends AltosRecord { + + /* + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + */ + + final static String AO_TELEM_VERSION = "VERSION"; + final static String AO_TELEM_CALL = "c"; + final static String AO_TELEM_SERIAL = "n"; + final static String AO_TELEM_FLIGHT = "f"; + final static String AO_TELEM_RSSI = "r"; + final static String AO_TELEM_STATE = "s"; + final static String AO_TELEM_TICK = "t"; + + /* + * Raw sensor values + * + * Name Value + * r_a Accelerometer reading (integer) + * r_b Barometer reading (integer) + * r_t Thermometer reading (integer) + * r_v Battery reading (integer) + * r_d Drogue continuity (integer) + * r_m Main continuity (integer) + */ + + final static String AO_TELEM_RAW_ACCEL = "r_a"; + final static String AO_TELEM_RAW_BARO = "r_b"; + final static String AO_TELEM_RAW_THERMO = "r_t"; + final static String AO_TELEM_RAW_BATT = "r_v"; + final static String AO_TELEM_RAW_DROGUE = "r_d"; + final static String AO_TELEM_RAW_MAIN = "r_m"; + + /* + * Sensor calibration values + * + * Name Value + * c_a Ground accelerometer reading (integer) + * c_b Ground barometer reading (integer) + * c_p Accelerometer reading for +1g + * c_m Accelerometer reading for -1g + */ + + final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; + final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; + final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; + final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; + + /* + * Kalman state values + * + * Name Value + * k_h Height above pad (integer, meters) + * k_s Vertical speeed (integer, m/s * 16) + * k_a Vertical acceleration (integer, m/s² * 16) + */ + + final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; + final static String AO_TELEM_KALMAN_SPEED = "k_s"; + final static String AO_TELEM_KALMAN_ACCEL = "k_a"; + + /* + * Ad-hoc flight values + * + * Name Value + * a_a Acceleration (integer, sensor units) + * a_s Speed (integer, integrated acceleration value) + * a_b Barometer reading (integer, sensor units) + */ + + final static String AO_TELEM_ADHOC_ACCEL = "a_a"; + final static String AO_TELEM_ADHOC_SPEED = "a_s"; + final static String AO_TELEM_ADHOC_BARO = "a_b"; + + /* + * GPS values + * + * Name Value + * g_s GPS state (string): + * l locked + * u unlocked + * e error (missing or broken) + * g_n Number of sats used in solution + * g_ns Latitude (degrees * 10e7) + * g_ew Longitude (degrees * 10e7) + * g_a Altitude (integer meters) + * g_Y GPS year (integer) + * g_M GPS month (integer - 1-12) + * g_D GPS day (integer - 1-31) + * g_h GPS hour (integer - 0-23) + * g_m GPS minute (integer - 0-59) + * g_s GPS second (integer - 0-59) + * g_v GPS vertical speed (integer, cm/sec) + * g_s GPS horizontal speed (integer, cm/sec) + * g_c GPS course (integer, 0-359) + * g_hd GPS hdop (integer * 10) + * g_vd GPS vdop (integer * 10) + * g_he GPS h error (integer) + * g_ve GPS v error (integer) + */ + + final static String AO_TELEM_GPS_STATE = "g"; + final static String AO_TELEM_GPS_STATE_LOCKED = "l"; + final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; + final static String AO_TELEM_GPS_STATE_ERROR = "e"; + final static String AO_TELEM_GPS_NUM_SAT = "g_n"; + final static String AO_TELEM_GPS_LATITUDE = "g_ns"; + final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; + final static String AO_TELEM_GPS_ALTITUDE = "g_a"; + final static String AO_TELEM_GPS_YEAR = "g_Y"; + final static String AO_TELEM_GPS_MONTH = "g_M"; + final static String AO_TELEM_GPS_DAY = "g_D"; + final static String AO_TELEM_GPS_HOUR = "g_h"; + final static String AO_TELEM_GPS_MINUTE = "g_m"; + final static String AO_TELEM_GPS_SECOND = "g_s"; + final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; + final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; + final static String AO_TELEM_GPS_COURSE = "g_c"; + final static String AO_TELEM_GPS_HDOP = "g_hd"; + final static String AO_TELEM_GPS_VDOP = "g_vd"; + final static String AO_TELEM_GPS_HERROR = "g_he"; + final static String AO_TELEM_GPS_VERROR = "g_ve"; + + /* + * GPS satellite values + * + * Name Value + * s_n Number of satellites reported (integer) + * s_v0 Space vehicle ID (integer) for report 0 + * s_c0 C/N0 number (integer) for report 0 + * s_v1 Space vehicle ID (integer) for report 1 + * s_c1 C/N0 number (integer) for report 1 + * ... + */ + + final static String AO_TELEM_SAT_NUM = "s_n"; + final static String AO_TELEM_SAT_SVID = "s_v"; + final static String AO_TELEM_SAT_C_N_0 = "s_c"; + + static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { + AltosTelemetryRecord r = AltosTelemetryRecord.parse(line); + + return r.update_state(previous); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java new file mode 100644 index 00000000..f4b4029f --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java @@ -0,0 +1,109 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosTelemetryIterable extends AltosRecordIterable { + TreeSet records; + + public Iterator iterator () { + return records.iterator(); + } + + boolean has_gps = false; + boolean has_accel = false; + boolean has_ignite = false; + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; }; + + public AltosTelemetryIterable (FileInputStream input) { + boolean saw_boost = false; + int current_tick = 0; + int boost_tick = 0; + + AltosRecord previous = null; + records = new TreeSet (); + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) { + break; + } + try { + AltosRecord record = AltosTelemetry.parse(line, previous); + if (record == null) + break; + if (records.isEmpty()) { + current_tick = record.tick; + } else { + int tick = record.tick; + while (tick < current_tick - 0x1000) + tick += 0x10000; + current_tick = tick; + record.tick = current_tick; + } + if (!saw_boost && record.state >= AltosLib.ao_flight_boost) + { + saw_boost = true; + boost_tick = record.tick; + } + if (record.accel != AltosRecord.MISSING) + has_accel = true; + if (record.gps != null) + has_gps = true; + if (record.main != AltosRecord.MISSING) + has_ignite = true; + if (previous != null && previous.tick != record.tick) + records.add(previous); + previous = record; + } catch (ParseException pe) { + System.out.printf("parse exception %s\n", pe.getMessage()); + } catch (AltosCRCException ce) { + } + } + } catch (IOException io) { + System.out.printf("io exception\n"); + } + + if (previous != null) + records.add(previous); + + /* Adjust all tick counts to match expected eeprom values, + * which starts with a 16-bit tick count 16 samples before boost + */ + + int tick_adjust = (boost_tick - 16) & 0xffff0000; + for (AltosRecord r : this) + r.tick -= tick_adjust; + boost_tick -= tick_adjust; + + /* adjust all tick counts to be relative to boost time */ + for (AltosRecord r : this) + r.time = (r.tick - boost_tick) / 100.0; + + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java new file mode 100644 index 00000000..003cb6a9 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java @@ -0,0 +1,63 @@ +/* + * 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.AltosLib; +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryMap extends HashMap { + public boolean has(String key) { + return containsKey(key); + } + + public String get_string(String key) throws ParseException { + if (!has(key)) + throw new ParseException ("missing " + key, 0); + return (String) get(key); + } + + public String get_string(String key, String def) { + if (has(key)) + return get(key); + else + return def; + } + + public int get_int(String key) throws ParseException { + return AltosParse.parse_int(get_string(key)); + } + + public int get_int(String key, int def) throws ParseException { + if (has(key)) + return get_int(key); + else + return def; + } + + public double get_double(String key, double def, double scale) throws ParseException { + if (has(key)) + return get_int(key) * scale; + else + return def; + } + + public AltosTelemetryMap(String[] words, int start) { + for (int i = start; i < words.length - 1; i += 2) + put(words[i], words[i+1]); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java new file mode 100644 index 00000000..67ac1b65 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java @@ -0,0 +1,119 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.io.*; +import java.util.concurrent.*; + +public class AltosTelemetryReader extends AltosFlightReader { + AltosLink link; + AltosLog log; + AltosRecord previous; + double frequency; + int telemetry; + + LinkedBlockingQueue telem; + + public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { + AltosLine l = telem.take(); + if (l.line == null) + throw new IOException("IO error"); + AltosRecord next = AltosTelemetry.parse(l.line, previous); + previous = next; + return next; + } + + public void flush() { + telem.clear(); + } + + public void close(boolean interrupted) { + link.remove_monitor(telem); + log.close(); + link.close(); + } + + public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + link.set_radio_frequency(frequency); + } + + public boolean supports_telemetry(int telemetry) { + + try { + /* Version 1.0 or later firmware supports all telemetry formats */ + if (serial.config_data().compare_version("1.0") >= 0) + return true; + + /* Version 0.9 firmware only supports 0.9 telemetry */ + if (serial.config_data().compare_version("0.9") >= 0) { + if (telemetry == Altos.ao_telemetry_0_9) + return true; + else + return false; + } + + /* Version 0.8 firmware only supports 0.8 telemetry */ + if (telemetry == Altos.ao_telemetry_0_8) + return true; + else + return false; + } catch (InterruptedException ie) { + return true; + } catch (TimeoutException te) { + return true; + } + } + + public void save_frequency() { + AltosPreferences.set_frequency(link.serial, frequency); + } + + public void set_telemetry(int in_telemetry) { + telemetry = in_telemetry; + link.set_telemetry(telemetry); + } + + public void save_telemetry() { + AltosPreferences.set_telemetry(link.serial, telemetry); + } + + public void set_monitor(boolean monitor) { + link.set_monitor(monitor); + } + + public File backing_file() { + return log.file(); + } + + public AltosTelemetryReader (AltosLink in_link) + throws IOException, InterruptedException, TimeoutException { + link = in_link; + log = new AltosLog(link); + name = link.name; + previous = null; + telem = new LinkedBlockingQueue(); + frequency = AltosPreferences.frequency(link.serial); + set_frequency(frequency); + telemetry = AltosPreferences.telemetry(link.serial); + set_telemetry(telemetry); + link.add_monitor(telem); + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java new file mode 100644 index 00000000..367c148d --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java @@ -0,0 +1,126 @@ +/* + * 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.AltosLib; + +public abstract class AltosTelemetryRecord { + + long received_time; + abstract public AltosRecord update_state(AltosRecord previous); + + static boolean cksum(int[] bytes) { + int sum = 0x5a; + for (int i = 1; i < bytes.length - 1; i++) + sum += bytes[i]; + sum &= 0xff; + return sum == bytes[bytes.length - 1]; + } + + final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); + final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); + final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; + + final static int packet_type_TM_sensor = 0x01; + final static int packet_type_Tm_sensor = 0x02; + final static int packet_type_Tn_sensor = 0x03; + final static int packet_type_configuration = 0x04; + final static int packet_type_location = 0x05; + final static int packet_type_satellite = 0x06; + final static int packet_type_companion = 0x07; + + static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + int[] bytes; + try { + bytes = Altos.hexbytes(hex); + } catch (NumberFormatException ne) { + throw new ParseException(ne.getMessage(), 0); + } + + /* one for length, one for checksum */ + if (bytes[0] != bytes.length - 2) + throw new ParseException(String.format("invalid length %d != %d\n", + bytes[0], + bytes.length - 2), 0); + if (!cksum(bytes)) + throw new ParseException(String.format("invalid line \"%s\"", hex), 0); + + int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; + int status = Altos.uint8(bytes, bytes.length - 2); + + if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) + throw new AltosCRCException(rssi); + + /* length, data ..., rssi, status, checksum -- 4 bytes extra */ + switch (bytes.length) { + case Altos.ao_telemetry_standard_len + 4: + int type = Altos.uint8(bytes, 4 + 1); + switch (type) { + case packet_type_TM_sensor: + case packet_type_Tm_sensor: + case packet_type_Tn_sensor: + r = new AltosTelemetryRecordSensor(bytes, rssi); + break; + case packet_type_configuration: + r = new AltosTelemetryRecordConfiguration(bytes); + break; + case packet_type_location: + r = new AltosTelemetryRecordLocation(bytes); + break; + case packet_type_satellite: + r = new AltosTelemetryRecordSatellite(bytes); + break; + case packet_type_companion: + r = new AltosTelemetryRecordCompanion(bytes); + break; + default: + r = new AltosTelemetryRecordRaw(bytes); + break; + } + break; + case Altos.ao_telemetry_0_9_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + case Altos.ao_telemetry_0_8_len + 4: + r = new AltosTelemetryRecordLegacy(bytes, rssi, status); + break; + default: + throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); + } + r.received_time = System.currentTimeMillis(); + return r; + } + + public static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + String[] word = line.split("\\s+"); + int i =0; + if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(word[i++], "RSSI"); + throw new AltosCRCException(AltosParse.parse_int(word[i++])); + } + + if (word[i].equals("TELEM")) + r = parse_hex(word[i+1]); + else + r = new AltosTelemetryRecordLegacy(line); + return r; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java new file mode 100644 index 00000000..6ad17244 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java @@ -0,0 +1,52 @@ +/* + * 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.AltosLib; + +public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { + + AltosRecordCompanion companion; + + public AltosTelemetryRecordCompanion(int[] in_bytes) { + super(in_bytes); + + int off = 0; + if (uint8(6) == 0) + off = 1; + int channels = uint8(7+off); + + if (off != 0 && channels >= 12) + channels = 11; + + companion = new AltosRecordCompanion(channels); + companion.tick = tick; + companion.board_id = uint8(5); + companion.update_period = uint8(6+off); + for (int i = 0; i < companion.companion_data.length; i++) + companion.companion_data[i] = uint16(8 + off + i * 2); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + next.companion = companion; + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + + companion.tick = tick; + return next; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java new file mode 100644 index 00000000..25242edc --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java @@ -0,0 +1,64 @@ +/* + * 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.AltosLib; + + +public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { + int device_type; + int flight; + int config_major; + int config_minor; + int apogee_delay; + int main_deploy; + int flight_log_max; + String callsign; + String version; + + public AltosTelemetryRecordConfiguration(int[] in_bytes) { + super(in_bytes); + + device_type = uint8(5); + flight = uint16(6); + config_major = uint8(8); + config_minor = uint8(9); + apogee_delay = uint16(10); + main_deploy = uint16(12); + flight_log_max = uint16(14); + callsign = string(16, 8); + version = string(24, 8); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + next.device_type = device_type; + next.flight = flight; + next.config_major = config_major; + next.config_minor = config_minor; + next.apogee_delay = apogee_delay; + next.main_deploy = main_deploy; + next.flight_log_max = flight_log_max; + + next.callsign = callsign; + next.firmware_version = version; + + next.seen |= AltosRecord.seen_deploy | AltosRecord.seen_flight; + + return next; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java new file mode 100644 index 00000000..5e157a54 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java @@ -0,0 +1,43 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordGeneral { + + static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { + AltosTelemetryRecord r; + + String[] word = line.split("\\s+"); + int i =0; + if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(word[i++], "RSSI"); + throw new AltosCRCException(AltosParse.parse_int(word[i++])); + } + + if (word[i].equals("TELEM")) + r = AltosTelemetryRecordRaw.parse(word[i+1]); + else + r = new AltosTelemetryRecordLegacy(line); + return r; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java new file mode 100644 index 00000000..8e3713cc --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java @@ -0,0 +1,521 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +/* + * Telemetry data contents + */ + + +/* + * The packet format is a simple hex dump of the raw telemetry frame. + * It starts with 'TELEM', then contains hex digits with a checksum as the last + * byte on the line. + * + * Version 4 is a replacement with consistent syntax. Each telemetry line + * contains a sequence of space-separated names and values, the values are + * either integers or strings. The names are all unique. All values are + * optional + * + * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 + * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 + * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 + * + * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 + * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 + * + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + * + * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports + * in 1/2dB increments while this protocol provides only integers. So, + * the syntax didn't change just the interpretation of the RSSI + * values. + * + * Version 2 of the telemetry data stream is a bit of a mess, with no + * consistent formatting. In particular, the GPS data is formatted for + * viewing instead of parsing. However, the key feature is that every + * telemetry line contains all of the information necessary to + * describe the current rocket state, including the calibration values + * for accelerometer and barometer. + * + * GPS unlocked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ + * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ + * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 + * + * GPS locked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ + * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ + * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ + * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ + * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ + * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 + * + */ + +public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { + /* + * General header fields + * + * Name Value + * + * VERSION Telemetry version number (4 or more). Must be first. + * c Callsign (string, no spaces allowed) + * n Flight unit serial number (integer) + * f Flight number (integer) + * r Packet RSSI value (integer) + * s Flight computer state (string, no spaces allowed) + * t Flight computer clock (integer in centiseconds) + */ + + final static String AO_TELEM_VERSION = "VERSION"; + final static String AO_TELEM_CALL = "c"; + final static String AO_TELEM_SERIAL = "n"; + final static String AO_TELEM_FLIGHT = "f"; + final static String AO_TELEM_RSSI = "r"; + final static String AO_TELEM_STATE = "s"; + final static String AO_TELEM_TICK = "t"; + + /* + * Raw sensor values + * + * Name Value + * r_a Accelerometer reading (integer) + * r_b Barometer reading (integer) + * r_t Thermometer reading (integer) + * r_v Battery reading (integer) + * r_d Drogue continuity (integer) + * r_m Main continuity (integer) + */ + + final static String AO_TELEM_RAW_ACCEL = "r_a"; + final static String AO_TELEM_RAW_BARO = "r_b"; + final static String AO_TELEM_RAW_THERMO = "r_t"; + final static String AO_TELEM_RAW_BATT = "r_v"; + final static String AO_TELEM_RAW_DROGUE = "r_d"; + final static String AO_TELEM_RAW_MAIN = "r_m"; + + /* + * Sensor calibration values + * + * Name Value + * c_a Ground accelerometer reading (integer) + * c_b Ground barometer reading (integer) + * c_p Accelerometer reading for +1g + * c_m Accelerometer reading for -1g + */ + + final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; + final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; + final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; + final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; + + /* + * Kalman state values + * + * Name Value + * k_h Height above pad (integer, meters) + * k_s Vertical speeed (integer, m/s * 16) + * k_a Vertical acceleration (integer, m/s² * 16) + */ + + final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; + final static String AO_TELEM_KALMAN_SPEED = "k_s"; + final static String AO_TELEM_KALMAN_ACCEL = "k_a"; + + /* + * Ad-hoc flight values + * + * Name Value + * a_a Acceleration (integer, sensor units) + * a_s Speed (integer, integrated acceleration value) + * a_b Barometer reading (integer, sensor units) + */ + + final static String AO_TELEM_ADHOC_ACCEL = "a_a"; + final static String AO_TELEM_ADHOC_SPEED = "a_s"; + final static String AO_TELEM_ADHOC_BARO = "a_b"; + + /* + * GPS values + * + * Name Value + * g_s GPS state (string): + * l locked + * u unlocked + * e error (missing or broken) + * g_n Number of sats used in solution + * g_ns Latitude (degrees * 10e7) + * g_ew Longitude (degrees * 10e7) + * g_a Altitude (integer meters) + * g_Y GPS year (integer) + * g_M GPS month (integer - 1-12) + * g_D GPS day (integer - 1-31) + * g_h GPS hour (integer - 0-23) + * g_m GPS minute (integer - 0-59) + * g_s GPS second (integer - 0-59) + * g_v GPS vertical speed (integer, cm/sec) + * g_s GPS horizontal speed (integer, cm/sec) + * g_c GPS course (integer, 0-359) + * g_hd GPS hdop (integer * 10) + * g_vd GPS vdop (integer * 10) + * g_he GPS h error (integer) + * g_ve GPS v error (integer) + */ + + final static String AO_TELEM_GPS_STATE = "g"; + final static String AO_TELEM_GPS_STATE_LOCKED = "l"; + final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; + final static String AO_TELEM_GPS_STATE_ERROR = "e"; + final static String AO_TELEM_GPS_NUM_SAT = "g_n"; + final static String AO_TELEM_GPS_LATITUDE = "g_ns"; + final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; + final static String AO_TELEM_GPS_ALTITUDE = "g_a"; + final static String AO_TELEM_GPS_YEAR = "g_Y"; + final static String AO_TELEM_GPS_MONTH = "g_M"; + final static String AO_TELEM_GPS_DAY = "g_D"; + final static String AO_TELEM_GPS_HOUR = "g_h"; + final static String AO_TELEM_GPS_MINUTE = "g_m"; + final static String AO_TELEM_GPS_SECOND = "g_s"; + final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; + final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; + final static String AO_TELEM_GPS_COURSE = "g_c"; + final static String AO_TELEM_GPS_HDOP = "g_hd"; + final static String AO_TELEM_GPS_VDOP = "g_vd"; + final static String AO_TELEM_GPS_HERROR = "g_he"; + final static String AO_TELEM_GPS_VERROR = "g_ve"; + + /* + * GPS satellite values + * + * Name Value + * s_n Number of satellites reported (integer) + * s_v0 Space vehicle ID (integer) for report 0 + * s_c0 C/N0 number (integer) for report 0 + * s_v1 Space vehicle ID (integer) for report 1 + * s_c1 C/N0 number (integer) for report 1 + * ... + */ + + final static String AO_TELEM_SAT_NUM = "s_n"; + final static String AO_TELEM_SAT_SVID = "s_v"; + final static String AO_TELEM_SAT_C_N_0 = "s_c"; + + AltosRecord record; + + private void parse_v4(String[] words, int i) throws ParseException { + AltosTelemetryMap map = new AltosTelemetryMap(words, i); + + record.callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); + record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING); + record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); + record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); + record.state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + record.tick = map.get_int(AO_TELEM_TICK, 0); + + /* raw sensor values */ + record.accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING); + record.pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING); + record.temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING); + record.batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING); + record.drogue = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING); + record.main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING); + + /* sensor calibration information */ + record.ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING); + record.ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING); + record.accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING); + record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING); + + /* flight computer values */ + record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); + record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); + record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); + + record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING); + record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); + record.flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING); + + if (map.has(AO_TELEM_GPS_STATE)) { + record.gps = new AltosGPS(map); + record.new_gps = true; + } + else + record.gps = null; + } + + private void parse_legacy(String[] words, int i) throws ParseException { + + AltosParse.word (words[i++], "CALL"); + record.callsign = words[i++]; + + AltosParse.word (words[i++], "SERIAL"); + record.serial = AltosParse.parse_int(words[i++]); + + if (record.version >= 2) { + AltosParse.word (words[i++], "FLIGHT"); + record.flight = AltosParse.parse_int(words[i++]); + } else + record.flight = 0; + + AltosParse.word(words[i++], "RSSI"); + record.rssi = AltosParse.parse_int(words[i++]); + + /* Older telemetry data had mis-computed RSSI value */ + if (record.version <= 2) + record.rssi = (record.rssi + 74) / 2 - 74; + + AltosParse.word(words[i++], "STATUS"); + record.status = AltosParse.parse_hex(words[i++]); + + AltosParse.word(words[i++], "STATE"); + record.state = Altos.state(words[i++]); + + record.tick = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a:"); + record.accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "p:"); + record.pres = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "t:"); + record.temp = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "v:"); + record.batt = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "d:"); + record.drogue = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "m:"); + record.main = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fa:"); + record.flight_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "ga:"); + record.ground_accel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fv:"); + record.flight_vel = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "fp:"); + record.flight_pres = AltosParse.parse_int(words[i++]); + + /* Old TeleDongle code with kalman-reporting TeleMetrum code */ + if ((record.flight_vel & 0xffff0000) == 0x80000000) { + record.speed = ((short) record.flight_vel) / 16.0; + record.acceleration = record.flight_accel / 16.0; + record.height = record.flight_pres; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + record.flight_accel = AltosRecord.MISSING; + } + + AltosParse.word(words[i++], "gp:"); + record.ground_pres = AltosParse.parse_int(words[i++]); + + if (record.version >= 1) { + AltosParse.word(words[i++], "a+:"); + record.accel_plus_g = AltosParse.parse_int(words[i++]); + + AltosParse.word(words[i++], "a-:"); + record.accel_minus_g = AltosParse.parse_int(words[i++]); + } else { + record.accel_plus_g = record.ground_accel; + record.accel_minus_g = record.ground_accel + 530; + } + + record.gps = new AltosGPS(words, i, record.version); + record.new_gps = true; + } + + public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { + String[] words = line.split("\\s+"); + int i = 0; + + record = new AltosRecord(); + + if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { + i += 2; + AltosParse.word(words[i++], "RSSI"); + record.rssi = AltosParse.parse_int(words[i++]); + throw new AltosCRCException(record.rssi); + } + if (words[i].equals("CALL")) { + record.version = 0; + } else { + AltosParse.word (words[i++], "VERSION"); + record.version = AltosParse.parse_int(words[i++]); + } + + if (record.version < 4) + parse_legacy(words, i); + else + parse_v4(words, i); + } + + /* + * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that + */ + + int[] bytes; + int adjust; + + private int int8(int i) { + return AltosLib.int8(bytes, i + 1 + adjust); + } + private int uint8(int i) { + return AltosLib.uint8(bytes, i + 1 + adjust); + } + private int int16(int i) { + return AltosLib.int16(bytes, i + 1 + adjust); + } + private int uint16(int i) { + return AltosLib.uint16(bytes, i + 1 + adjust); + } + private int uint32(int i) { + return AltosLib.uint32(bytes, i + 1 + adjust); + } + private String string(int i, int l) { + return AltosLib.string(bytes, i + 1 + adjust, l); + } + + static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); + static final int AO_GPS_NUM_SAT_SHIFT = (0); + + static final int AO_GPS_VALID = (1 << 4); + static final int AO_GPS_RUNNING = (1 << 5); + static final int AO_GPS_DATE_VALID = (1 << 6); + static final int AO_GPS_COURSE_VALID = (1 << 7); + + public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { + record = new AltosRecord(); + + bytes = in_bytes; + record.version = 4; + adjust = 0; + + if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { + record.serial = uint8(0); + adjust = -1; + } else + record.serial = uint16(0); + + record.seen = AltosRecord.seen_flight | AltosRecord.seen_sensor | AltosRecord.seen_temp_volt | AltosRecord.seen_deploy; + + record.callsign = string(62, 8); + record.flight = uint16(2); + record.rssi = in_rssi; + record.status = in_status; + record.state = uint8(4); + record.tick = uint16(21); + record.accel = int16(23); + record.pres = int16(25); + record.temp = int16(27); + record.batt = int16(29); + record.drogue = int16(31); + record.main = int16(33); + + record.ground_accel = int16(7); + record.ground_pres = int16(15); + record.accel_plus_g = int16(17); + record.accel_minus_g = int16(19); + + if (uint16(11) == 0x8000) { + record.acceleration = int16(5); + record.speed = int16(9); + record.height = int16(13); + record.flight_accel = AltosRecord.MISSING; + record.flight_vel = AltosRecord.MISSING; + record.flight_pres = AltosRecord.MISSING; + } else { + record.flight_accel = int16(5); + record.flight_vel = uint32(9); + record.flight_pres = int16(13); + record.acceleration = AltosRecord.MISSING; + record.speed = AltosRecord.MISSING; + record.height = AltosRecord.MISSING; + } + + record.gps = null; + + int gps_flags = uint8(41); + + if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { + record.gps = new AltosGPS(); + record.new_gps = true; + + record.seen |= record.seen_gps_time | record.seen_gps_lat | record.seen_gps_lon; + record.gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); + record.gps.locked = (gps_flags & AO_GPS_VALID) != 0; + record.gps.connected = true; + record.gps.lat = uint32(42) / 1.0e7; + record.gps.lon = uint32(46) / 1.0e7; + record.gps.alt = int16(50); + record.gps.ground_speed = uint16(52) / 100.0; + record.gps.course = uint8(54) * 2; + record.gps.hdop = uint8(55) / 5.0; + record.gps.h_error = uint16(58); + record.gps.v_error = uint16(60); + + int n_tracking_reported = uint8(70); + if (n_tracking_reported > 12) + n_tracking_reported = 12; + int n_tracking_actual = 0; + for (int i = 0; i < n_tracking_reported; i++) { + if (uint8(71 + i*2) != 0) + n_tracking_actual++; + } + if (n_tracking_actual > 0) { + record.gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; + + n_tracking_actual = 0; + for (int i = 0; i < n_tracking_reported; i++) { + int svid = uint8(71 + i*2); + int c_n0 = uint8(72 + i*2); + if (svid != 0) + record.gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); + } + } + } + + record.time = 0.0; + } + + public AltosRecord update_state(AltosRecord previous) { + return record; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java new file mode 100644 index 00000000..cddb773d --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java @@ -0,0 +1,93 @@ +/* + * 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.AltosLib; + + +public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { + int flags; + int altitude; + int latitude; + int longitude; + int year; + int month; + int day; + int hour; + int minute; + int second; + int pdop; + int hdop; + int vdop; + int mode; + int ground_speed; + int climb_rate; + int course; + + public AltosTelemetryRecordLocation(int[] in_bytes) { + super(in_bytes); + + flags = uint8(5); + altitude = int16(6); + latitude = uint32(8); + longitude = uint32(12); + year = uint8(16); + month = uint8(17); + day = uint8(18); + hour = uint8(19); + minute = uint8(20); + second = uint8(21); + pdop = uint8(22); + hdop = uint8(23); + vdop = uint8(24); + mode = uint8(25); + ground_speed = uint16(26); + climb_rate = int16(28); + course = uint8(30); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + next.gps.nsat = flags & 0xf; + next.gps.locked = (flags & (1 << 4)) != 0; + next.gps.connected = (flags & (1 << 5)) != 0; + + if (next.gps.locked) { + next.gps.lat = latitude * 1.0e-7; + next.gps.lon = longitude * 1.0e-7; + next.gps.alt = altitude; + next.gps.year = 2000 + year; + next.gps.month = month; + next.gps.day = day; + next.gps.hour = hour; + next.gps.minute = minute; + next.gps.second = second; + next.gps.ground_speed = ground_speed * 1.0e-2; + next.gps.course = course * 2; + next.gps.climb_rate = climb_rate * 1.0e-2; + next.gps.hdop = hdop; + next.gps.vdop = vdop; + next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon; + next.new_gps = true; + } + + return next; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java new file mode 100644 index 00000000..43d0f17a --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java @@ -0,0 +1,77 @@ +/* + * 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.AltosLib; + +import java.lang.*; +import java.text.*; +import java.util.HashMap; + +public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { + int[] bytes; + int serial; + int tick; + int type; + + long received_time; + + public int int8(int off) { + return AltosLib.int8(bytes, off + 1); + } + + public int uint8(int off) { + return AltosLib.uint8(bytes, off + 1); + } + + public int int16(int off) { + return AltosLib.int16(bytes, off + 1); + } + + public int uint16(int off) { + return AltosLib.uint16(bytes, off + 1); + } + + public int uint32(int off) { + return AltosLib.uint32(bytes, off + 1); + } + + public String string(int off, int l) { + return AltosLib.string(bytes, off + 1, l); + } + + public AltosTelemetryRecordRaw(int[] in_bytes) { + bytes = in_bytes; + serial = uint16(0); + tick = uint16(2); + type = uint8(4); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next; + if (previous != null) + next = new AltosRecord(previous); + else + next = new AltosRecord(); + next.serial = serial; + next.tick = tick; + return next; + } + + public long received_time() { + return received_time; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java new file mode 100644 index 00000000..2526afb6 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java @@ -0,0 +1,52 @@ +/* + * 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.AltosLib; + +public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { + int channels; + AltosGPSSat[] sats; + + public AltosTelemetryRecordSatellite(int[] in_bytes) { + super(in_bytes); + + channels = uint8(5); + if (channels > 12) + channels = 12; + if (channels == 0) + sats = null; + else { + sats = new AltosGPSSat[channels]; + for (int i = 0; i < channels; i++) { + int svid = uint8(6 + i * 2 + 0); + int c_n_1 = uint8(6 + i * 2 + 1); + sats[i] = new AltosGPSSat(svid, c_n_1); + } + } + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + if (next.gps == null) + next.gps = new AltosGPS(); + + next.gps.cc_gps_sat = sats; + + return next; + } +} diff --git a/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java new file mode 100644 index 00000000..cfaf90b0 --- /dev/null +++ b/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java @@ -0,0 +1,104 @@ +/* + * 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.AltosLib; + + +public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { + int state; + int accel; + int pres; + int temp; + int v_batt; + int sense_d; + int sense_m; + + int acceleration; + int speed; + int height; + + int ground_accel; + int ground_pres; + int accel_plus_g; + int accel_minus_g; + + int rssi; + + public AltosTelemetryRecordSensor(int[] in_bytes, int in_rssi) { + super(in_bytes); + state = uint8(5); + + accel = int16(6); + pres = int16(8); + temp = int16(10); + v_batt = int16(12); + sense_d = int16(14); + sense_m = int16(16); + + acceleration = int16(18); + speed = int16(20); + height = int16(22); + + ground_pres = int16(24); + ground_accel = int16(26); + accel_plus_g = int16(28); + accel_minus_g = int16(30); + + rssi = in_rssi; + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord next = super.update_state(previous); + + next.state = state; + if (type == packet_type_TM_sensor) + next.accel = accel; + else + next.accel = AltosRecord.MISSING; + next.pres = pres; + next.temp = temp; + next.batt = v_batt; + if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) { + next.drogue = sense_d; + next.main = sense_m; + } else { + next.drogue = AltosRecord.MISSING; + next.main = AltosRecord.MISSING; + } + + next.acceleration = acceleration / 16.0; + next.speed = speed / 16.0; + next.height = height; + + next.ground_pres = ground_pres; + if (type == packet_type_TM_sensor) { + next.ground_accel = ground_accel; + next.accel_plus_g = accel_plus_g; + next.accel_minus_g = accel_minus_g; + } else { + next.ground_accel = AltosRecord.MISSING; + next.accel_plus_g = AltosRecord.MISSING; + next.accel_minus_g = AltosRecord.MISSING; + } + + next.rssi = rssi; + + next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; + + return next; + } +} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 7a3c53e7..d494547b 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=libaltos altoslib +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/bin:libaltos:$(FREETTS)/*:/usr/share/java/*" +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:libaltos:$(FREETTS)/*:/usr/share/java/*" bin_SCRIPTS=altosui @@ -287,9 +287,9 @@ build-altos64-dll: $(ALTOSLIB_CLASS): -rm -f "$@" - $(LN_S) altoslib/"$@" . + $(LN_S) ../altoslib/"$@" . -$(FREETTS_CLASS): +$(FREETTS_CLASS): ../altoslib/"$@" -rm -f "$@" $(LN_S) "$(FREETTS)"/"$@" . diff --git a/altosui/altoslib/.gitignore b/altosui/altoslib/.gitignore deleted file mode 100644 index ad2f8cbf..00000000 --- a/altosui/altoslib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -classAltosLib.stamp diff --git a/altosui/altoslib/Makefile.am b/altosui/altoslib/Makefile.am deleted file mode 100644 index 2ddd24e6..00000000 --- a/altosui/altoslib/Makefile.am +++ /dev/null @@ -1,69 +0,0 @@ -AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation - -JAVAROOT=bin - -CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="bin:$(FREETTS)/*:/usr/share/java/*" - -SRC=src/org/altusmetrum/AltosLib -BIN=bin/org/altusmetrum/AltosLib - -AltosLibdir = $(datadir)/java - -AltosLib_JAVA = \ - $(SRC)/AltosLib.java \ - $(SRC)/AltosConfigData.java \ - $(SRC)/AltosConvert.java \ - $(SRC)/AltosCRCException.java \ - $(SRC)/AltosEepromChunk.java \ - $(SRC)/AltosEepromIterable.java \ - $(SRC)/AltosEepromLog.java \ - $(SRC)/AltosEepromRecord.java \ - $(SRC)/AltosEepromTeleScience.java \ - $(SRC)/AltosFile.java \ - $(SRC)/AltosFlightReader.java \ - $(SRC)/AltosFrequency.java \ - $(SRC)/AltosGPS.java \ - $(SRC)/AltosGPSSat.java \ - $(SRC)/AltosGreatCircle.java \ - $(SRC)/AltosLine.java \ - $(SRC)/AltosLink.java \ - $(SRC)/AltosLog.java \ - $(SRC)/AltosParse.java \ - $(SRC)/AltosPreferences.java \ - $(SRC)/AltosRecordCompanion.java \ - $(SRC)/AltosRecordIterable.java \ - $(SRC)/AltosRecord.java \ - $(SRC)/AltosReplayReader.java \ - $(SRC)/AltosState.java \ - $(SRC)/AltosTelemetry.java \ - $(SRC)/AltosTelemetryIterable.java \ - $(SRC)/AltosTelemetryMap.java \ - $(SRC)/AltosTelemetryReader.java \ - $(SRC)/AltosTelemetryRecordCompanion.java \ - $(SRC)/AltosTelemetryRecordConfiguration.java \ - $(SRC)/AltosTelemetryRecordGeneral.java \ - $(SRC)/AltosTelemetryRecord.java \ - $(SRC)/AltosTelemetryRecordLegacy.java \ - $(SRC)/AltosTelemetryRecordLocation.java \ - $(SRC)/AltosTelemetryRecordRaw.java \ - $(SRC)/AltosTelemetryRecordSatellite.java \ - $(SRC)/AltosTelemetryRecordSensor.java - -JAR=AltosLib.jar - -all-local: $(JAR) - -clean-local: - -rm -rf bin $(JAR) - -install-AltosLibJAVA: $(JAR) - @$(NORMAL_INSTALL) - test -z "$(AltosLibdir)" || $(MKDIR_P) "$(DESTDIR)$(AltosLibdir)" - echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(AltosLibdir)/$(JAR)"; \ - $(INSTALL_DATA) "$<" "$(DESTDIR)$(AltosLibdir)" - -bin: - mkdir -p bin - -$(JAR): classAltosLib.stamp - jar cf $@ -C bin org diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java deleted file mode 100644 index 101c5363..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosCRCException.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.AltosLib; - -public class AltosCRCException extends Exception { - public int rssi; - - public AltosCRCException (int in_rssi) { - rssi = in_rssi; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java deleted file mode 100644 index 4ad4e58a..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConfigData.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; -import org.altusmetrum.AltosLib.*; - -public class AltosConfigData implements Iterable { - - /* Version information */ - public String manufacturer; - public String product; - public String version; - public int log_format; - public int serial; - - /* Strings returned */ - public LinkedList lines; - - /* Config information */ - public int config_major; - public int config_minor; - public int main_deploy; - public int apogee_delay; - public int radio_channel; - public int radio_setting; - public int radio_frequency; - public String callsign; - public int accel_cal_plus, accel_cal_minus; - public int radio_calibration; - public int flight_log_max; - public int ignite_mode; - public int stored_flight; - public int storage_size; - public int storage_erase_unit; - - public static String get_string(String line, String label) throws ParseException { - if (line.startsWith(label)) { - String quoted = line.substring(label.length()).trim(); - - if (quoted.startsWith("\"")) - quoted = quoted.substring(1); - if (quoted.endsWith("\"")) - quoted = quoted.substring(0,quoted.length()-1); - return quoted; - } - throw new ParseException("mismatch", 0); - } - - public static int get_int(String line, String label) throws NumberFormatException, ParseException { - if (line.startsWith(label)) { - String tail = line.substring(label.length()).trim(); - String[] tokens = tail.split("\\s+"); - if (tokens.length > 0) - return Integer.parseInt(tokens[0]); - } - throw new ParseException("mismatch", 0); - } - - public Iterator iterator() { - return lines.iterator(); - } - - public int log_available() { - switch (log_format) { - case AltosLib.AO_LOG_FORMAT_TINY: - if (stored_flight == 0) - return 1; - return 0; - default: - if (flight_log_max <= 0) - return 1; - int log_space = storage_size - storage_erase_unit; - int log_used = stored_flight * flight_log_max; - - if (log_used >= log_space) - return 0; - return (log_space - log_used) / flight_log_max; - } - } - - int[] parse_version(String v) { - String[] parts = v.split("\\."); - int r[] = new int[parts.length]; - - for (int i = 0; i < parts.length; i++) { - try { - r[i] = Altos.fromdec(parts[i]); - } catch (NumberFormatException n) { - r[i] = 0; - } - } - - return r; - } - - public int compare_version(String other) { - int[] me = parse_version(version); - int[] them = parse_version(other); - - int l = Math.min(me.length, them.length); - - for (int i = 0; i < l; i++) { - int d = me[i] - them[i]; - if (d != 0) - return d; - } - if (me.length > l) - return 1; - if (them.length > l) - return -1; - return 0; - } - - public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException { - link.printf("c s\np\nf\nl\nv\n"); - lines = new LinkedList(); - radio_setting = 0; - radio_frequency = 0; - stored_flight = 0; - for (;;) { - String line = link.get_reply(); - if (line == null) - throw new TimeoutException(); - if (line.contains("Syntax error")) - continue; - lines.add(line); - try { serial = get_int(line, "serial-number"); } catch (Exception e) {} - try { log_format = get_int(line, "log-format"); } catch (Exception e) {} - try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} - try { apogee_delay = get_int(line, "Apogee delay:"); } catch (Exception e) {} - try { radio_channel = get_int(line, "Radio channel:"); } catch (Exception e) {} - try { radio_setting = get_int(line, "Radio setting:"); } catch (Exception e) {} - try { - radio_frequency = get_int(line, "Frequency:"); - if (radio_frequency < 0) - radio_frequency = 434550; - } catch (Exception e) {} - try { - if (line.startsWith("Accel cal")) { - String[] bits = line.split("\\s+"); - if (bits.length >= 6) { - accel_cal_plus = Integer.parseInt(bits[3]); - accel_cal_minus = Integer.parseInt(bits[5]); - } - } - } catch (Exception e) {} - try { radio_calibration = get_int(line, "Radio cal:"); } catch (Exception e) {} - try { flight_log_max = get_int(line, "Max flight log:"); } catch (Exception e) {} - try { ignite_mode = get_int(line, "Ignite mode:"); } catch (Exception e) {} - try { callsign = get_string(line, "Callsign:"); } catch (Exception e) {} - try { version = get_string(line,"software-version"); } catch (Exception e) {} - try { product = get_string(line,"product"); } catch (Exception e) {} - - try { get_int(line, "flight"); stored_flight++; } catch (Exception e) {} - try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {} - try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} - - /* signals the end of the version info */ - if (line.startsWith("software-version")) - break; - } - } - -} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java deleted file mode 100644 index 3527b575..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosConvert.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * 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. - */ - -/* - * Sensor data conversion functions - */ -package org.altusmetrum.AltosLib; - -public class AltosConvert { - /* - * Pressure Sensor Model, version 1.1 - * - * written by Holly Grimes - * - * Uses the International Standard Atmosphere as described in - * "A Quick Derivation relating altitude to air pressure" (version 1.03) - * from the Portland State Aerospace Society, except that the atmosphere - * is divided into layers with each layer having a different lapse rate. - * - * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007 - * at site MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */ - return 0; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted altitude */ - for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) { - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - base_pressure *= Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - base_pressure *= Math.pow(base, exponent); - } - base_temperature += delta_z * lapse_rate[layer_number]; - } - - /* calculate the pressure at the inputted altitude */ - delta_z = altitude - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - pressure = base_pressure * Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - pressure = base_pressure * Math.pow(base, exponent); - } - - return pressure; - } - - -/* outputs the altitude associated with the given pressure. the altitude - returned is measured with respect to the mean sea level */ - public static double - pressure_to_altitude(double pressure) - { - - double next_base_temperature = LAYER0_BASE_TEMPERATURE; - double next_base_pressure = LAYER0_BASE_PRESSURE; - - double altitude; - double base_pressure; - double base_temperature; - double base; /* base for function to determine base pressure of next layer */ - double exponent; /* exponent for function to determine base pressure - of next layer */ - double coefficient; - int layer_number; /* identifies layer in the atmosphere */ - int delta_z; /* difference between two altitudes */ - - if (pressure < 0) /* illegal pressure */ - return -1; - if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */ - return MAXIMUM_ALTITUDE; - - /* calculate the base temperature and pressure for the atmospheric layer - associated with the inputted pressure. */ - layer_number = -1; - do { - layer_number++; - base_pressure = next_base_pressure; - base_temperature = next_base_temperature; - delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number]; - if (lapse_rate[layer_number] == 0.0) { - exponent = GRAVITATIONAL_ACCELERATION * delta_z - / AIR_GAS_CONSTANT / base_temperature; - next_base_pressure *= Math.exp(exponent); - } - else { - base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0; - exponent = GRAVITATIONAL_ACCELERATION / - (AIR_GAS_CONSTANT * lapse_rate[layer_number]); - next_base_pressure *= Math.pow(base, exponent); - } - next_base_temperature += delta_z * lapse_rate[layer_number]; - } - while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure); - - /* calculate the altitude associated with the inputted pressure */ - if (lapse_rate[layer_number] == 0.0) { - coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) - * base_temperature; - altitude = base_altitude[layer_number] - + coefficient * Math.log(pressure / base_pressure); - } - else { - base = pressure / base_pressure; - exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] - / GRAVITATIONAL_ACCELERATION; - coefficient = base_temperature / lapse_rate[layer_number]; - altitude = base_altitude[layer_number] - + coefficient * (Math.pow(base, exponent) - 1); - } - - return altitude; - } - - public static double - cc_battery_to_voltage(double battery) - { - return battery / 32767.0 * 5.0; - } - - public static double - cc_ignitor_to_voltage(double ignite) - { - return ignite / 32767 * 15.0; - } - - public static double radio_to_frequency(int freq, int setting, int cal, int channel) { - double f; - - if (freq > 0) - f = freq / 1000.0; - else { - if (setting <= 0) - setting = cal; - f = 434.550 * setting / cal; - /* Round to nearest 50KHz */ - f = Math.floor (20.0 * f + 0.5) / 20.0; - } - return f + channel * 0.100; - } - - public static int radio_frequency_to_setting(double frequency, int cal) { - double set = frequency / 434.550 * cal; - - return (int) Math.floor (set + 0.5); - } - - public static int radio_frequency_to_channel(double frequency) { - int channel = (int) Math.floor ((frequency - 434.550) / 0.100 + 0.5); - - if (channel < 0) - channel = 0; - if (channel > 9) - channel = 9; - return channel; - } - - public static double radio_channel_to_frequency(int channel) { - return 434.550 + channel * 0.100; - } - - public static int[] ParseHex(String line) { - String[] tokens = line.split("\\s+"); - int[] array = new int[tokens.length]; - - for (int i = 0; i < tokens.length; i++) - try { - array[i] = Integer.parseInt(tokens[i], 16); - } catch (NumberFormatException ne) { - return null; - } - return array; - } - - public static double meters_to_feet(double meters) { - return meters * (100 / (2.54 * 12)); - } - - public static double meters_to_mach(double meters) { - return meters / 343; /* something close to mach at usual rocket sites */ - } - - public static double meters_to_g(double meters) { - return meters / 9.80665; - } - - public static int checksum(int[] data, int start, int length) { - int csum = 0x5a; - for (int i = 0; i < length; i++) - csum += data[i + start]; - return csum & 0xff; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java deleted file mode 100644 index 6d889723..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromChunk.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.concurrent.*; - -public class AltosEepromChunk { - - public static final int chunk_size = 256; - public static final int per_line = 8; - - public int data[]; - public int address; - public ParseException parse_exception = null; - - int[] ParseHex(String line) { - String[] tokens = line.split("\\s+"); - int[] array = new int[tokens.length]; - - for (int i = 0; i < tokens.length; i++) - try { - array[i] = Integer.parseInt(tokens[i], 16); - } catch (NumberFormatException ne) { - return null; - } - return array; - } - - public int data(int offset) { - return data[offset]; - } - - public int data16(int offset) { - return data[offset] | (data[offset + 1] << 8); - } - - public int data32(int offset) { - return data[offset] | (data[offset + 1] << 8) | - (data[offset+2] << 16) | (data[offset+3] << 24); - } - - public boolean erased(int start, int len) { - for (int i = 0; i < len; i++) - if (data[start+i] != 0xff) - return false; - return true; - } - - public AltosEepromChunk(AltosLink link, int block, boolean flush) - throws TimeoutException, InterruptedException { - - int offset; - - data = new int[chunk_size]; - address = block * chunk_size; - if (flush) - link.flush_input(); - link.printf("e %x\n", block); - - for (offset = 0; offset < chunk_size; offset += per_line) { - try { - String line = link.get_reply(5000); - - if (line == null) - throw new TimeoutException(); - - int[] values = ParseHex(line); - - if (values == null || values.length != per_line + 1) - throw new ParseException(String.format("invalid line %s", line), 0); - if (values[0] != offset) - throw new ParseException(String.format("data address out of sync at 0x%x", - address + offset), 0); - for (int i = 0; i < per_line; i++) - data[offset + i] = values[1 + i]; - } catch (ParseException pe) { - for (int i = 0; i < per_line; i++) - data[offset + i] = 0xff; - if (parse_exception == null) - parse_exception = pe; - } - } - } -} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java deleted file mode 100644 index f1397c7b..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromIterable.java +++ /dev/null @@ -1,475 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; - -/* - * AltosRecords with an index field so they can be sorted by tick while preserving - * the original ordering for elements with matching ticks - */ -class AltosOrderedRecord extends AltosEepromRecord implements Comparable { - - public int index; - - public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) - throws ParseException { - super(line); - if (prev_tick_valid) { - tick |= (prev_tick & ~0xffff); - if (tick < prev_tick) { - if (prev_tick - tick > 0x8000) - tick += 0x10000; - } else { - if (tick - prev_tick > 0x8000) - tick -= 0x10000; - } - } - index = in_index; - } - - public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { - super(in_cmd, in_tick, in_a, in_b); - index = in_index; - } - - public String toString() { - return String.format("%d.%d %04x %04x %04x", - cmd, index, tick, a, b); - } - - public int compareTo(AltosOrderedRecord o) { - int tick_diff = tick - o.tick; - if (tick_diff != 0) - return tick_diff; - return index - o.index; - } -} - -public class AltosEepromIterable extends AltosRecordIterable { - - static final int seen_flight = 1; - static final int seen_sensor = 2; - static final int seen_temp_volt = 4; - static final int seen_deploy = 8; - static final int seen_gps_time = 16; - static final int seen_gps_lat = 32; - static final int seen_gps_lon = 64; - - static final int seen_basic = seen_flight|seen_sensor; - - boolean has_accel; - boolean has_gps; - boolean has_ignite; - - AltosEepromRecord flight_record; - AltosEepromRecord gps_date_record; - - TreeSet records; - - LinkedList list; - - class EepromState { - int seen; - int n_pad_samples; - double ground_pres; - int gps_tick; - int boost_tick; - int sensor_tick; - - EepromState() { - seen = 0; - n_pad_samples = 0; - ground_pres = 0.0; - gps_tick = 0; - } - } - - void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { - state.tick = record.tick; - switch (record.cmd) { - case AltosLib.AO_LOG_FLIGHT: - eeprom.seen |= seen_flight; - state.ground_accel = record.a; - state.flight_accel = record.a; - state.flight = record.b; - eeprom.boost_tick = record.tick; - break; - case AltosLib.AO_LOG_SENSOR: - state.accel = record.a; - state.pres = record.b; - if (state.state < AltosLib.ao_flight_boost) { - eeprom.n_pad_samples++; - eeprom.ground_pres += state.pres; - state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); - state.flight_pres = state.ground_pres; - } else { - state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; - } - state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; - if ((eeprom.seen & seen_sensor) == 0) - eeprom.sensor_tick = record.tick - 1; - state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick); - eeprom.seen |= seen_sensor; - eeprom.sensor_tick = record.tick; - has_accel = true; - break; - case AltosLib.AO_LOG_PRESSURE: - state.pres = record.b; - state.flight_pres = state.pres; - if (eeprom.n_pad_samples == 0) { - eeprom.n_pad_samples++; - state.ground_pres = state.pres; - } - eeprom.seen |= seen_sensor; - break; - case AltosLib.AO_LOG_TEMP_VOLT: - state.temp = record.a; - state.batt = record.b; - eeprom.seen |= seen_temp_volt; - break; - case AltosLib.AO_LOG_DEPLOY: - state.drogue = record.a; - state.main = record.b; - eeprom.seen |= seen_deploy; - has_ignite = true; - break; - case AltosLib.AO_LOG_STATE: - state.state = record.a; - break; - case AltosLib.AO_LOG_GPS_TIME: - eeprom.gps_tick = state.tick; - AltosGPS old = state.gps; - state.gps = new AltosGPS(); - - /* GPS date doesn't get repeated through the file */ - if (old != null) { - state.gps.year = old.year; - state.gps.month = old.month; - state.gps.day = old.day; - } - state.gps.hour = (record.a & 0xff); - state.gps.minute = (record.a >> 8); - state.gps.second = (record.b & 0xff); - - int flags = (record.b >> 8); - state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0; - state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0; - state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> - AltosLib.AO_GPS_NUM_SAT_SHIFT; - state.new_gps = true; - has_gps = true; - break; - case AltosLib.AO_LOG_GPS_LAT: - int lat32 = record.a | (record.b << 16); - state.gps.lat = (double) lat32 / 1e7; - break; - case AltosLib.AO_LOG_GPS_LON: - int lon32 = record.a | (record.b << 16); - state.gps.lon = (double) lon32 / 1e7; - break; - case AltosLib.AO_LOG_GPS_ALT: - state.gps.alt = record.a; - break; - case AltosLib.AO_LOG_GPS_SAT: - if (state.tick == eeprom.gps_tick) { - int svid = record.a; - int c_n0 = record.b >> 8; - state.gps.add_sat(svid, c_n0); - } - break; - case AltosLib.AO_LOG_GPS_DATE: - state.gps.year = (record.a & 0xff) + 2000; - state.gps.month = record.a >> 8; - state.gps.day = record.b & 0xff; - break; - - case AltosLib.AO_LOG_CONFIG_VERSION: - break; - case AltosLib.AO_LOG_MAIN_DEPLOY: - break; - case AltosLib.AO_LOG_APOGEE_DELAY: - break; - case AltosLib.AO_LOG_RADIO_CHANNEL: - break; - case AltosLib.AO_LOG_CALLSIGN: - state.callsign = record.data; - break; - case AltosLib.AO_LOG_ACCEL_CAL: - state.accel_plus_g = record.a; - state.accel_minus_g = record.b; - break; - case AltosLib.AO_LOG_RADIO_CAL: - break; - case AltosLib.AO_LOG_MANUFACTURER: - break; - case AltosLib.AO_LOG_PRODUCT: - break; - case AltosLib.AO_LOG_SERIAL_NUMBER: - state.serial = record.a; - break; - case AltosLib.AO_LOG_SOFTWARE_VERSION: - break; - } - state.seen |= eeprom.seen; - } - - LinkedList make_list() { - LinkedList list = new LinkedList(); - Iterator iterator = records.iterator(); - AltosOrderedRecord record = null; - AltosRecord state = new AltosRecord(); - boolean last_reported = false; - EepromState eeprom = new EepromState(); - - state.state = AltosLib.ao_flight_pad; - state.accel_plus_g = 15758; - state.accel_minus_g = 16294; - - /* Pull in static data from the flight and gps_date records */ - if (flight_record != null) - update_state(state, flight_record, eeprom); - if (gps_date_record != null) - update_state(state, gps_date_record, eeprom); - - while (iterator.hasNext()) { - record = iterator.next(); - if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - } - update_state(state, record, eeprom); - } - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - return list; - } - - public Iterator iterator() { - if (list == null) - list = make_list(); - return list.iterator(); - } - - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; } - - public void write_comments(PrintStream out) { - Iterator iterator = records.iterator(); - out.printf("# Comments\n"); - while (iterator.hasNext()) { - AltosOrderedRecord record = iterator.next(); - switch (record.cmd) { - case AltosLib.AO_LOG_CONFIG_VERSION: - out.printf("# Config version: %s\n", record.data); - break; - case AltosLib.AO_LOG_MAIN_DEPLOY: - out.printf("# Main deploy: %s\n", record.a); - break; - case AltosLib.AO_LOG_APOGEE_DELAY: - out.printf("# Apogee delay: %s\n", record.a); - break; - case AltosLib.AO_LOG_RADIO_CHANNEL: - out.printf("# Radio channel: %s\n", record.a); - break; - case AltosLib.AO_LOG_CALLSIGN: - out.printf("# Callsign: %s\n", record.data); - break; - case AltosLib.AO_LOG_ACCEL_CAL: - out.printf ("# Accel cal: %d %d\n", record.a, record.b); - break; - case AltosLib.AO_LOG_RADIO_CAL: - out.printf ("# Radio cal: %d\n", record.a); - break; - case AltosLib.AO_LOG_MAX_FLIGHT_LOG: - out.printf ("# Max flight log: %d\n", record.a); - break; - case AltosLib.AO_LOG_MANUFACTURER: - out.printf ("# Manufacturer: %s\n", record.data); - break; - case AltosLib.AO_LOG_PRODUCT: - out.printf ("# Product: %s\n", record.data); - break; - case AltosLib.AO_LOG_SERIAL_NUMBER: - out.printf ("# Serial number: %d\n", record.a); - break; - case AltosLib.AO_LOG_SOFTWARE_VERSION: - out.printf ("# Software version: %s\n", record.data); - break; - case Altos.AO_LOG_BARO_RESERVED: - out.printf ("# Baro reserved: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_SENS: - out.printf ("# Baro sens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_OFF: - out.printf ("# Baro off: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCS: - out.printf ("# Baro tcs: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCO: - out.printf ("# Baro tco: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TREF: - out.printf ("# Baro tref: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TEMPSENS: - out.printf ("# Baro tempsens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_CRC: - out.printf ("# Baro crc: %d\n", record.a); - break; - } - } - } - - /* - * Given an AO_LOG_GPS_TIME record with correct time, and one - * missing time, rewrite the missing time values with the good - * ones, assuming that the difference between them is 'diff' seconds - */ - void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { - - int diff = (bad.tick - good.tick + 50) / 100; - - int hour = (good.a & 0xff); - int minute = (good.a >> 8); - int second = (good.b & 0xff); - int flags = (good.b >> 8); - int seconds = hour * 3600 + minute * 60 + second; - - /* Make sure this looks like a good GPS value */ - if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) - flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); - flags |= AltosLib.AO_GPS_RUNNING; - flags |= AltosLib.AO_GPS_VALID; - - int new_seconds = seconds + diff; - if (new_seconds < 0) - new_seconds += 24 * 3600; - int new_second = (new_seconds % 60); - int new_minutes = (new_seconds / 60); - int new_minute = (new_minutes % 60); - int new_hours = (new_minutes / 60); - int new_hour = (new_hours % 24); - - bad.a = new_hour + (new_minute << 8); - bad.b = new_second + (flags << 8); - } - - /* - * Read the whole file, dumping records into a RB tree so - * we can enumerate them in time order -- the eeprom data - * are sometimes out of order with GPS data getting timestamps - * matching the first packet out of the GPS unit but not - * written until the final GPS packet has been received. - */ - public AltosEepromIterable (FileInputStream input) { - records = new TreeSet(); - - AltosOrderedRecord last_gps_time = null; - - int index = 0; - int prev_tick = 0; - boolean prev_tick_valid = false; - boolean missing_time = false; - - try { - for (;;) { - String line = AltosRecord.gets(input); - if (line == null) - break; - AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); - if (record == null) - break; - if (record.cmd == AltosLib.AO_LOG_INVALID) - continue; - prev_tick = record.tick; - if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) - prev_tick_valid = true; - if (record.cmd == AltosLib.AO_LOG_FLIGHT) { - flight_record = record; - continue; - } - - /* Two firmware bugs caused the loss of some GPS data. - * The flight date would never be recorded, and often - * the flight time would get overwritten by another - * record. Detect the loss of the GPS date and fix up the - * missing time records - */ - if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { - gps_date_record = record; - continue; - } - - /* go back and fix up any missing time values */ - if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { - last_gps_time = record; - if (missing_time) { - Iterator iterator = records.iterator(); - while (iterator.hasNext()) { - AltosOrderedRecord old = iterator.next(); - if (old.cmd == AltosLib.AO_LOG_GPS_TIME && - old.a == -1 && old.b == -1) - { - update_time(record, old); - } - } - missing_time = false; - } - } - - if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { - if (last_gps_time == null || last_gps_time.tick != record.tick) { - AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME, - record.tick, - -1, -1, index-1); - if (last_gps_time != null) - update_time(last_gps_time, add_gps_time); - else - missing_time = true; - - records.add(add_gps_time); - record.index = index++; - } - } - records.add(record); - - /* Bail after reading the 'landed' record; we're all done */ - if (record.cmd == AltosLib.AO_LOG_STATE && - record.a == AltosLib.ao_flight_landed) - break; - } - } catch (IOException io) { - } catch (ParseException pe) { - } - try { - input.close(); - } catch (IOException ie) { - } - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java deleted file mode 100644 index 7fca4bd9..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromLog.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -/* - * Extract a bit of information from an eeprom-stored flight log. - */ - -public class AltosEepromLog { - public int serial; - public boolean has_flight; - public int flight; - public int start_block; - public int end_block; - - public int year, month, day; - - public boolean selected; - - public AltosEepromLog(AltosConfigData config_data, - AltosLink link, - int in_flight, int in_start_block, - int in_end_block) - throws InterruptedException, TimeoutException { - - int block; - boolean has_date = false; - - flight = in_flight; - if (flight != 0) - has_flight = true; - start_block = in_start_block; - end_block = in_end_block; - serial = config_data.serial; - - /* - * Select all flights for download - */ - selected = true; - - /* - * Look in TeleMetrum log data for date - */ - if (config_data.log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN || - config_data.log_format == AltosLib.AO_LOG_FORMAT_FULL) - { - /* - * Only look in the first two blocks so that this - * process doesn't take a long time - */ - if (in_end_block > in_start_block + 2) - in_end_block = in_start_block + 2; - - for (block = in_start_block; block < in_end_block; block++) { - AltosEepromChunk eechunk = new AltosEepromChunk(link, block, block == in_start_block); - - for (int i = 0; i < eechunk.chunk_size; i += AltosEepromRecord.record_length) { - try { - AltosEepromRecord r = new AltosEepromRecord(eechunk, i); - - if (r.cmd == AltosLib.AO_LOG_FLIGHT) { - flight = r.b; - has_flight = true; - } - if (r.cmd == AltosLib.AO_LOG_GPS_DATE) { - year = 2000 + (r.a & 0xff); - month = (r.a >> 8) & 0xff; - day = (r.b & 0xff); - has_date = true; - } - } catch (ParseException pe) { - } - } - if (has_date && has_flight) - break; - } - } - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java deleted file mode 100644 index 1e845f46..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromRecord.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -public class AltosEepromRecord { - public int cmd; - public int tick; - public int a; - public int b; - public String data; - public boolean tick_valid; - - public static final int record_length = 8; - - public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException { - - cmd = chunk.data(start); - tick_valid = true; - - tick_valid = !chunk.erased(start, record_length); - if (tick_valid) { - if (AltosConvert.checksum(chunk.data, start, record_length) != 0) - throw new ParseException(String.format("invalid checksum at 0x%x", - chunk.address + start), 0); - } else { - cmd = AltosLib.AO_LOG_INVALID; - } - - tick = chunk.data16(start + 2); - a = chunk.data16(start + 4); - b = chunk.data16(start + 6); - - data = null; - } - - public AltosEepromRecord (String line) { - tick_valid = false; - tick = 0; - a = 0; - b = 0; - data = null; - if (line == null) { - cmd = AltosLib.AO_LOG_INVALID; - data = ""; - } else { - try { - String[] tokens = line.split("\\s+"); - - if (tokens[0].length() == 1) { - if (tokens.length != 4) { - cmd = AltosLib.AO_LOG_INVALID; - data = line; - } else { - cmd = tokens[0].codePointAt(0); - tick = Integer.parseInt(tokens[1],16); - tick_valid = true; - a = Integer.parseInt(tokens[2],16); - b = Integer.parseInt(tokens[3],16); - } - } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { - cmd = AltosLib.AO_LOG_CONFIG_VERSION; - data = tokens[2]; - } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { - cmd = AltosLib.AO_LOG_MAIN_DEPLOY; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { - cmd = AltosLib.AO_LOG_APOGEE_DELAY; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { - cmd = AltosLib.AO_LOG_RADIO_CHANNEL; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Callsign:")) { - cmd = AltosLib.AO_LOG_CALLSIGN; - data = tokens[1].replaceAll("\"",""); - } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { - cmd = AltosLib.AO_LOG_ACCEL_CAL; - a = Integer.parseInt(tokens[3]); - b = Integer.parseInt(tokens[5]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { - cmd = AltosLib.AO_LOG_RADIO_CAL; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { - cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG; - a = Integer.parseInt(tokens[3]); - } else if (tokens[0].equals("manufacturer")) { - cmd = AltosLib.AO_LOG_MANUFACTURER; - data = tokens[1]; - } else if (tokens[0].equals("product")) { - cmd = AltosLib.AO_LOG_PRODUCT; - data = tokens[1]; - } else if (tokens[0].equals("serial-number")) { - cmd = AltosLib.AO_LOG_SERIAL_NUMBER; - a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("log-format")) { - cmd = AltosLib.AO_LOG_LOG_FORMAT; - a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("software-version")) { - cmd = AltosLib.AO_LOG_SOFTWARE_VERSION; - data = tokens[1]; - } else { - cmd = AltosLib.AO_LOG_INVALID; - data = line; - } - } catch (NumberFormatException ne) { - cmd = AltosLib.AO_LOG_INVALID; - data = line; - } - } - } - - public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) { - tick_valid = true; - cmd = in_cmd; - tick = in_tick; - a = in_a; - b = in_b; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java deleted file mode 100644 index 1758fa34..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosEepromTeleScience.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -public class AltosEepromTeleScience { - public int type; - public int tick; - public int tm_state; - public int tm_tick; - public int[] data; - public boolean valid; - - public static final int AO_LOG_TELESCIENCE_START = 's'; - public static final int AO_LOG_TELESCIENCE_DATA = 'd'; - - static final int max_data = 12; - public static final int record_length = 32; - - public AltosEepromTeleScience (AltosEepromChunk chunk, int start) throws ParseException { - type = chunk.data(start); - - valid = !chunk.erased(start, record_length); - if (valid) { - if (AltosConvert.checksum(chunk.data, start, record_length) != 0) - throw new ParseException(String.format("invalid checksum at 0x%x", - chunk.address + start), 0); - } else { - type = AltosLib.AO_LOG_INVALID; - } - - tick = chunk.data16(start+2); - tm_tick = chunk.data16(start+4); - tm_state = chunk.data(start+6); - data = new int[max_data]; - for (int i = 0; i < max_data; i++) - data[i] = chunk.data16(start + 8 + i * 2); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java deleted file mode 100644 index d2e4f2f7..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFile.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.io.File; -import java.util.*; - -public class AltosFile extends File { - - public AltosFile(int year, int month, int day, int serial, int flight, String extension) { - super (AltosPreferences.logdir(), - String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s", - year, month, day, serial, flight, extension)); - } - - public AltosFile(int serial, int flight, String extension) { - this(Calendar.getInstance().get(Calendar.YEAR), - Calendar.getInstance().get(Calendar.MONTH) + 1, - Calendar.getInstance().get(Calendar.DAY_OF_MONTH), - serial, - flight, - extension); - } - - public AltosFile(AltosRecord telem) { - this(telem.serial, telem.flight, "telem"); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java deleted file mode 100644 index 3fdea469..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFlightReader.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; -import java.io.*; -import java.util.concurrent.*; - -public class AltosFlightReader { - public String name; - - public int serial; - - public void init() { } - - public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; } - - public void close(boolean interrupted) { } - - public void set_frequency(double frequency) throws InterruptedException, TimeoutException { } - - public void save_frequency() { } - - public void set_telemetry(int telemetry) { } - - public void save_telemetry() { } - - public void update(AltosState state) throws InterruptedException { } - - public boolean supports_telemetry(int telemetry) { return false; } - - public File backing_file() { return null; } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java deleted file mode 100644 index f08ff116..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosFrequency.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; - -public class AltosFrequency { - public double frequency; - public String description; - - public String toString() { - return String.format("%7.3f MHz %-20s", - frequency, description); - } - - public String toShortString() { - return String.format("%7.3f MHz %s", - frequency, description); - } - - public boolean close(double f) { - double diff = Math.abs(frequency - f); - - return diff < 0.010; - } - - public AltosFrequency(double f, String d) { - frequency = f; - description = d; - } -} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java deleted file mode 100644 index f078a469..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPS.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; - -public class AltosGPS { - - public final static int MISSING = AltosRecord.MISSING; - - public int nsat; - public boolean locked; - public boolean connected; - public double lat; /* degrees (+N -S) */ - public double lon; /* degrees (+E -W) */ - public int alt; /* m */ - public int year; - public int month; - public int day; - public int hour; - public int minute; - public int second; - - public double ground_speed; /* m/s */ - public int course; /* degrees */ - public double climb_rate; /* m/s */ - public double hdop; /* unitless */ - public double vdop; /* unitless */ - public int h_error; /* m */ - public int v_error; /* m */ - - public AltosGPSSat[] cc_gps_sat; /* tracking data */ - - public void ParseGPSDate(String date) throws ParseException { - String[] ymd = date.split("-"); - if (ymd.length != 3) - throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); - year = AltosParse.parse_int(ymd[0]); - month = AltosParse.parse_int(ymd[1]); - day = AltosParse.parse_int(ymd[2]); - } - - public void ParseGPSTime(String time) throws ParseException { - String[] hms = time.split(":"); - if (hms.length != 3) - throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); - hour = AltosParse.parse_int(hms[0]); - minute = AltosParse.parse_int(hms[1]); - second = AltosParse.parse_int(hms[2]); - } - - public void ClearGPSTime() { - year = month = day = 0; - hour = minute = second = 0; - } - - public AltosGPS(AltosTelemetryMap map) throws ParseException { - String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE, - AltosTelemetry.AO_TELEM_GPS_STATE_ERROR); - - nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0); - if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) { - connected = true; - locked = true; - lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7); - lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7); - alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING); - year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING); - if (year != MISSING) - year += 2000; - month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING); - day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING); - - hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0); - minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0); - second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0); - - ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED, - AltosRecord.MISSING, 1/100.0); - course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE, - AltosRecord.MISSING); - hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0); - vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0); - h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING); - v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING); - } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) { - connected = true; - locked = false; - } else { - connected = false; - locked = false; - } - } - - public AltosGPS(String[] words, int i, int version) throws ParseException { - AltosParse.word(words[i++], "GPS"); - nsat = AltosParse.parse_int(words[i++]); - AltosParse.word(words[i++], "sat"); - - connected = false; - locked = false; - lat = lon = 0; - alt = 0; - ClearGPSTime(); - if ((words[i]).equals("unlocked")) { - connected = true; - i++; - } else if ((words[i]).equals("not-connected")) { - i++; - } else if (words.length >= 40) { - locked = true; - connected = true; - - if (version > 1) - ParseGPSDate(words[i++]); - else - year = month = day = 0; - ParseGPSTime(words[i++]); - lat = AltosParse.parse_coord(words[i++]); - lon = AltosParse.parse_coord(words[i++]); - alt = AltosParse.parse_int(words[i++]); - if (version > 1 || (i < words.length && !words[i].equals("SAT"))) { - ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)")); - course = AltosParse.parse_int(words[i++]); - climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)")); - hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)")); - h_error = AltosParse.parse_int(words[i++]); - v_error = AltosParse.parse_int(words[i++]); - } - } else { - i++; - } - if (i < words.length) { - AltosParse.word(words[i++], "SAT"); - int tracking_channels = 0; - if (words[i].equals("not-connected")) - tracking_channels = 0; - else - tracking_channels = AltosParse.parse_int(words[i]); - i++; - cc_gps_sat = new AltosGPSSat[tracking_channels]; - for (int chan = 0; chan < tracking_channels; chan++) { - cc_gps_sat[chan] = new AltosGPSSat(); - cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]); - /* Older versions included SiRF status bits */ - if (version < 2) - i++; - cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]); - } - } else - cc_gps_sat = new AltosGPSSat[0]; - } - - public void set_latitude(int in_lat) { - lat = in_lat / 10.0e7; - } - - public void set_longitude(int in_lon) { - lon = in_lon / 10.0e7; - } - - public void set_time(int hour, int minute, int second) { - hour = hour; - minute = minute; - second = second; - } - - public void set_date(int year, int month, int day) { - year = year; - month = month; - day = day; - } - - public void set_flags(int flags) { - flags = flags; - } - - public void set_altitude(int altitude) { - altitude = altitude; - } - - public void add_sat(int svid, int c_n0) { - if (cc_gps_sat == null) { - cc_gps_sat = new AltosGPSSat[1]; - } else { - AltosGPSSat[] new_gps_sat = new AltosGPSSat[cc_gps_sat.length + 1]; - for (int i = 0; i < cc_gps_sat.length; i++) - new_gps_sat[i] = cc_gps_sat[i]; - cc_gps_sat = new_gps_sat; - } - AltosGPSSat sat = new AltosGPSSat(); - sat.svid = svid; - sat.c_n0 = c_n0; - cc_gps_sat[cc_gps_sat.length - 1] = sat; - } - - public AltosGPS() { - ClearGPSTime(); - cc_gps_sat = null; - } - - public AltosGPS(AltosGPS old) { - nsat = old.nsat; - locked = old.locked; - connected = old.connected; - lat = old.lat; /* degrees (+N -S) */ - lon = old.lon; /* degrees (+E -W) */ - alt = old.alt; /* m */ - year = old.year; - month = old.month; - day = old.day; - hour = old.hour; - minute = old.minute; - second = old.second; - - ground_speed = old.ground_speed; /* m/s */ - course = old.course; /* degrees */ - climb_rate = old.climb_rate; /* m/s */ - hdop = old.hdop; /* unitless? */ - h_error = old.h_error; /* m */ - v_error = old.v_error; /* m */ - - if (old.cc_gps_sat != null) { - cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length]; - for (int i = 0; i < old.cc_gps_sat.length; i++) { - cc_gps_sat[i] = new AltosGPSSat(); - cc_gps_sat[i].svid = old.cc_gps_sat[i].svid; - cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0; - } - } - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java deleted file mode 100644 index faa1ec8d..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGPSSat.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.AltosLib; - -public class AltosGPSSat { - public int svid; - public int c_n0; - - public AltosGPSSat(int s, int c) { - svid = s; - c_n0= c; - } - - public AltosGPSSat() { - } -} - diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java deleted file mode 100644 index 76b71859..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosGreatCircle.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.Math; - -public class AltosGreatCircle { - public double distance; - public double bearing; - - double sqr(double a) { return a * a; } - - static final double rad = Math.PI / 180; - static final double earth_radius = 6371.2 * 1000; /* in meters */ - - public static final int BEARING_LONG = 0; - public static final int BEARING_SHORT = 1; - public static final int BEARING_VOICE = 2; - - public String bearing_words(int length) { - String [][] bearing_string = { - { - "North", "North North East", "North East", "East North East", - "East", "East South East", "South East", "South South East", - "South", "South South West", "South West", "West South West", - "West", "West North West", "North West", "North North West" - }, { - "N", "NNE", "NE", "ENE", - "E", "ESE", "SE", "SSE", - "S", "SSW", "SW", "WSW", - "W", "WNW", "NW", "NNW" - }, { - "north", "nor nor east", "north east", "east nor east", - "east", "east sow east", "south east", "sow sow east", - "south", "sow sow west", "south west", "west sow west", - "west", "west nor west", "north west", "nor nor west " - } - }; - return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16]; - } - - public AltosGreatCircle (double start_lat, double start_lon, - double end_lat, double end_lon) - { - double lat1 = rad * start_lat; - double lon1 = rad * -start_lon; - double lat2 = rad * end_lat; - double lon2 = rad * -end_lon; - - double d_lon = lon2 - lon1; - - /* From http://en.wikipedia.org/wiki/Great-circle_distance */ - double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) + - sqr(Math.cos(lat1) * Math.sin(lat2) - - Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon))); - double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon); - double d = Math.atan2(vdn,vdd); - double course; - - if (Math.cos(lat1) < 1e-20) { - if (lat1 > 0) - course = Math.PI; - else - course = -Math.PI; - } else { - if (d < 1e-10) - course = 0; - else - course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) / - (Math.sin(d)*Math.cos(lat1))); - if (Math.sin(lon2-lon1) > 0) - course = 2 * Math.PI-course; - } - distance = d * earth_radius; - bearing = course * 180/Math.PI; - } - - public AltosGreatCircle(AltosGPS start, AltosGPS end) { - this(start.lat, start.lon, end.lat, end.lon); - } - - public AltosGreatCircle() { - distance = 0; - bearing = 0; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java deleted file mode 100644 index 2921d040..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLib.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * 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.AltosLib; - -import java.awt.*; -import java.util.*; -import java.text.*; -import java.nio.charset.Charset; - -public class AltosLib { - /* EEProm command letters */ - public static final int AO_LOG_FLIGHT = 'F'; - public static final int AO_LOG_SENSOR = 'A'; - public static final int AO_LOG_TEMP_VOLT = 'T'; - public static final int AO_LOG_DEPLOY = 'D'; - public static final int AO_LOG_STATE = 'S'; - public static final int AO_LOG_GPS_TIME = 'G'; - public static final int AO_LOG_GPS_LAT = 'N'; - public static final int AO_LOG_GPS_LON = 'W'; - public static final int AO_LOG_GPS_ALT = 'H'; - public static final int AO_LOG_GPS_SAT = 'V'; - public static final int AO_LOG_GPS_DATE = 'Y'; - public static final int AO_LOG_PRESSURE = 'P'; - - /* Added for header fields in eeprom files */ - public static final int AO_LOG_CONFIG_VERSION = 1000; - public static final int AO_LOG_MAIN_DEPLOY = 1001; - public static final int AO_LOG_APOGEE_DELAY = 1002; - public static final int AO_LOG_RADIO_CHANNEL = 1003; - public static final int AO_LOG_CALLSIGN = 1004; - public static final int AO_LOG_ACCEL_CAL = 1005; - public static final int AO_LOG_RADIO_CAL = 1006; - public static final int AO_LOG_MAX_FLIGHT_LOG = 1007; - public static final int AO_LOG_MANUFACTURER = 2000; - public static final int AO_LOG_PRODUCT = 2001; - public static final int AO_LOG_SERIAL_NUMBER = 2002; - public static final int AO_LOG_LOG_FORMAT = 2003; - public static final int AO_LOG_SOFTWARE_VERSION = 9999; - - /* Added to flag invalid records */ - public static final int AO_LOG_INVALID = -1; - - /* Flight state numbers and names */ - public static final int ao_flight_startup = 0; - public static final int ao_flight_idle = 1; - public static final int ao_flight_pad = 2; - public static final int ao_flight_boost = 3; - public static final int ao_flight_fast = 4; - public static final int ao_flight_coast = 5; - public static final int ao_flight_drogue = 6; - public static final int ao_flight_main = 7; - public static final int ao_flight_landed = 8; - public static final int ao_flight_invalid = 9; - - /* Telemetry modes */ - public static final int ao_telemetry_off = 0; - public static final int ao_telemetry_min = 1; - public static final int ao_telemetry_standard = 1; - public static final int ao_telemetry_0_9 = 2; - public static final int ao_telemetry_0_8 = 3; - public static final int ao_telemetry_max = 3; - - public static final String[] ao_telemetry_name = { - "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" - }; - - public static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; - - public static final int ao_telemetry_standard_len = 32; - public static final int ao_telemetry_0_9_len = 95; - public static final int ao_telemetry_0_8_len = 94; - - public static final int[] ao_telemetry_len = { - 0, 32, 95, 94 - }; - - public static HashMap string_to_state = new HashMap(); - - public static boolean map_initialized = false; - - public static void initialize_map() - { - string_to_state.put("startup", ao_flight_startup); - string_to_state.put("idle", ao_flight_idle); - string_to_state.put("pad", ao_flight_pad); - string_to_state.put("boost", ao_flight_boost); - string_to_state.put("fast", ao_flight_fast); - string_to_state.put("coast", ao_flight_coast); - string_to_state.put("drogue", ao_flight_drogue); - string_to_state.put("apogee", ao_flight_coast); - string_to_state.put("main", ao_flight_main); - string_to_state.put("landed", ao_flight_landed); - string_to_state.put("invalid", ao_flight_invalid); - map_initialized = true; - } - - public static int telemetry_len(int telemetry) { - if (telemetry <= ao_telemetry_max) - return ao_telemetry_len[telemetry]; - throw new IllegalArgumentException(String.format("Invalid telemetry %d", - telemetry)); - } - - public static String telemetry_name(int telemetry) { - if (telemetry <= ao_telemetry_max) - return ao_telemetry_name[telemetry]; - throw new IllegalArgumentException(String.format("Invalid telemetry %d", - telemetry)); - } - - public static String[] state_to_string = { - "startup", - "idle", - "pad", - "boost", - "fast", - "coast", - "drogue", - "main", - "landed", - "invalid", - }; - - public static String[] state_to_string_capital = { - "Startup", - "Idle", - "Pad", - "Boost", - "Fast", - "Coast", - "Drogue", - "Main", - "Landed", - "Invalid", - }; - - public static int state(String state) { - if (!map_initialized) - initialize_map(); - if (string_to_state.containsKey(state)) - return string_to_state.get(state); - return ao_flight_invalid; - } - - public static String state_name(int state) { - if (state < 0 || state_to_string.length <= state) - return "invalid"; - return state_to_string[state]; - } - - public static final int AO_GPS_VALID = (1 << 4); - public static final int AO_GPS_RUNNING = (1 << 5); - public static final int AO_GPS_DATE_VALID = (1 << 6); - public static final int AO_GPS_NUM_SAT_SHIFT = 0; - public static final int AO_GPS_NUM_SAT_MASK = 0xf; - - public static final int AO_LOG_FORMAT_UNKNOWN = 0; - public static final int AO_LOG_FORMAT_FULL = 1; - public static final int AO_LOG_FORMAT_TINY = 2; - public static final int AO_LOG_FORMAT_TELEMETRY = 3; - public static final int AO_LOG_FORMAT_TELESCIENCE = 4; - public static final int AO_LOG_FORMAT_NONE = 127; - - public static boolean isspace(int c) { - switch (c) { - case ' ': - case '\t': - return true; - } - return false; - } - - public static boolean ishex(int c) { - if ('0' <= c && c <= '9') - return true; - if ('a' <= c && c <= 'f') - return true; - if ('A' <= c && c <= 'F') - return true; - return false; - } - - public static boolean ishex(String s) { - for (int i = 0; i < s.length(); i++) - if (!ishex(s.charAt(i))) - return false; - return true; - } - - public static int fromhex(int c) { - 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; - return -1; - } - - public static int fromhex(String s) throws NumberFormatException { - int c, v = 0; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - if (!ishex(c)) { - if (i == 0) - throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); - return v; - } - v = v * 16 + fromhex(c); - } - return v; - } - - public static boolean isdec(int c) { - if ('0' <= c && c <= '9') - return true; - return false; - } - - public static boolean isdec(String s) { - for (int i = 0; i < s.length(); i++) - if (!isdec(s.charAt(i))) - return false; - return true; - } - - public static int fromdec(int c) { - if ('0' <= c && c <= '9') - return c - '0'; - return -1; - } - - public static int int8(int[] bytes, int i) { - return (int) (byte) bytes[i]; - } - - public static int uint8(int[] bytes, int i) { - return bytes[i]; - } - - public static int int16(int[] bytes, int i) { - return (int) (short) (bytes[i] + (bytes[i+1] << 8)); - } - - public static int uint16(int[] bytes, int i) { - return bytes[i] + (bytes[i+1] << 8); - } - - public static int uint32(int[] bytes, int i) { - return bytes[i] + - (bytes[i+1] << 8) + - (bytes[i+2] << 16) + - (bytes[i+3] << 24); - } - - public static final Charset unicode_set = Charset.forName("UTF-8"); - - public static String string(int[] bytes, int s, int l) { - if (s + l > bytes.length) { - if (s > bytes.length) { - s = bytes.length; - l = 0; - } else { - l = bytes.length - s; - } - } - - int i; - for (i = l - 1; i >= 0; i--) - if (bytes[s+i] != 0) - break; - - l = i + 1; - byte[] b = new byte[l]; - - for (i = 0; i < l; i++) - b[i] = (byte) bytes[s+i]; - String n = new String(b, unicode_set); - return n; - } - - public static int hexbyte(String s, int i) { - int c0, c1; - - if (s.length() < i + 2) - throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); - c0 = s.charAt(i); - if (!ishex(c0)) - throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); - c1 = s.charAt(i+1); - if (!ishex(c1)) - throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); - return fromhex(c0) * 16 + fromhex(c1); - } - - public static int[] hexbytes(String s) { - int n; - int[] r; - int i; - - if ((s.length() & 1) != 0) - throw new NumberFormatException(String.format("invalid line \"%s\"", s)); - n = s.length() / 2; - r = new int[n]; - for (i = 0; i < n; i++) - r[i] = hexbyte(s, i * 2); - return r; - } - - public static int fromdec(String s) throws NumberFormatException { - int c, v = 0; - int sign = 1; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - if (i == 0 && c == '-') { - sign = -1; - } else if (!isdec(c)) { - if (i == 0) - throw new NumberFormatException(String.format("invalid number \"%s\"", s)); - return v; - } else - v = v * 10 + fromdec(c); - } - return v * sign; - } - - public static String replace_extension(String input, String extension) { - int dot = input.lastIndexOf("."); - if (dot > 0) - input = input.substring(0,dot); - return input.concat(extension); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java deleted file mode 100644 index 5627795a..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLine.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.AltosLib; - -public class AltosLine { - public String line; - - public AltosLine() { - line = null; - } - - public AltosLine(String s) { - line = s; - } -} \ No newline at end of file diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java deleted file mode 100644 index 9b80e916..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLink.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.io.*; -import java.util.concurrent.*; -import java.util.*; -import java.text.*; - -public abstract class AltosLink { - public abstract void print(String data); - public abstract void close(); - - public static boolean debug = false; - public static void set_debug(boolean in_debug) { debug = in_debug; } - LinkedList pending_output = new LinkedList(); - - public LinkedList> monitors = new LinkedList> ();; - public LinkedBlockingQueue reply_queue = new LinkedBlockingQueue(); - - public void add_monitor(LinkedBlockingQueue q) { - set_monitor(true); - monitors.add(q); - } - - public void remove_monitor(LinkedBlockingQueue q) { - monitors.remove(q); - if (monitors.isEmpty()) - set_monitor(false); - } - - public void printf(String format, Object ... arguments) { - String line = String.format(format, arguments); - if (debug) - pending_output.add(line); - print(line); - } - - public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException { - flush_output(); - AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); - if (line != null) - return line.line; - return null; - } - - public String get_reply(int timeout) throws InterruptedException { - try { - return get_reply_no_dialog(timeout); - } catch (TimeoutException te) { - return null; - } - } - - public String get_reply() throws InterruptedException { - return get_reply(5000); - } - - public void add_telem(AltosLine line) throws InterruptedException { - for (int e = 0; e < monitors.size(); e++) { - LinkedBlockingQueue q = monitors.get(e); - q.put(line); - } - } - - public void add_reply(AltosLine line) throws InterruptedException { - reply_queue.put (line); - } - - public void add_string(String line) throws InterruptedException { - if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { - add_telem(new AltosLine(line)); - } else { - add_reply(new AltosLine(line)); - } - } - - public void add_bytes(byte[] bytes, int len) throws InterruptedException { - String line; - try { - line = new String(bytes, 0, len, "UTF-8"); - } catch (UnsupportedEncodingException ue) { - line = ""; - for (int i = 0; i < len; i++) - line = line + bytes[i]; - } - if (debug) - System.out.printf("\t\t\t\t\t%s\n", line); - add_string(line); - } - - public void flush_output() { - for (String s : pending_output) - System.out.print(s); - pending_output.clear(); - } - - public void flush_input(int timeout) throws InterruptedException { - flush_output(); - boolean got_some; - - do { - Thread.sleep(timeout); - got_some = !reply_queue.isEmpty(); - reply_queue.clear(); - } while (got_some); - } - - - public void flush_input() throws InterruptedException { - flush_input(100); - } - - - /* - * Various command-level operations on - * the link - */ - public boolean monitor_mode = false; - public int telemetry = AltosLib.ao_telemetry_standard; - public double frequency; - AltosConfigData config_data; - - private int telemetry_len() { - return AltosLib.telemetry_len(telemetry); - } - - public void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - if (monitor_mode) - printf("m 0\nm %x\n", telemetry_len()); - flush_output(); - } - - public void set_monitor(boolean monitor) { - monitor_mode = monitor; - if (monitor) - printf("m %x\n", telemetry_len()); - else - printf("m 0\n"); - flush_output(); - } - - private void set_channel(int channel) { - if (monitor_mode) - printf("m 0\nc r %d\nm %x\n", - channel, telemetry_len()); - else - printf("c r %d\n", channel); - flush_output(); - } - - private void set_radio_setting(int setting) { - if (monitor_mode) - printf("m 0\nc R %d\nm %x\n", - setting, telemetry_len()); - else - printf("c R %d\n", setting); - flush_output(); - } - - public void set_radio_frequency(double frequency, - boolean has_setting, - int cal) { - if (debug) - System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); - if (has_setting) - set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); - else - set_channel(AltosConvert.radio_frequency_to_channel(frequency)); - } - - public AltosConfigData config_data() throws InterruptedException, TimeoutException { - if (config_data == null) - config_data = new AltosConfigData(this); - return config_data; - } - - public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - config_data(); - set_radio_frequency(frequency, - config_data.radio_setting != 0, - config_data.radio_calibration); - } - - public void set_callsign(String callsign) { - printf ("c c %s\n", callsign); - flush_output(); - } - - public boolean remote; - public int serial; - public String name; - - public void start_remote() throws TimeoutException, InterruptedException { - if (debug) - System.out.printf("start remote %7.3f\n", frequency); - if (frequency == 0.0) - frequency = AltosPreferences.frequency(serial); - set_radio_frequency(frequency); - set_callsign(AltosPreferences.callsign()); - printf("p\nE 0\n"); - flush_input(); - remote = true; - } - - public void stop_remote() throws InterruptedException { - if (debug) - System.out.printf("stop remote\n"); - try { - flush_input(); - } finally { - printf ("~\n"); - flush_output(); - } - remote = false; - } - - public AltosLink() { - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java deleted file mode 100644 index 08c45ca8..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosLog.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.lang.*; -import java.util.*; -import java.text.ParseException; -import java.util.concurrent.LinkedBlockingQueue; - -/* - * This creates a thread to capture telemetry data and write it to - * a log file - */ -class AltosLog implements Runnable { - - LinkedBlockingQueue input_queue; - LinkedBlockingQueue pending_queue; - int serial; - int flight; - FileWriter log_file; - Thread log_thread; - AltosFile file; - - private void close_log_file() { - if (log_file != null) { - try { - log_file.close(); - } catch (IOException io) { - } - log_file = null; - } - } - - void close() { - close_log_file(); - if (log_thread != null) { - log_thread.interrupt(); - log_thread = null; - } - } - - File file() { - return file; - } - - boolean open (AltosRecord telem) throws IOException { - AltosFile a = new AltosFile(telem); - - System.out.printf("open %s\n", a.toString()); - log_file = new FileWriter(a, true); - if (log_file != null) { - while (!pending_queue.isEmpty()) { - try { - String s = pending_queue.take(); - log_file.write(s); - log_file.write('\n'); - } catch (InterruptedException ie) { - } - } - log_file.flush(); - file = a; - } - return log_file != null; - } - - public void run () { - try { - AltosRecord previous = null; - for (;;) { - AltosLine line = input_queue.take(); - if (line.line == null) - continue; - try { - AltosRecord telem = AltosTelemetry.parse(line.line, previous); - if (telem.serial != 0 && telem.flight != 0 && - (telem.serial != serial || telem.flight != flight || log_file == null)) - { - close_log_file(); - serial = telem.serial; - flight = telem.flight; - open(telem); - } - previous = telem; - } catch (ParseException pe) { - } catch (AltosCRCException ce) { - } - if (log_file != null) { - log_file.write(line.line); - log_file.write('\n'); - log_file.flush(); - } else - pending_queue.put(line.line); - } - } catch (InterruptedException ie) { - } catch (IOException ie) { - } - close(); - } - - public AltosLog (AltosLink link) { - pending_queue = new LinkedBlockingQueue (); - input_queue = new LinkedBlockingQueue (); - link.add_monitor(input_queue); - serial = -1; - flight = -1; - log_file = null; - log_thread = new Thread(this); - log_thread.start(); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java deleted file mode 100644 index 7d832f1a..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosParse.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.AltosLib; - -import java.text.*; -import java.lang.*; - -public class AltosParse { - public static boolean isdigit(char c) { - return '0' <= c && c <= '9'; - } - - public static int parse_int(String v) throws ParseException { - try { - return AltosLib.fromdec(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing int " + v, 0); - } - } - - public static int parse_hex(String v) throws ParseException { - try { - return AltosLib.fromhex(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing hex " + v, 0); - } - } - - public static double parse_double(String v) throws ParseException { - try { - return Double.parseDouble(v); - } catch (NumberFormatException e) { - throw new ParseException("error parsing double " + v, 0); - } - } - - public static double parse_coord(String coord) throws ParseException { - String[] dsf = coord.split("\\D+"); - - if (dsf.length != 3) { - throw new ParseException("error parsing coord " + coord, 0); - } - int deg = parse_int(dsf[0]); - int min = parse_int(dsf[1]); - int frac = parse_int(dsf[2]); - - double r = deg + (min + frac / 10000.0) / 60.0; - if (coord.endsWith("S") || coord.endsWith("W")) - r = -r; - return r; - } - - public static String strip_suffix(String v, String suffix) { - if (v.endsWith(suffix)) - return v.substring(0, v.length() - suffix.length()); - return v; - } - - public static void word(String v, String m) throws ParseException { - if (!v.equals(m)) { - throw new ParseException("error matching '" + v + "' '" + m + "'", 0); - } - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java deleted file mode 100644 index 43c7088d..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosPreferences.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.awt.Component; -import javax.swing.*; -import javax.swing.filechooser.FileSystemView; - -public class AltosPreferences { - public static Preferences preferences; - - /* logdir preference name */ - public final static String logdirPreference = "LOGDIR"; - - /* channel preference name */ - public final static String channelPreferenceFormat = "CHANNEL-%d"; - - /* frequency preference name */ - public final static String frequencyPreferenceFormat = "FREQUENCY-%d"; - - /* telemetry format preference name */ - public final static String telemetryPreferenceFormat = "TELEMETRY-%d"; - - /* voice preference name */ - public final static String voicePreference = "VOICE"; - - /* callsign preference name */ - public final static String callsignPreference = "CALLSIGN"; - - /* firmware directory preference name */ - public final static String firmwaredirPreference = "FIRMWARE"; - - /* serial debug preference name */ - public final static String serialDebugPreference = "SERIAL-DEBUG"; - - /* scanning telemetry preferences name */ - public final static String scanningTelemetryPreference = "SCANNING-TELEMETRY"; - - /* Launcher serial preference name */ - public final static String launcherSerialPreference = "LAUNCHER-SERIAL"; - - /* Launcher channel preference name */ - public final static String launcherChannelPreference = "LAUNCHER-CHANNEL"; - - /* Default logdir is ~/TeleMetrum */ - public final static String logdirName = "TeleMetrum"; - - /* Log directory */ - public static File logdir; - - /* Map directory -- hangs of logdir */ - public static File mapdir; - - /* Frequency (map serial to frequency) */ - public static Hashtable frequencies; - - /* Telemetry (map serial to telemetry format) */ - public static Hashtable telemetries; - - /* Voice preference */ - public static boolean voice; - - /* Callsign preference */ - public static String callsign; - - /* Firmware directory */ - public static File firmwaredir; - - /* Scanning telemetry */ - public static int scanning_telemetry; - - /* List of frequencies */ - public final static String common_frequencies_node_name = "COMMON-FREQUENCIES"; - public static AltosFrequency[] common_frequencies; - - public final static String frequency_count = "COUNT"; - public final static String frequency_format = "FREQUENCY-%d"; - public final static String description_format = "DESCRIPTION-%d"; - - public static AltosFrequency[] load_common_frequencies() { - AltosFrequency[] frequencies = null; - boolean existing = false; - try { - existing = preferences.nodeExists(common_frequencies_node_name); - } catch (BackingStoreException be) { - existing = false; - } - if (existing) { - Preferences node = preferences.node(common_frequencies_node_name); - int count = node.getInt(frequency_count, 0); - - frequencies = new AltosFrequency[count]; - for (int i = 0; i < count; i++) { - double frequency; - String description; - - frequency = node.getDouble(String.format(frequency_format, i), 0.0); - description = node.get(String.format(description_format, i), null); - frequencies[i] = new AltosFrequency(frequency, description); - } - } else { - frequencies = new AltosFrequency[10]; - for (int i = 0; i < 10; i++) { - frequencies[i] = new AltosFrequency(434.550 + i * .1, - String.format("Channel %d", i)); - } - } - return frequencies; - } - - public static void save_common_frequencies(AltosFrequency[] frequencies) { - Preferences node = preferences.node(common_frequencies_node_name); - - node.putInt(frequency_count, frequencies.length); - for (int i = 0; i < frequencies.length; i++) { - node.putDouble(String.format(frequency_format, i), frequencies[i].frequency); - node.put(String.format(description_format, i), frequencies[i].description); - } - } - public static int launcher_serial; - - public static int launcher_channel; - - public static void init() { - preferences = Preferences.userRoot().node("/org/altusmetrum/altosui"); - - /* Initialize logdir from preferences */ - String logdir_string = preferences.get(logdirPreference, null); - if (logdir_string != null) - logdir = new File(logdir_string); - else { - /* Use the file system view default directory */ - logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName); - if (!logdir.exists()) - logdir.mkdirs(); - } - mapdir = new File(logdir, "maps"); - if (!mapdir.exists()) - mapdir.mkdirs(); - - frequencies = new Hashtable(); - - telemetries = new Hashtable(); - - voice = preferences.getBoolean(voicePreference, true); - - callsign = preferences.get(callsignPreference,"N0CALL"); - - scanning_telemetry = preferences.getInt(scanningTelemetryPreference,(1 << AltosLib.ao_telemetry_standard)); - - launcher_serial = preferences.getInt(launcherSerialPreference, 0); - - launcher_channel = preferences.getInt(launcherChannelPreference, 0); - - String firmwaredir_string = preferences.get(firmwaredirPreference, null); - if (firmwaredir_string != null) - firmwaredir = new File(firmwaredir_string); - else - firmwaredir = null; - - common_frequencies = load_common_frequencies(); - - } - - static { init(); } - - public static void flush_preferences() { - try { - preferences.flush(); - } catch (BackingStoreException ee) { -/* - if (component != null) - JOptionPane.showMessageDialog(component, - preferences.absolutePath(), - "Cannot save prefernces", - JOptionPane.ERROR_MESSAGE); - else -*/ - System.err.printf("Cannot save preferences\n"); - } - } - - public static void set_logdir(File new_logdir) { - logdir = new_logdir; - mapdir = new File(logdir, "maps"); - if (!mapdir.exists()) - mapdir.mkdirs(); - synchronized (preferences) { - preferences.put(logdirPreference, logdir.getPath()); - flush_preferences(); - } - } - - public static File logdir() { - return logdir; - } - - public static File mapdir() { - return mapdir; - } - - public static void set_frequency(int serial, double new_frequency) { - frequencies.put(serial, new_frequency); - synchronized (preferences) { - preferences.putDouble(String.format(frequencyPreferenceFormat, serial), new_frequency); - flush_preferences(); - } - } - - public static double frequency(int serial) { - if (frequencies.containsKey(serial)) - return frequencies.get(serial); - double frequency = preferences.getDouble(String.format(frequencyPreferenceFormat, serial), 0); - if (frequency == 0.0) { - int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0); - frequency = AltosConvert.radio_channel_to_frequency(channel); - } - frequencies.put(serial, frequency); - return frequency; - } - - public static void set_telemetry(int serial, int new_telemetry) { - telemetries.put(serial, new_telemetry); - synchronized (preferences) { - preferences.putInt(String.format(telemetryPreferenceFormat, serial), new_telemetry); - flush_preferences(); - } - } - - public static int telemetry(int serial) { - if (telemetries.containsKey(serial)) - return telemetries.get(serial); - int telemetry = preferences.getInt(String.format(telemetryPreferenceFormat, serial), - AltosLib.ao_telemetry_standard); - telemetries.put(serial, telemetry); - return telemetry; - } - - public static void set_scanning_telemetry(int new_scanning_telemetry) { - scanning_telemetry = new_scanning_telemetry; - synchronized (preferences) { - preferences.putInt(scanningTelemetryPreference, scanning_telemetry); - flush_preferences(); - } - } - - public static int scanning_telemetry() { - return scanning_telemetry; - } - - public static void set_voice(boolean new_voice) { - voice = new_voice; - synchronized (preferences) { - preferences.putBoolean(voicePreference, voice); - flush_preferences(); - } - } - - public static boolean voice() { - return voice; - } - - public static void set_callsign(String new_callsign) { - callsign = new_callsign; - synchronized(preferences) { - preferences.put(callsignPreference, callsign); - flush_preferences(); - } - } - - public static String callsign() { - return callsign; - } - - public static void set_firmwaredir(File new_firmwaredir) { - firmwaredir = new_firmwaredir; - synchronized (preferences) { - preferences.put(firmwaredirPreference, firmwaredir.getPath()); - flush_preferences(); - } - } - - public static File firmwaredir() { - return firmwaredir; - } - - public static void set_launcher_serial(int new_launcher_serial) { - launcher_serial = new_launcher_serial; - System.out.printf("set launcher serial to %d\n", new_launcher_serial); - synchronized (preferences) { - preferences.putInt(launcherSerialPreference, launcher_serial); - flush_preferences(); - } - } - - public static int launcher_serial() { - return launcher_serial; - } - - public static void set_launcher_channel(int new_launcher_channel) { - launcher_channel = new_launcher_channel; - System.out.printf("set launcher channel to %d\n", new_launcher_channel); - synchronized (preferences) { - preferences.putInt(launcherChannelPreference, launcher_channel); - flush_preferences(); - } - } - - public static int launcher_channel() { - return launcher_channel; - } - - public static Preferences bt_devices() { - return preferences.node("bt_devices"); - } - - public static AltosFrequency[] common_frequencies() { - return common_frequencies; - } - - public static void set_common_frequencies(AltosFrequency[] frequencies) { - common_frequencies = frequencies; - synchronized(preferences) { - save_common_frequencies(frequencies); - flush_preferences(); - } - } - - public static void add_common_frequency(AltosFrequency frequency) { - AltosFrequency[] new_frequencies = new AltosFrequency[common_frequencies.length + 1]; - int i; - - for (i = 0; i < common_frequencies.length; i++) { - if (frequency.frequency == common_frequencies[i].frequency) - return; - if (frequency.frequency < common_frequencies[i].frequency) - break; - new_frequencies[i] = common_frequencies[i]; - } - new_frequencies[i] = frequency; - for (; i < common_frequencies.length; i++) - new_frequencies[i+1] = common_frequencies[i]; - set_common_frequencies(new_frequencies); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java deleted file mode 100644 index e4915af0..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecord.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; -import java.io.*; - -public class AltosRecord implements Comparable { - public final static int MISSING = 0x7fffffff; - - public static final int seen_flight = 1; - public static final int seen_sensor = 2; - public static final int seen_temp_volt = 4; - public static final int seen_deploy = 8; - public static final int seen_gps_time = 16; - public static final int seen_gps_lat = 32; - public static final int seen_gps_lon = 64; - public static final int seen_companion = 128; - public int seen; - - public int version; - public String callsign; - public int serial; - public int flight; - public int rssi; - public int status; - public int state; - public int tick; - - public int accel; - public int pres; - public int temp; - public int batt; - public int drogue; - public int main; - - public int ground_accel; - public int ground_pres; - public int accel_plus_g; - public int accel_minus_g; - - public double acceleration; - public double speed; - public double height; - - public int flight_accel; - public int flight_vel; - public int flight_pres; - - public AltosGPS gps; - public boolean new_gps; - - public AltosIMU imu; - public AltosMag mag; - - public double time; /* seconds since boost */ - - public int device_type; - public int config_major; - public int config_minor; - public int apogee_delay; - public int main_deploy; - public int flight_log_max; - public String firmware_version; - - public AltosRecordCompanion companion; - ->>>>>>> 5a249bc... altosui: Complete split out of separate java library - /* - * Values for our MP3H6115A pressure sensor - * - * From the data sheet: - * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * - * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa - * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa - */ - - public static final double counts_per_kPa = 27 * 2047 / 3300; - public static final double counts_at_101_3kPa = 1674.0; - - public static double - barometer_to_pressure(double count) - { - return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; - } - - public double raw_pressure() { - if (pres == MISSING) - return MISSING; - return barometer_to_pressure(pres); - } - - public double filtered_pressure() { - if (flight_pres == MISSING) - return MISSING; - return barometer_to_pressure(flight_pres); - } - - public double ground_pressure() { - if (ground_pres == MISSING) - return MISSING; - return barometer_to_pressure(ground_pres); - } - - public double raw_altitude() { - double p = raw_pressure(); - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double ground_altitude() { - double p = ground_pressure(); - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double filtered_altitude() { - if (height != MISSING && ground_pres != MISSING) - return height + ground_altitude(); - - double p = filtered_pressure(); - if (p == MISSING) - return MISSING; - return AltosConvert.pressure_to_altitude(p); - } - - public double filtered_height() { - if (height != MISSING) - return height; - - double f = filtered_altitude(); - double g = ground_altitude(); - if (f == MISSING || g == MISSING) - return MISSING; - return f - g; - } - - public double raw_height() { - double r = raw_altitude(); - double g = ground_altitude(); - - if (r == MISSING || g == MISSING) - return height; - return r - g; - } - - public double battery_voltage() { - if (batt == MISSING) - return MISSING; - return AltosConvert.cc_battery_to_voltage(batt); - } - - public double main_voltage() { - if (main == MISSING) - return MISSING; - return AltosConvert.cc_ignitor_to_voltage(main); - } - - public double drogue_voltage() { - if (drogue == MISSING) - return MISSING; - return AltosConvert.cc_ignitor_to_voltage(drogue); - } - - /* Value for the CC1111 built-in temperature sensor - * Output voltage at 0°C = 0.755V - * Coefficient = 0.00247V/°C - * Reference voltage = 1.25V - * - * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 - * = (value - 19791.268) / 32768 * 1.25 / 0.00247 - */ - - public static double - thermometer_to_temperature(double thermo) - { - return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; - } - - public double temperature() { - if (temp == MISSING) - return MISSING; - return thermometer_to_temperature(temp); - } - - public double accel_counts_per_mss() { - double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; - - return counts_per_g / 9.80665; - } - - public double acceleration() { - if (acceleration != MISSING) - return acceleration; - - if (ground_accel == MISSING || accel == MISSING) - return MISSING; - return (ground_accel - accel) / accel_counts_per_mss(); - } - - public double accel_speed() { - if (speed != MISSING) - return speed; - if (flight_vel == MISSING) - return MISSING; - return flight_vel / (accel_counts_per_mss() * 100.0); - } - - public String state() { - return AltosLib.state_name(state); - } - - public static String gets(FileInputStream s) throws IOException { - int c; - String line = ""; - - while ((c = s.read()) != -1) { - if (c == '\r') - continue; - if (c == '\n') { - return line; - } - line = line + (char) c; - } - return null; - } - - public int compareTo(AltosRecord o) { - return tick - o.tick; - } - - public AltosRecord(AltosRecord old) { - version = old.version; - seen = old.seen; - callsign = old.callsign; - serial = old.serial; - flight = old.flight; - rssi = old.rssi; - status = old.status; - state = old.state; - tick = old.tick; - accel = old.accel; - pres = old.pres; - temp = old.temp; - batt = old.batt; - drogue = old.drogue; - main = old.main; - flight_accel = old.flight_accel; - ground_accel = old.ground_accel; - flight_vel = old.flight_vel; - flight_pres = old.flight_pres; - ground_pres = old.ground_pres; - accel_plus_g = old.accel_plus_g; - accel_minus_g = old.accel_minus_g; - acceleration = old.acceleration; - speed = old.speed; - height = old.height; - gps = new AltosGPS(old.gps); - new_gps = false; - companion = old.companion; - imu = old.imu; - mag = old.mag; - } - - public AltosRecord() { - version = 0; - seen = 0; - callsign = "N0CALL"; - serial = 0; - flight = 0; - rssi = 0; - status = 0; - state = AltosLib.ao_flight_startup; - tick = 0; - accel = MISSING; - pres = MISSING; - temp = MISSING; - batt = MISSING; - drogue = MISSING; - main = MISSING; - flight_accel = 0; - ground_accel = 0; - flight_vel = 0; - flight_pres = 0; - ground_pres = 0; - accel_plus_g = 0; - accel_minus_g = 0; - acceleration = MISSING; - speed = MISSING; - height = MISSING; - gps = new AltosGPS(); - new_gps = false; - companion = null; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java deleted file mode 100644 index c8cc6cac..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordCompanion.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.AltosLib; - -public class AltosRecordCompanion { - public final static int board_id_telescience = 0x0a; - public final static int MAX_CHANNELS = 12; - - public int tick; - public int board_id; - public int update_period; - public int channels; - public int[] companion_data; - - public AltosRecordCompanion(int in_channels) { - channels = in_channels; - if (channels < 0) - channels = 0; - if (channels > MAX_CHANNELS) - channels = MAX_CHANNELS; - companion_data = new int[channels]; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java deleted file mode 100644 index ed1787ed..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosRecordIterable.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; - -public abstract class AltosRecordIterable implements Iterable { - public abstract Iterator iterator(); - public void write_comments(PrintStream out) { } - public boolean has_accel() { return false; } - public boolean has_gps() { return false; } - public boolean has_ignite() { return false; }; -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java deleted file mode 100644 index 1585f9eb..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosReplayReader.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; - -/* - * Open an existing telemetry file and replay it in realtime - */ - -public class AltosReplayReader extends AltosFlightReader { - Iterator iterator; - File file; - - public AltosRecord read() { - if (iterator.hasNext()) - return iterator.next(); - return null; - } - - public void close (boolean interrupted) { - } - - public void update(AltosState state) throws InterruptedException { - /* Make it run in realtime after the rocket leaves the pad */ - if (state.state > AltosLib.ao_flight_pad) - Thread.sleep((int) (Math.min(state.time_change,10) * 1000)); - } - - public File backing_file() { return file; } - - public AltosReplayReader(Iterator in_iterator, File in_file) { - iterator = in_iterator; - file = in_file; - name = file.getName(); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosState.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosState.java deleted file mode 100644 index 0645e448..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosState.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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. - */ - -/* - * Track flight state from telemetry or eeprom data stream - */ - -package org.altusmetrum.AltosLib; - -public class AltosState { - public AltosRecord data; - - /* derived data */ - - public long report_time; - - public double time; - public double time_change; - public int tick; - - public int state; - public boolean landed; - public boolean ascent; /* going up? */ - public boolean boost; /* under power */ - - public double ground_altitude; - public double height; - public double speed; - public double acceleration; - public double battery; - public double temperature; - public double main_sense; - public double drogue_sense; - public double baro_speed; - - public double max_height; - public double max_acceleration; - public double max_speed; - public double max_baro_speed; - - public AltosGPS gps; - - public AltosIMU imu; - public AltosMag mag; - - public static final int MIN_PAD_SAMPLES = 10; - - public int npad; - public int ngps; - public int gps_waiting; - public boolean gps_ready; - - public AltosGreatCircle from_pad; - public double elevation; /* from pad */ - public double range; /* total distance */ - - public double gps_height; - - public int speak_tick; - public double speak_altitude; - - public void init (AltosRecord cur, AltosState prev_state) { - int i; - AltosRecord prev; - - data = cur; - - ground_altitude = data.ground_altitude(); - height = data.filtered_height(); - - report_time = System.currentTimeMillis(); - - acceleration = data.acceleration(); - speed = data.accel_speed(); - temperature = data.temperature(); - drogue_sense = data.drogue_voltage(); - main_sense = data.main_voltage(); - battery = data.battery_voltage(); - tick = data.tick; - state = data.state; - - if (prev_state != null) { - - /* Preserve any existing gps data */ - npad = prev_state.npad; - ngps = prev_state.ngps; - gps = prev_state.gps; - pad_lat = prev_state.pad_lat; - pad_lon = prev_state.pad_lon; - pad_alt = prev_state.pad_alt; - max_height = prev_state.max_height; - max_acceleration = prev_state.max_acceleration; - max_speed = prev_state.max_speed; - max_baro_speed = prev_state.max_baro_speed; - imu = prev_state.imu; - mag = prev_state.mag; - - /* make sure the clock is monotonic */ - while (tick < prev_state.tick) - tick += 65536; - - time_change = (tick - prev_state.tick) / 100.0; - - /* compute barometric speed */ - - double height_change = height - prev_state.height; - if (data.speed != AltosRecord.MISSING) - baro_speed = data.speed; - else { - if (time_change > 0) - baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0; - else - baro_speed = prev_state.baro_speed; - } - } else { - npad = 0; - ngps = 0; - gps = null; - baro_speed = 0; - time_change = 0; - } - - time = tick / 100.0; - - if (cur.new_gps && (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_idle)) { - - /* Track consecutive 'good' gps reports, waiting for 10 of them */ - if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) - npad++; - else - npad = 0; - - /* Average GPS data while on the pad */ - if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) { - if (ngps > 1) { - /* filter pad position */ - pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0; - pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0; - pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0; - } else { - pad_lat = data.gps.lat; - pad_lon = data.gps.lon; - pad_alt = data.gps.alt; - } - ngps++; - } - } - - gps_waiting = MIN_PAD_SAMPLES - npad; - if (gps_waiting < 0) - gps_waiting = 0; - - gps_ready = gps_waiting == 0; - - ascent = (AltosLib.ao_flight_boost <= state && - state <= AltosLib.ao_flight_coast); - boost = (AltosLib.ao_flight_boost == state); - - /* Only look at accelerometer data under boost */ - if (boost && acceleration > max_acceleration) - max_acceleration = acceleration; - if (boost && speed > max_speed) - max_speed = speed; - if (boost && baro_speed > max_baro_speed) - max_baro_speed = baro_speed; - - if (height > max_height) - max_height = height; - if (data.gps != null) { - if (gps == null || !gps.locked || data.gps.locked) - gps = data.gps; - if (ngps > 0 && gps.locked) { - from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); - } - } - elevation = 0; - range = -1; - if (ngps > 0) { - gps_height = gps.alt - pad_alt; - if (from_pad != null) { - elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; - range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); - } - } else { - gps_height = 0; - } - } - - public AltosState(AltosRecord cur) { - init(cur, null); - } - - public AltosState (AltosRecord cur, AltosState prev) { - init(cur, prev); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java deleted file mode 100644 index 04abb1f3..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetry.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -/* - * Telemetry data contents - */ - - -/* - * The packet format is a simple hex dump of the raw telemetry frame. - * It starts with 'TELEM', then contains hex digits with a checksum as the last - * byte on the line. - * - * Version 4 is a replacement with consistent syntax. Each telemetry line - * contains a sequence of space-separated names and values, the values are - * either integers or strings. The names are all unique. All values are - * optional - * - * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 - * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 - * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 - * - * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 - * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 - * - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - * - * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports - * in 1/2dB increments while this protocol provides only integers. So, - * the syntax didn't change just the interpretation of the RSSI - * values. - * - * Version 2 of the telemetry data stream is a bit of a mess, with no - * consistent formatting. In particular, the GPS data is formatted for - * viewing instead of parsing. However, the key feature is that every - * telemetry line contains all of the information necessary to - * describe the current rocket state, including the calibration values - * for accelerometer and barometer. - * - * GPS unlocked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ - * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ - * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 - * - * GPS locked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ - * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ - * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ - * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ - * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ - * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 - * - */ - -public class AltosTelemetry extends AltosRecord { - - /* - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - */ - - final static String AO_TELEM_VERSION = "VERSION"; - final static String AO_TELEM_CALL = "c"; - final static String AO_TELEM_SERIAL = "n"; - final static String AO_TELEM_FLIGHT = "f"; - final static String AO_TELEM_RSSI = "r"; - final static String AO_TELEM_STATE = "s"; - final static String AO_TELEM_TICK = "t"; - - /* - * Raw sensor values - * - * Name Value - * r_a Accelerometer reading (integer) - * r_b Barometer reading (integer) - * r_t Thermometer reading (integer) - * r_v Battery reading (integer) - * r_d Drogue continuity (integer) - * r_m Main continuity (integer) - */ - - final static String AO_TELEM_RAW_ACCEL = "r_a"; - final static String AO_TELEM_RAW_BARO = "r_b"; - final static String AO_TELEM_RAW_THERMO = "r_t"; - final static String AO_TELEM_RAW_BATT = "r_v"; - final static String AO_TELEM_RAW_DROGUE = "r_d"; - final static String AO_TELEM_RAW_MAIN = "r_m"; - - /* - * Sensor calibration values - * - * Name Value - * c_a Ground accelerometer reading (integer) - * c_b Ground barometer reading (integer) - * c_p Accelerometer reading for +1g - * c_m Accelerometer reading for -1g - */ - - final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; - final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; - final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; - final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; - - /* - * Kalman state values - * - * Name Value - * k_h Height above pad (integer, meters) - * k_s Vertical speeed (integer, m/s * 16) - * k_a Vertical acceleration (integer, m/s² * 16) - */ - - final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; - final static String AO_TELEM_KALMAN_SPEED = "k_s"; - final static String AO_TELEM_KALMAN_ACCEL = "k_a"; - - /* - * Ad-hoc flight values - * - * Name Value - * a_a Acceleration (integer, sensor units) - * a_s Speed (integer, integrated acceleration value) - * a_b Barometer reading (integer, sensor units) - */ - - final static String AO_TELEM_ADHOC_ACCEL = "a_a"; - final static String AO_TELEM_ADHOC_SPEED = "a_s"; - final static String AO_TELEM_ADHOC_BARO = "a_b"; - - /* - * GPS values - * - * Name Value - * g_s GPS state (string): - * l locked - * u unlocked - * e error (missing or broken) - * g_n Number of sats used in solution - * g_ns Latitude (degrees * 10e7) - * g_ew Longitude (degrees * 10e7) - * g_a Altitude (integer meters) - * g_Y GPS year (integer) - * g_M GPS month (integer - 1-12) - * g_D GPS day (integer - 1-31) - * g_h GPS hour (integer - 0-23) - * g_m GPS minute (integer - 0-59) - * g_s GPS second (integer - 0-59) - * g_v GPS vertical speed (integer, cm/sec) - * g_s GPS horizontal speed (integer, cm/sec) - * g_c GPS course (integer, 0-359) - * g_hd GPS hdop (integer * 10) - * g_vd GPS vdop (integer * 10) - * g_he GPS h error (integer) - * g_ve GPS v error (integer) - */ - - final static String AO_TELEM_GPS_STATE = "g"; - final static String AO_TELEM_GPS_STATE_LOCKED = "l"; - final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; - final static String AO_TELEM_GPS_STATE_ERROR = "e"; - final static String AO_TELEM_GPS_NUM_SAT = "g_n"; - final static String AO_TELEM_GPS_LATITUDE = "g_ns"; - final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; - final static String AO_TELEM_GPS_ALTITUDE = "g_a"; - final static String AO_TELEM_GPS_YEAR = "g_Y"; - final static String AO_TELEM_GPS_MONTH = "g_M"; - final static String AO_TELEM_GPS_DAY = "g_D"; - final static String AO_TELEM_GPS_HOUR = "g_h"; - final static String AO_TELEM_GPS_MINUTE = "g_m"; - final static String AO_TELEM_GPS_SECOND = "g_s"; - final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; - final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; - final static String AO_TELEM_GPS_COURSE = "g_c"; - final static String AO_TELEM_GPS_HDOP = "g_hd"; - final static String AO_TELEM_GPS_VDOP = "g_vd"; - final static String AO_TELEM_GPS_HERROR = "g_he"; - final static String AO_TELEM_GPS_VERROR = "g_ve"; - - /* - * GPS satellite values - * - * Name Value - * s_n Number of satellites reported (integer) - * s_v0 Space vehicle ID (integer) for report 0 - * s_c0 C/N0 number (integer) for report 0 - * s_v1 Space vehicle ID (integer) for report 1 - * s_c1 C/N0 number (integer) for report 1 - * ... - */ - - final static String AO_TELEM_SAT_NUM = "s_n"; - final static String AO_TELEM_SAT_SVID = "s_v"; - final static String AO_TELEM_SAT_C_N_0 = "s_c"; - - static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException { - AltosTelemetryRecord r = AltosTelemetryRecord.parse(line); - - return r.update_state(previous); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java deleted file mode 100644 index f4b4029f..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryIterable.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.AltosLib; - -import java.io.*; -import java.util.*; -import java.text.*; - -public class AltosTelemetryIterable extends AltosRecordIterable { - TreeSet records; - - public Iterator iterator () { - return records.iterator(); - } - - boolean has_gps = false; - boolean has_accel = false; - boolean has_ignite = false; - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; }; - - public AltosTelemetryIterable (FileInputStream input) { - boolean saw_boost = false; - int current_tick = 0; - int boost_tick = 0; - - AltosRecord previous = null; - records = new TreeSet (); - - try { - for (;;) { - String line = AltosRecord.gets(input); - if (line == null) { - break; - } - try { - AltosRecord record = AltosTelemetry.parse(line, previous); - if (record == null) - break; - if (records.isEmpty()) { - current_tick = record.tick; - } else { - int tick = record.tick; - while (tick < current_tick - 0x1000) - tick += 0x10000; - current_tick = tick; - record.tick = current_tick; - } - if (!saw_boost && record.state >= AltosLib.ao_flight_boost) - { - saw_boost = true; - boost_tick = record.tick; - } - if (record.accel != AltosRecord.MISSING) - has_accel = true; - if (record.gps != null) - has_gps = true; - if (record.main != AltosRecord.MISSING) - has_ignite = true; - if (previous != null && previous.tick != record.tick) - records.add(previous); - previous = record; - } catch (ParseException pe) { - System.out.printf("parse exception %s\n", pe.getMessage()); - } catch (AltosCRCException ce) { - } - } - } catch (IOException io) { - System.out.printf("io exception\n"); - } - - if (previous != null) - records.add(previous); - - /* Adjust all tick counts to match expected eeprom values, - * which starts with a 16-bit tick count 16 samples before boost - */ - - int tick_adjust = (boost_tick - 16) & 0xffff0000; - for (AltosRecord r : this) - r.tick -= tick_adjust; - boost_tick -= tick_adjust; - - /* adjust all tick counts to be relative to boost time */ - for (AltosRecord r : this) - r.time = (r.tick - boost_tick) / 100.0; - - try { - input.close(); - } catch (IOException ie) { - } - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java deleted file mode 100644 index 003cb6a9..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryMap.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.AltosLib; -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryMap extends HashMap { - public boolean has(String key) { - return containsKey(key); - } - - public String get_string(String key) throws ParseException { - if (!has(key)) - throw new ParseException ("missing " + key, 0); - return (String) get(key); - } - - public String get_string(String key, String def) { - if (has(key)) - return get(key); - else - return def; - } - - public int get_int(String key) throws ParseException { - return AltosParse.parse_int(get_string(key)); - } - - public int get_int(String key, int def) throws ParseException { - if (has(key)) - return get_int(key); - else - return def; - } - - public double get_double(String key, double def, double scale) throws ParseException { - if (has(key)) - return get_int(key) * scale; - else - return def; - } - - public AltosTelemetryMap(String[] words, int start) { - for (int i = start; i < words.length - 1; i += 2) - put(words[i], words[i+1]); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java deleted file mode 100644 index 67ac1b65..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryReader.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; -import java.io.*; -import java.util.concurrent.*; - -public class AltosTelemetryReader extends AltosFlightReader { - AltosLink link; - AltosLog log; - AltosRecord previous; - double frequency; - int telemetry; - - LinkedBlockingQueue telem; - - public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { - AltosLine l = telem.take(); - if (l.line == null) - throw new IOException("IO error"); - AltosRecord next = AltosTelemetry.parse(l.line, previous); - previous = next; - return next; - } - - public void flush() { - telem.clear(); - } - - public void close(boolean interrupted) { - link.remove_monitor(telem); - log.close(); - link.close(); - } - - public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - link.set_radio_frequency(frequency); - } - - public boolean supports_telemetry(int telemetry) { - - try { - /* Version 1.0 or later firmware supports all telemetry formats */ - if (serial.config_data().compare_version("1.0") >= 0) - return true; - - /* Version 0.9 firmware only supports 0.9 telemetry */ - if (serial.config_data().compare_version("0.9") >= 0) { - if (telemetry == Altos.ao_telemetry_0_9) - return true; - else - return false; - } - - /* Version 0.8 firmware only supports 0.8 telemetry */ - if (telemetry == Altos.ao_telemetry_0_8) - return true; - else - return false; - } catch (InterruptedException ie) { - return true; - } catch (TimeoutException te) { - return true; - } - } - - public void save_frequency() { - AltosPreferences.set_frequency(link.serial, frequency); - } - - public void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - link.set_telemetry(telemetry); - } - - public void save_telemetry() { - AltosPreferences.set_telemetry(link.serial, telemetry); - } - - public void set_monitor(boolean monitor) { - link.set_monitor(monitor); - } - - public File backing_file() { - return log.file(); - } - - public AltosTelemetryReader (AltosLink in_link) - throws IOException, InterruptedException, TimeoutException { - link = in_link; - log = new AltosLog(link); - name = link.name; - previous = null; - telem = new LinkedBlockingQueue(); - frequency = AltosPreferences.frequency(link.serial); - set_frequency(frequency); - telemetry = AltosPreferences.telemetry(link.serial); - set_telemetry(telemetry); - link.add_monitor(telem); - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java deleted file mode 100644 index 367c148d..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecord.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.AltosLib; - -public abstract class AltosTelemetryRecord { - - long received_time; - abstract public AltosRecord update_state(AltosRecord previous); - - static boolean cksum(int[] bytes) { - int sum = 0x5a; - for (int i = 1; i < bytes.length - 1; i++) - sum += bytes[i]; - sum &= 0xff; - return sum == bytes[bytes.length - 1]; - } - - final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7); - final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f); - final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0; - - final static int packet_type_TM_sensor = 0x01; - final static int packet_type_Tm_sensor = 0x02; - final static int packet_type_Tn_sensor = 0x03; - final static int packet_type_configuration = 0x04; - final static int packet_type_location = 0x05; - final static int packet_type_satellite = 0x06; - final static int packet_type_companion = 0x07; - - static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - int[] bytes; - try { - bytes = Altos.hexbytes(hex); - } catch (NumberFormatException ne) { - throw new ParseException(ne.getMessage(), 0); - } - - /* one for length, one for checksum */ - if (bytes[0] != bytes.length - 2) - throw new ParseException(String.format("invalid length %d != %d\n", - bytes[0], - bytes.length - 2), 0); - if (!cksum(bytes)) - throw new ParseException(String.format("invalid line \"%s\"", hex), 0); - - int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; - int status = Altos.uint8(bytes, bytes.length - 2); - - if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) - throw new AltosCRCException(rssi); - - /* length, data ..., rssi, status, checksum -- 4 bytes extra */ - switch (bytes.length) { - case Altos.ao_telemetry_standard_len + 4: - int type = Altos.uint8(bytes, 4 + 1); - switch (type) { - case packet_type_TM_sensor: - case packet_type_Tm_sensor: - case packet_type_Tn_sensor: - r = new AltosTelemetryRecordSensor(bytes, rssi); - break; - case packet_type_configuration: - r = new AltosTelemetryRecordConfiguration(bytes); - break; - case packet_type_location: - r = new AltosTelemetryRecordLocation(bytes); - break; - case packet_type_satellite: - r = new AltosTelemetryRecordSatellite(bytes); - break; - case packet_type_companion: - r = new AltosTelemetryRecordCompanion(bytes); - break; - default: - r = new AltosTelemetryRecordRaw(bytes); - break; - } - break; - case Altos.ao_telemetry_0_9_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - case Altos.ao_telemetry_0_8_len + 4: - r = new AltosTelemetryRecordLegacy(bytes, rssi, status); - break; - default: - throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0); - } - r.received_time = System.currentTimeMillis(); - return r; - } - - public static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - String[] word = line.split("\\s+"); - int i =0; - if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(word[i++], "RSSI"); - throw new AltosCRCException(AltosParse.parse_int(word[i++])); - } - - if (word[i].equals("TELEM")) - r = parse_hex(word[i+1]); - else - r = new AltosTelemetryRecordLegacy(line); - return r; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java deleted file mode 100644 index 6ad17244..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordCompanion.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.AltosLib; - -public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw { - - AltosRecordCompanion companion; - - public AltosTelemetryRecordCompanion(int[] in_bytes) { - super(in_bytes); - - int off = 0; - if (uint8(6) == 0) - off = 1; - int channels = uint8(7+off); - - if (off != 0 && channels >= 12) - channels = 11; - - companion = new AltosRecordCompanion(channels); - companion.tick = tick; - companion.board_id = uint8(5); - companion.update_period = uint8(6+off); - for (int i = 0; i < companion.companion_data.length; i++) - companion.companion_data[i] = uint16(8 + off + i * 2); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - next.companion = companion; - next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; - - companion.tick = tick; - return next; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java deleted file mode 100644 index 25242edc..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordConfiguration.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.AltosLib; - - -public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw { - int device_type; - int flight; - int config_major; - int config_minor; - int apogee_delay; - int main_deploy; - int flight_log_max; - String callsign; - String version; - - public AltosTelemetryRecordConfiguration(int[] in_bytes) { - super(in_bytes); - - device_type = uint8(5); - flight = uint16(6); - config_major = uint8(8); - config_minor = uint8(9); - apogee_delay = uint16(10); - main_deploy = uint16(12); - flight_log_max = uint16(14); - callsign = string(16, 8); - version = string(24, 8); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - next.device_type = device_type; - next.flight = flight; - next.config_major = config_major; - next.config_minor = config_minor; - next.apogee_delay = apogee_delay; - next.main_deploy = main_deploy; - next.flight_log_max = flight_log_max; - - next.callsign = callsign; - next.firmware_version = version; - - next.seen |= AltosRecord.seen_deploy | AltosRecord.seen_flight; - - return next; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java deleted file mode 100644 index 5e157a54..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordGeneral.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryRecordGeneral { - - static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException { - AltosTelemetryRecord r; - - String[] word = line.split("\\s+"); - int i =0; - if (word[i].equals("CRC") && word[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(word[i++], "RSSI"); - throw new AltosCRCException(AltosParse.parse_int(word[i++])); - } - - if (word[i].equals("TELEM")) - r = AltosTelemetryRecordRaw.parse(word[i+1]); - else - r = new AltosTelemetryRecordLegacy(line); - return r; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java deleted file mode 100644 index 8e3713cc..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLegacy.java +++ /dev/null @@ -1,521 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -/* - * Telemetry data contents - */ - - -/* - * The packet format is a simple hex dump of the raw telemetry frame. - * It starts with 'TELEM', then contains hex digits with a checksum as the last - * byte on the line. - * - * Version 4 is a replacement with consistent syntax. Each telemetry line - * contains a sequence of space-separated names and values, the values are - * either integers or strings. The names are all unique. All values are - * optional - * - * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944 - * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764 - * a_s 0 a_b 26439 g_s u g_n 0 s_n 0 - * - * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788 - * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0 - * - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - * - * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports - * in 1/2dB increments while this protocol provides only integers. So, - * the syntax didn't change just the interpretation of the RSSI - * values. - * - * Version 2 of the telemetry data stream is a bit of a mess, with no - * consistent formatting. In particular, the GPS data is formatted for - * viewing instead of parsing. However, the key feature is that every - * telemetry line contains all of the information necessary to - * describe the current rocket state, including the calibration values - * for accelerometer and barometer. - * - * GPS unlocked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ - * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ - * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 - * - * GPS locked: - * - * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ - * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ - * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ - * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ - * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ - * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 - * - */ - -public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { - /* - * General header fields - * - * Name Value - * - * VERSION Telemetry version number (4 or more). Must be first. - * c Callsign (string, no spaces allowed) - * n Flight unit serial number (integer) - * f Flight number (integer) - * r Packet RSSI value (integer) - * s Flight computer state (string, no spaces allowed) - * t Flight computer clock (integer in centiseconds) - */ - - final static String AO_TELEM_VERSION = "VERSION"; - final static String AO_TELEM_CALL = "c"; - final static String AO_TELEM_SERIAL = "n"; - final static String AO_TELEM_FLIGHT = "f"; - final static String AO_TELEM_RSSI = "r"; - final static String AO_TELEM_STATE = "s"; - final static String AO_TELEM_TICK = "t"; - - /* - * Raw sensor values - * - * Name Value - * r_a Accelerometer reading (integer) - * r_b Barometer reading (integer) - * r_t Thermometer reading (integer) - * r_v Battery reading (integer) - * r_d Drogue continuity (integer) - * r_m Main continuity (integer) - */ - - final static String AO_TELEM_RAW_ACCEL = "r_a"; - final static String AO_TELEM_RAW_BARO = "r_b"; - final static String AO_TELEM_RAW_THERMO = "r_t"; - final static String AO_TELEM_RAW_BATT = "r_v"; - final static String AO_TELEM_RAW_DROGUE = "r_d"; - final static String AO_TELEM_RAW_MAIN = "r_m"; - - /* - * Sensor calibration values - * - * Name Value - * c_a Ground accelerometer reading (integer) - * c_b Ground barometer reading (integer) - * c_p Accelerometer reading for +1g - * c_m Accelerometer reading for -1g - */ - - final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a"; - final static String AO_TELEM_CAL_BARO_GROUND = "c_b"; - final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p"; - final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m"; - - /* - * Kalman state values - * - * Name Value - * k_h Height above pad (integer, meters) - * k_s Vertical speeed (integer, m/s * 16) - * k_a Vertical acceleration (integer, m/s² * 16) - */ - - final static String AO_TELEM_KALMAN_HEIGHT = "k_h"; - final static String AO_TELEM_KALMAN_SPEED = "k_s"; - final static String AO_TELEM_KALMAN_ACCEL = "k_a"; - - /* - * Ad-hoc flight values - * - * Name Value - * a_a Acceleration (integer, sensor units) - * a_s Speed (integer, integrated acceleration value) - * a_b Barometer reading (integer, sensor units) - */ - - final static String AO_TELEM_ADHOC_ACCEL = "a_a"; - final static String AO_TELEM_ADHOC_SPEED = "a_s"; - final static String AO_TELEM_ADHOC_BARO = "a_b"; - - /* - * GPS values - * - * Name Value - * g_s GPS state (string): - * l locked - * u unlocked - * e error (missing or broken) - * g_n Number of sats used in solution - * g_ns Latitude (degrees * 10e7) - * g_ew Longitude (degrees * 10e7) - * g_a Altitude (integer meters) - * g_Y GPS year (integer) - * g_M GPS month (integer - 1-12) - * g_D GPS day (integer - 1-31) - * g_h GPS hour (integer - 0-23) - * g_m GPS minute (integer - 0-59) - * g_s GPS second (integer - 0-59) - * g_v GPS vertical speed (integer, cm/sec) - * g_s GPS horizontal speed (integer, cm/sec) - * g_c GPS course (integer, 0-359) - * g_hd GPS hdop (integer * 10) - * g_vd GPS vdop (integer * 10) - * g_he GPS h error (integer) - * g_ve GPS v error (integer) - */ - - final static String AO_TELEM_GPS_STATE = "g"; - final static String AO_TELEM_GPS_STATE_LOCKED = "l"; - final static String AO_TELEM_GPS_STATE_UNLOCKED = "u"; - final static String AO_TELEM_GPS_STATE_ERROR = "e"; - final static String AO_TELEM_GPS_NUM_SAT = "g_n"; - final static String AO_TELEM_GPS_LATITUDE = "g_ns"; - final static String AO_TELEM_GPS_LONGITUDE = "g_ew"; - final static String AO_TELEM_GPS_ALTITUDE = "g_a"; - final static String AO_TELEM_GPS_YEAR = "g_Y"; - final static String AO_TELEM_GPS_MONTH = "g_M"; - final static String AO_TELEM_GPS_DAY = "g_D"; - final static String AO_TELEM_GPS_HOUR = "g_h"; - final static String AO_TELEM_GPS_MINUTE = "g_m"; - final static String AO_TELEM_GPS_SECOND = "g_s"; - final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v"; - final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g"; - final static String AO_TELEM_GPS_COURSE = "g_c"; - final static String AO_TELEM_GPS_HDOP = "g_hd"; - final static String AO_TELEM_GPS_VDOP = "g_vd"; - final static String AO_TELEM_GPS_HERROR = "g_he"; - final static String AO_TELEM_GPS_VERROR = "g_ve"; - - /* - * GPS satellite values - * - * Name Value - * s_n Number of satellites reported (integer) - * s_v0 Space vehicle ID (integer) for report 0 - * s_c0 C/N0 number (integer) for report 0 - * s_v1 Space vehicle ID (integer) for report 1 - * s_c1 C/N0 number (integer) for report 1 - * ... - */ - - final static String AO_TELEM_SAT_NUM = "s_n"; - final static String AO_TELEM_SAT_SVID = "s_v"; - final static String AO_TELEM_SAT_C_N_0 = "s_c"; - - AltosRecord record; - - private void parse_v4(String[] words, int i) throws ParseException { - AltosTelemetryMap map = new AltosTelemetryMap(words, i); - - record.callsign = map.get_string(AO_TELEM_CALL, "N0CALL"); - record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING); - record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); - record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); - record.state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); - record.tick = map.get_int(AO_TELEM_TICK, 0); - - /* raw sensor values */ - record.accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING); - record.pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING); - record.temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING); - record.batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING); - record.drogue = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING); - record.main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING); - - /* sensor calibration information */ - record.ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING); - record.ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING); - record.accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING); - record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING); - - /* flight computer values */ - record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); - record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); - record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); - - record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING); - record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); - record.flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING); - - if (map.has(AO_TELEM_GPS_STATE)) { - record.gps = new AltosGPS(map); - record.new_gps = true; - } - else - record.gps = null; - } - - private void parse_legacy(String[] words, int i) throws ParseException { - - AltosParse.word (words[i++], "CALL"); - record.callsign = words[i++]; - - AltosParse.word (words[i++], "SERIAL"); - record.serial = AltosParse.parse_int(words[i++]); - - if (record.version >= 2) { - AltosParse.word (words[i++], "FLIGHT"); - record.flight = AltosParse.parse_int(words[i++]); - } else - record.flight = 0; - - AltosParse.word(words[i++], "RSSI"); - record.rssi = AltosParse.parse_int(words[i++]); - - /* Older telemetry data had mis-computed RSSI value */ - if (record.version <= 2) - record.rssi = (record.rssi + 74) / 2 - 74; - - AltosParse.word(words[i++], "STATUS"); - record.status = AltosParse.parse_hex(words[i++]); - - AltosParse.word(words[i++], "STATE"); - record.state = Altos.state(words[i++]); - - record.tick = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "a:"); - record.accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "p:"); - record.pres = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "t:"); - record.temp = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "v:"); - record.batt = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "d:"); - record.drogue = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "m:"); - record.main = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fa:"); - record.flight_accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "ga:"); - record.ground_accel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fv:"); - record.flight_vel = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "fp:"); - record.flight_pres = AltosParse.parse_int(words[i++]); - - /* Old TeleDongle code with kalman-reporting TeleMetrum code */ - if ((record.flight_vel & 0xffff0000) == 0x80000000) { - record.speed = ((short) record.flight_vel) / 16.0; - record.acceleration = record.flight_accel / 16.0; - record.height = record.flight_pres; - record.flight_vel = AltosRecord.MISSING; - record.flight_pres = AltosRecord.MISSING; - record.flight_accel = AltosRecord.MISSING; - } - - AltosParse.word(words[i++], "gp:"); - record.ground_pres = AltosParse.parse_int(words[i++]); - - if (record.version >= 1) { - AltosParse.word(words[i++], "a+:"); - record.accel_plus_g = AltosParse.parse_int(words[i++]); - - AltosParse.word(words[i++], "a-:"); - record.accel_minus_g = AltosParse.parse_int(words[i++]); - } else { - record.accel_plus_g = record.ground_accel; - record.accel_minus_g = record.ground_accel + 530; - } - - record.gps = new AltosGPS(words, i, record.version); - record.new_gps = true; - } - - public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException { - String[] words = line.split("\\s+"); - int i = 0; - - record = new AltosRecord(); - - if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { - i += 2; - AltosParse.word(words[i++], "RSSI"); - record.rssi = AltosParse.parse_int(words[i++]); - throw new AltosCRCException(record.rssi); - } - if (words[i].equals("CALL")) { - record.version = 0; - } else { - AltosParse.word (words[i++], "VERSION"); - record.version = AltosParse.parse_int(words[i++]); - } - - if (record.version < 4) - parse_legacy(words, i); - else - parse_v4(words, i); - } - - /* - * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that - */ - - int[] bytes; - int adjust; - - private int int8(int i) { - return AltosLib.int8(bytes, i + 1 + adjust); - } - private int uint8(int i) { - return AltosLib.uint8(bytes, i + 1 + adjust); - } - private int int16(int i) { - return AltosLib.int16(bytes, i + 1 + adjust); - } - private int uint16(int i) { - return AltosLib.uint16(bytes, i + 1 + adjust); - } - private int uint32(int i) { - return AltosLib.uint32(bytes, i + 1 + adjust); - } - private String string(int i, int l) { - return AltosLib.string(bytes, i + 1 + adjust, l); - } - - static final int AO_GPS_NUM_SAT_MASK = (0xf << 0); - static final int AO_GPS_NUM_SAT_SHIFT = (0); - - static final int AO_GPS_VALID = (1 << 4); - static final int AO_GPS_RUNNING = (1 << 5); - static final int AO_GPS_DATE_VALID = (1 << 6); - static final int AO_GPS_COURSE_VALID = (1 << 7); - - public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { - record = new AltosRecord(); - - bytes = in_bytes; - record.version = 4; - adjust = 0; - - if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) { - record.serial = uint8(0); - adjust = -1; - } else - record.serial = uint16(0); - - record.seen = AltosRecord.seen_flight | AltosRecord.seen_sensor | AltosRecord.seen_temp_volt | AltosRecord.seen_deploy; - - record.callsign = string(62, 8); - record.flight = uint16(2); - record.rssi = in_rssi; - record.status = in_status; - record.state = uint8(4); - record.tick = uint16(21); - record.accel = int16(23); - record.pres = int16(25); - record.temp = int16(27); - record.batt = int16(29); - record.drogue = int16(31); - record.main = int16(33); - - record.ground_accel = int16(7); - record.ground_pres = int16(15); - record.accel_plus_g = int16(17); - record.accel_minus_g = int16(19); - - if (uint16(11) == 0x8000) { - record.acceleration = int16(5); - record.speed = int16(9); - record.height = int16(13); - record.flight_accel = AltosRecord.MISSING; - record.flight_vel = AltosRecord.MISSING; - record.flight_pres = AltosRecord.MISSING; - } else { - record.flight_accel = int16(5); - record.flight_vel = uint32(9); - record.flight_pres = int16(13); - record.acceleration = AltosRecord.MISSING; - record.speed = AltosRecord.MISSING; - record.height = AltosRecord.MISSING; - } - - record.gps = null; - - int gps_flags = uint8(41); - - if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) { - record.gps = new AltosGPS(); - record.new_gps = true; - - record.seen |= record.seen_gps_time | record.seen_gps_lat | record.seen_gps_lon; - record.gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK); - record.gps.locked = (gps_flags & AO_GPS_VALID) != 0; - record.gps.connected = true; - record.gps.lat = uint32(42) / 1.0e7; - record.gps.lon = uint32(46) / 1.0e7; - record.gps.alt = int16(50); - record.gps.ground_speed = uint16(52) / 100.0; - record.gps.course = uint8(54) * 2; - record.gps.hdop = uint8(55) / 5.0; - record.gps.h_error = uint16(58); - record.gps.v_error = uint16(60); - - int n_tracking_reported = uint8(70); - if (n_tracking_reported > 12) - n_tracking_reported = 12; - int n_tracking_actual = 0; - for (int i = 0; i < n_tracking_reported; i++) { - if (uint8(71 + i*2) != 0) - n_tracking_actual++; - } - if (n_tracking_actual > 0) { - record.gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual]; - - n_tracking_actual = 0; - for (int i = 0; i < n_tracking_reported; i++) { - int svid = uint8(71 + i*2); - int c_n0 = uint8(72 + i*2); - if (svid != 0) - record.gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0); - } - } - } - - record.time = 0.0; - } - - public AltosRecord update_state(AltosRecord previous) { - return record; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java deleted file mode 100644 index cddb773d..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordLocation.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.AltosLib; - - -public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw { - int flags; - int altitude; - int latitude; - int longitude; - int year; - int month; - int day; - int hour; - int minute; - int second; - int pdop; - int hdop; - int vdop; - int mode; - int ground_speed; - int climb_rate; - int course; - - public AltosTelemetryRecordLocation(int[] in_bytes) { - super(in_bytes); - - flags = uint8(5); - altitude = int16(6); - latitude = uint32(8); - longitude = uint32(12); - year = uint8(16); - month = uint8(17); - day = uint8(18); - hour = uint8(19); - minute = uint8(20); - second = uint8(21); - pdop = uint8(22); - hdop = uint8(23); - vdop = uint8(24); - mode = uint8(25); - ground_speed = uint16(26); - climb_rate = int16(28); - course = uint8(30); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - if (next.gps == null) - next.gps = new AltosGPS(); - - next.gps.nsat = flags & 0xf; - next.gps.locked = (flags & (1 << 4)) != 0; - next.gps.connected = (flags & (1 << 5)) != 0; - - if (next.gps.locked) { - next.gps.lat = latitude * 1.0e-7; - next.gps.lon = longitude * 1.0e-7; - next.gps.alt = altitude; - next.gps.year = 2000 + year; - next.gps.month = month; - next.gps.day = day; - next.gps.hour = hour; - next.gps.minute = minute; - next.gps.second = second; - next.gps.ground_speed = ground_speed * 1.0e-2; - next.gps.course = course * 2; - next.gps.climb_rate = climb_rate * 1.0e-2; - next.gps.hdop = hdop; - next.gps.vdop = vdop; - next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon; - next.new_gps = true; - } - - return next; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java deleted file mode 100644 index 43d0f17a..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordRaw.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.AltosLib; - -import java.lang.*; -import java.text.*; -import java.util.HashMap; - -public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { - int[] bytes; - int serial; - int tick; - int type; - - long received_time; - - public int int8(int off) { - return AltosLib.int8(bytes, off + 1); - } - - public int uint8(int off) { - return AltosLib.uint8(bytes, off + 1); - } - - public int int16(int off) { - return AltosLib.int16(bytes, off + 1); - } - - public int uint16(int off) { - return AltosLib.uint16(bytes, off + 1); - } - - public int uint32(int off) { - return AltosLib.uint32(bytes, off + 1); - } - - public String string(int off, int l) { - return AltosLib.string(bytes, off + 1, l); - } - - public AltosTelemetryRecordRaw(int[] in_bytes) { - bytes = in_bytes; - serial = uint16(0); - tick = uint16(2); - type = uint8(4); - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next; - if (previous != null) - next = new AltosRecord(previous); - else - next = new AltosRecord(); - next.serial = serial; - next.tick = tick; - return next; - } - - public long received_time() { - return received_time; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java deleted file mode 100644 index 2526afb6..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSatellite.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.AltosLib; - -public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw { - int channels; - AltosGPSSat[] sats; - - public AltosTelemetryRecordSatellite(int[] in_bytes) { - super(in_bytes); - - channels = uint8(5); - if (channels > 12) - channels = 12; - if (channels == 0) - sats = null; - else { - sats = new AltosGPSSat[channels]; - for (int i = 0; i < channels; i++) { - int svid = uint8(6 + i * 2 + 0); - int c_n_1 = uint8(6 + i * 2 + 1); - sats[i] = new AltosGPSSat(svid, c_n_1); - } - } - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - if (next.gps == null) - next.gps = new AltosGPS(); - - next.gps.cc_gps_sat = sats; - - return next; - } -} diff --git a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java b/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java deleted file mode 100644 index cfaf90b0..00000000 --- a/altosui/altoslib/src/org/altusmetrum/AltosLib/AltosTelemetryRecordSensor.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.AltosLib; - - -public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { - int state; - int accel; - int pres; - int temp; - int v_batt; - int sense_d; - int sense_m; - - int acceleration; - int speed; - int height; - - int ground_accel; - int ground_pres; - int accel_plus_g; - int accel_minus_g; - - int rssi; - - public AltosTelemetryRecordSensor(int[] in_bytes, int in_rssi) { - super(in_bytes); - state = uint8(5); - - accel = int16(6); - pres = int16(8); - temp = int16(10); - v_batt = int16(12); - sense_d = int16(14); - sense_m = int16(16); - - acceleration = int16(18); - speed = int16(20); - height = int16(22); - - ground_pres = int16(24); - ground_accel = int16(26); - accel_plus_g = int16(28); - accel_minus_g = int16(30); - - rssi = in_rssi; - } - - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); - - next.state = state; - if (type == packet_type_TM_sensor) - next.accel = accel; - else - next.accel = AltosRecord.MISSING; - next.pres = pres; - next.temp = temp; - next.batt = v_batt; - if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) { - next.drogue = sense_d; - next.main = sense_m; - } else { - next.drogue = AltosRecord.MISSING; - next.main = AltosRecord.MISSING; - } - - next.acceleration = acceleration / 16.0; - next.speed = speed / 16.0; - next.height = height; - - next.ground_pres = ground_pres; - if (type == packet_type_TM_sensor) { - next.ground_accel = ground_accel; - next.accel_plus_g = accel_plus_g; - next.accel_minus_g = accel_minus_g; - } else { - next.ground_accel = AltosRecord.MISSING; - next.accel_plus_g = AltosRecord.MISSING; - next.accel_minus_g = AltosRecord.MISSING; - } - - next.rssi = rssi; - - next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt; - - return next; - } -} diff --git a/configure.ac b/configure.ac index efccf714..fb078e80 100644 --- a/configure.ac +++ b/configure.ac @@ -111,9 +111,9 @@ PKG_CHECK_MODULES([LIBUSB], [libusb-1.0]) AC_OUTPUT([ Makefile +altoslib/Makefile altosui/Makefile altosui/AltosVersion.java -altosui/altoslib/Makefile altosui/libaltos/Makefile ao-tools/Makefile ao-tools/lib/Makefile -- cgit v1.2.3 From bb5b5312a0c6102b12f3d4710ef213f0f6c67412 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Jan 2012 20:56:49 -0800 Subject: altosui: Clean up a few 'fat' build rules Signed-off-by: Keith Packard --- altosui/Makefile.am | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index d494547b..1ec45c5f 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -259,7 +259,7 @@ altosui-jdb: Makefile echo 'exec jdb -classpath "classes:libaltos:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" altosui/AltosUI "$$@"' >> $@ chmod +x $@ -libaltos.so: +libaltos.so: build-libaltos -rm -f "$@" $(LN_S) libaltos/.libs/"$@" . @@ -275,10 +275,14 @@ 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 @@ -289,7 +293,7 @@ $(ALTOSLIB_CLASS): -rm -f "$@" $(LN_S) ../altoslib/"$@" . -$(FREETTS_CLASS): ../altoslib/"$@" +$(FREETTS_CLASS): -rm -f "$@" $(LN_S) "$(FREETTS)"/"$@" . -- cgit v1.2.3 From dd43a2ae7594f062a8980d1756a07488ee54b447 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Jun 2012 19:42:47 -0700 Subject: altoslib: Move new sensor library code into altoslib Signed-off-by: Keith Packard --- altoslib/AltosIMU.java | 29 ++++++++++++++++++ altoslib/AltosMag.java | 25 ++++++++++++++++ altoslib/AltosMs5607.java | 76 +++++++++++++++++++++++++++++++++++++++++++++++ altoslib/Makefile.am | 5 +++- altosui/AltosIMU.java | 29 ------------------ altosui/AltosMag.java | 25 ---------------- altosui/AltosMs5607.java | 76 ----------------------------------------------- altosui/Makefile.am | 3 -- 8 files changed, 134 insertions(+), 134 deletions(-) create mode 100644 altoslib/AltosIMU.java create mode 100644 altoslib/AltosMag.java create mode 100644 altoslib/AltosMs5607.java delete mode 100644 altosui/AltosIMU.java delete mode 100644 altosui/AltosMag.java delete mode 100644 altosui/AltosMs5607.java (limited to 'altosui') diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java new file mode 100644 index 00000000..88e36544 --- /dev/null +++ b/altoslib/AltosIMU.java @@ -0,0 +1,29 @@ +/* + * 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 altoslib; + +public class AltosIMU { + public int accel_x; + public int accel_y; + public int accel_z; + + public int gyro_x; + public int gyro_y; + public int gyro_z; +} + \ No newline at end of file diff --git a/altoslib/AltosMag.java b/altoslib/AltosMag.java new file mode 100644 index 00000000..45f1924c --- /dev/null +++ b/altoslib/AltosMag.java @@ -0,0 +1,25 @@ +/* + * 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 altoslib; + +public class AltosMag { + public int x; + public int y; + public int z; +} + \ No newline at end of file diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java new file mode 100644 index 00000000..253e2f9b --- /dev/null +++ b/altoslib/AltosMs5607.java @@ -0,0 +1,76 @@ +/* + * 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 altoslib; + +public class AltosMs5607 { + public int reserved; + public int sens; + public int off; + public int tcs; + public int tco; + public int tref; + public int tempsens; + public int crc; + + public int raw_pres; + public int raw_temp; + public int pa; + public int cc; + + void convert() { + int dT; + int TEMP; + long OFF; + long SENS; + int P; + + dT = raw_temp - ((int) tref << 8); + + TEMP = (int) (2000 + (((long) dT * tempsens) >> 23)); + + OFF = ((long) off << 17) + (((long) tco * dT) >> 6); + + SENS = ((long) sens << 16) + (((long) tcs * dT) >> 7); + + if (TEMP < 2000) { + int T2 = (int) (((long) dT * (long) dT) >> 31); + int TEMPM = TEMP - 2000; + long OFF2 = (61 * (long) TEMPM * (long) TEMPM) >> 4; + long SENS2 = 2 * (long) TEMPM * (long) TEMPM; + if (TEMP < 1500) { + int TEMPP = TEMP + 1500; + long TEMPP2 = TEMPP * TEMPP; + OFF2 = OFF2 + 15 * TEMPP2; + SENS2 = SENS2 + 8 * TEMPP2; + } + TEMP -= T2; + OFF -= OFF2; + SENS -= SENS2; + } + + pa = (int) (((((long) raw_pres * SENS) >> 21) - OFF) >> 15); + cc = TEMP; + } + + public int set(int in_pres, int in_temp) { + raw_pres = in_pres; + raw_temp = in_temp; + convert(); + return pa; + } +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 4262daca..2e4a795a 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -47,7 +47,10 @@ AltosLib_JAVA = \ $(SRC)/AltosTelemetryRecordLocation.java \ $(SRC)/AltosTelemetryRecordRaw.java \ $(SRC)/AltosTelemetryRecordSatellite.java \ - $(SRC)/AltosTelemetryRecordSensor.java + $(SRC)/AltosTelemetryRecordSensor.java \ + $(SRC)/AltosMs5607.java \ + $(SRC)/AltosIMU.java \ + $(SRC)/AltosMag.java JAR=AltosLib.jar diff --git a/altosui/AltosIMU.java b/altosui/AltosIMU.java deleted file mode 100644 index 1f865a65..00000000 --- a/altosui/AltosIMU.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 altosui; - -public class AltosIMU { - int accel_x; - int accel_y; - int accel_z; - - int gyro_x; - int gyro_y; - int gyro_z; -} - \ No newline at end of file diff --git a/altosui/AltosMag.java b/altosui/AltosMag.java deleted file mode 100644 index b3fc542b..00000000 --- a/altosui/AltosMag.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 altosui; - -public class AltosMag { - int x; - int y; - int z; -} - \ No newline at end of file diff --git a/altosui/AltosMs5607.java b/altosui/AltosMs5607.java deleted file mode 100644 index 6f8bdbbe..00000000 --- a/altosui/AltosMs5607.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 altosui; - -public class AltosMs5607 { - int reserved; - int sens; - int off; - int tcs; - int tco; - int tref; - int tempsens; - int crc; - - int raw_pres; - int raw_temp; - public int pa; - public int cc; - - void convert() { - int dT; - int TEMP; - long OFF; - long SENS; - int P; - - dT = raw_temp - ((int) tref << 8); - - TEMP = (int) (2000 + (((long) dT * tempsens) >> 23)); - - OFF = ((long) off << 17) + (((long) tco * dT) >> 6); - - SENS = ((long) sens << 16) + (((long) tcs * dT) >> 7); - - if (TEMP < 2000) { - int T2 = (int) (((long) dT * (long) dT) >> 31); - int TEMPM = TEMP - 2000; - long OFF2 = (61 * (long) TEMPM * (long) TEMPM) >> 4; - long SENS2 = 2 * (long) TEMPM * (long) TEMPM; - if (TEMP < 1500) { - int TEMPP = TEMP + 1500; - long TEMPP2 = TEMPP * TEMPP; - OFF2 = OFF2 + 15 * TEMPP2; - SENS2 = SENS2 + 8 * TEMPP2; - } - TEMP -= T2; - OFF -= OFF2; - SENS -= SENS2; - } - - pa = (int) (((((long) raw_pres * SENS) >> 21) - OFF) >> 15); - cc = TEMP; - } - - public int set(int in_pres, int in_temp) { - raw_pres = in_pres; - raw_temp = in_temp; - convert(); - return pa; - } -} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 1ec45c5f..0a6ae59e 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -45,9 +45,6 @@ altosui_JAVA = \ AltosEepromTeleScience.java \ AltosEepromMega.java \ AltosEepromMegaIterable.java \ - AltosMs5607.java \ - AltosIMU.java \ - AltosMag.java \ AltosEepromSelect.java \ AltosFlash.java \ AltosFlashUI.java \ -- cgit v1.2.3 From f86dac643081987c8994ab57a96640d5e91b342a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Jun 2012 19:59:40 -0700 Subject: altoslib: Clean up random rebase failures Signed-off-by: Keith Packard --- altoslib/AltosConfigData.java | 2 +- altoslib/AltosEepromIterable.java | 16 ++++---- altoslib/AltosIMU.java | 2 +- altoslib/AltosLib.java | 11 ++++++ altoslib/AltosMag.java | 2 +- altoslib/AltosMs5607.java | 2 +- altoslib/AltosRecord.java | 1 - altoslib/AltosState.java | 2 + altoslib/AltosTelemetryReader.java | 8 ++-- altoslib/AltosTelemetryRecord.java | 15 +++---- altoslib/AltosTelemetryRecordLegacy.java | 4 +- altosui/Altos.java | 67 -------------------------------- altosui/AltosSerial.java | 3 -- altosui/Makefile.am | 3 -- 14 files changed, 39 insertions(+), 99 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 4ad4e58a..fa6a72b5 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -104,7 +104,7 @@ public class AltosConfigData implements Iterable { for (int i = 0; i < parts.length; i++) { try { - r[i] = Altos.fromdec(parts[i]); + r[i] = AltosLib.fromdec(parts[i]); } catch (NumberFormatException n) { r[i] = 0; } diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index f1397c7b..a923d63b 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -318,28 +318,28 @@ public class AltosEepromIterable extends AltosRecordIterable { case AltosLib.AO_LOG_SOFTWARE_VERSION: out.printf ("# Software version: %s\n", record.data); break; - case Altos.AO_LOG_BARO_RESERVED: + case AltosLib.AO_LOG_BARO_RESERVED: out.printf ("# Baro reserved: %d\n", record.a); break; - case Altos.AO_LOG_BARO_SENS: + case AltosLib.AO_LOG_BARO_SENS: out.printf ("# Baro sens: %d\n", record.a); break; - case Altos.AO_LOG_BARO_OFF: + case AltosLib.AO_LOG_BARO_OFF: out.printf ("# Baro off: %d\n", record.a); break; - case Altos.AO_LOG_BARO_TCS: + case AltosLib.AO_LOG_BARO_TCS: out.printf ("# Baro tcs: %d\n", record.a); break; - case Altos.AO_LOG_BARO_TCO: + case AltosLib.AO_LOG_BARO_TCO: out.printf ("# Baro tco: %d\n", record.a); break; - case Altos.AO_LOG_BARO_TREF: + case AltosLib.AO_LOG_BARO_TREF: out.printf ("# Baro tref: %d\n", record.a); break; - case Altos.AO_LOG_BARO_TEMPSENS: + case AltosLib.AO_LOG_BARO_TEMPSENS: out.printf ("# Baro tempsens: %d\n", record.a); break; - case Altos.AO_LOG_BARO_CRC: + case AltosLib.AO_LOG_BARO_CRC: out.printf ("# Baro crc: %d\n", record.a); break; } diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index 88e36544..c0eaf139 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altoslib; +package org.altusmetrum.AltosLib; public class AltosIMU { public int accel_x; diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 2921d040..27d72079 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -50,6 +50,17 @@ public class AltosLib { public static final int AO_LOG_PRODUCT = 2001; public static final int AO_LOG_SERIAL_NUMBER = 2002; public static final int AO_LOG_LOG_FORMAT = 2003; + + /* Added for header fields in megametrum files */ + public static final int AO_LOG_BARO_RESERVED = 3000; + public static final int AO_LOG_BARO_SENS = 3001; + public static final int AO_LOG_BARO_OFF = 3002; + public static final int AO_LOG_BARO_TCS = 3004; + public static final int AO_LOG_BARO_TCO = 3005; + public static final int AO_LOG_BARO_TREF = 3006; + public static final int AO_LOG_BARO_TEMPSENS = 3007; + public static final int AO_LOG_BARO_CRC = 3008; + public static final int AO_LOG_SOFTWARE_VERSION = 9999; /* Added to flag invalid records */ diff --git a/altoslib/AltosMag.java b/altoslib/AltosMag.java index 45f1924c..0f8399ab 100644 --- a/altoslib/AltosMag.java +++ b/altoslib/AltosMag.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altoslib; +package org.altusmetrum.AltosLib; public class AltosMag { public int x; diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java index 253e2f9b..a7b902e2 100644 --- a/altoslib/AltosMs5607.java +++ b/altoslib/AltosMs5607.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altoslib; +package org.altusmetrum.AltosLib; public class AltosMs5607 { public int reserved; diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index e4915af0..10ef3061 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -82,7 +82,6 @@ public class AltosRecord implements Comparable { public AltosRecordCompanion companion; ->>>>>>> 5a249bc... altosui: Complete split out of separate java library /* * Values for our MP3H6115A pressure sensor * diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 0645e448..68c7611f 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -70,6 +70,8 @@ public class AltosState { public double gps_height; + public double pad_lat, pad_lon, pad_alt; + public int speak_tick; public double speak_altitude; diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 67ac1b65..112e008e 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -59,19 +59,19 @@ public class AltosTelemetryReader extends AltosFlightReader { try { /* Version 1.0 or later firmware supports all telemetry formats */ - if (serial.config_data().compare_version("1.0") >= 0) + if (link.config_data().compare_version("1.0") >= 0) return true; /* Version 0.9 firmware only supports 0.9 telemetry */ - if (serial.config_data().compare_version("0.9") >= 0) { - if (telemetry == Altos.ao_telemetry_0_9) + if (link.config_data().compare_version("0.9") >= 0) { + if (telemetry == AltosLib.ao_telemetry_0_9) return true; else return false; } /* Version 0.8 firmware only supports 0.8 telemetry */ - if (telemetry == Altos.ao_telemetry_0_8) + if (telemetry == AltosLib.ao_telemetry_0_8) return true; else return false; diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java index 367c148d..4292dae8 100644 --- a/altoslib/AltosTelemetryRecord.java +++ b/altoslib/AltosTelemetryRecord.java @@ -16,6 +16,7 @@ */ package org.altusmetrum.AltosLib; +import java.text.*; public abstract class AltosTelemetryRecord { @@ -47,7 +48,7 @@ public abstract class AltosTelemetryRecord { int[] bytes; try { - bytes = Altos.hexbytes(hex); + bytes = AltosLib.hexbytes(hex); } catch (NumberFormatException ne) { throw new ParseException(ne.getMessage(), 0); } @@ -60,16 +61,16 @@ public abstract class AltosTelemetryRecord { if (!cksum(bytes)) throw new ParseException(String.format("invalid line \"%s\"", hex), 0); - int rssi = Altos.int8(bytes, bytes.length - 3) / 2 - 74; - int status = Altos.uint8(bytes, bytes.length - 2); + int rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74; + int status = AltosLib.uint8(bytes, bytes.length - 2); if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0) throw new AltosCRCException(rssi); /* length, data ..., rssi, status, checksum -- 4 bytes extra */ switch (bytes.length) { - case Altos.ao_telemetry_standard_len + 4: - int type = Altos.uint8(bytes, 4 + 1); + case AltosLib.ao_telemetry_standard_len + 4: + int type = AltosLib.uint8(bytes, 4 + 1); switch (type) { case packet_type_TM_sensor: case packet_type_Tm_sensor: @@ -93,10 +94,10 @@ public abstract class AltosTelemetryRecord { break; } break; - case Altos.ao_telemetry_0_9_len + 4: + case AltosLib.ao_telemetry_0_9_len + 4: r = new AltosTelemetryRecordLegacy(bytes, rssi, status); break; - case Altos.ao_telemetry_0_8_len + 4: + case AltosLib.ao_telemetry_0_8_len + 4: r = new AltosTelemetryRecordLegacy(bytes, rssi, status); break; default: diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java index 8e3713cc..85071d9c 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -241,7 +241,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING); record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING); record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING); - record.state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid")); + record.state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid")); record.tick = map.get_int(AO_TELEM_TICK, 0); /* raw sensor values */ @@ -300,7 +300,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { record.status = AltosParse.parse_hex(words[i++]); AltosParse.word(words[i++], "STATE"); - record.state = Altos.state(words[i++]); + record.state = AltosLib.state(words[i++]); record.tick = AltosParse.parse_int(words[i++]); diff --git a/altosui/Altos.java b/altosui/Altos.java index 380796cc..334ddb07 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -28,73 +28,6 @@ import org.altusmetrum.AltosLib.*; public class Altos extends AltosLib { - /* Added for header fields in eeprom files */ - static final int AO_LOG_CONFIG_VERSION = 1000; - static final int AO_LOG_MAIN_DEPLOY = 1001; - static final int AO_LOG_APOGEE_DELAY = 1002; - static final int AO_LOG_RADIO_CHANNEL = 1003; - static final int AO_LOG_CALLSIGN = 1004; - static final int AO_LOG_ACCEL_CAL = 1005; - static final int AO_LOG_RADIO_CAL = 1006; - static final int AO_LOG_MAX_FLIGHT_LOG = 1007; - static final int AO_LOG_MANUFACTURER = 2000; - static final int AO_LOG_PRODUCT = 2001; - static final int AO_LOG_SERIAL_NUMBER = 2002; - static final int AO_LOG_LOG_FORMAT = 2003; - - /* Added for header fields in megametrum files */ - static final int AO_LOG_BARO_RESERVED = 3000; - static final int AO_LOG_BARO_SENS = 3001; - static final int AO_LOG_BARO_OFF = 3002; - static final int AO_LOG_BARO_TCS = 3004; - static final int AO_LOG_BARO_TCO = 3005; - static final int AO_LOG_BARO_TREF = 3006; - static final int AO_LOG_BARO_TEMPSENS = 3007; - static final int AO_LOG_BARO_CRC = 3008; - - static final int AO_LOG_SOFTWARE_VERSION = 9999; - - /* Added to flag invalid records */ - static final int AO_LOG_INVALID = -1; - - /* Flight state numbers and names */ - static final int ao_flight_startup = 0; - static final int ao_flight_idle = 1; - static final int ao_flight_pad = 2; - static final int ao_flight_boost = 3; - static final int ao_flight_fast = 4; - static final int ao_flight_coast = 5; - static final int ao_flight_drogue = 6; - static final int ao_flight_main = 7; - static final int ao_flight_landed = 8; - static final int ao_flight_invalid = 9; - - /* Telemetry modes */ - static final int ao_telemetry_off = 0; - static final int ao_telemetry_min = 1; - static final int ao_telemetry_standard = 1; - static final int ao_telemetry_0_9 = 2; - static final int ao_telemetry_0_8 = 3; - static final int ao_telemetry_max = 3; - - static final String[] ao_telemetry_name = { - "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" - }; - - static final String launch_sites_url = "http://www.altusmetrum.org/AltOS/launch-sites.txt"; - - static final int ao_telemetry_standard_len = 32; - static final int ao_telemetry_0_9_len = 95; - static final int ao_telemetry_0_8_len = 94; - - static final int[] ao_telemetry_len = { - 0, 32, 95, 94 - }; - - static HashMap string_to_state = new HashMap(); - - static boolean map_initialized = false; - static final int tab_elt_pad = 5; static Font label_font; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 54cdcba7..3abdb645 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -264,7 +264,6 @@ public class AltosSerial extends AltosLink implements Runnable { flush_output(); } -<<<<<<< HEAD private int telemetry_len() { return Altos.telemetry_len(telemetry); } @@ -386,8 +385,6 @@ public class AltosSerial extends AltosLink implements Runnable { remote = false; } -======= ->>>>>>> bc5e669... altosui: Pull most of AltosSerial into AltosLink public void set_frame(Frame in_frame) { frame = in_frame; } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 0a6ae59e..9fc7b5b3 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -27,8 +27,6 @@ altosui_JAVA = \ AltosConfigureUI.java \ AltosConfigTD.java \ AltosConfigTDUI.java \ - AltosConvert.java \ - AltosCRCException.java \ AltosCSV.java \ AltosCSVUI.java \ AltosDebug.java \ @@ -42,7 +40,6 @@ altosui_JAVA = \ AltosEepromList.java \ AltosEepromManage.java \ AltosEepromMonitor.java \ - AltosEepromTeleScience.java \ AltosEepromMega.java \ AltosEepromMegaIterable.java \ AltosEepromSelect.java \ -- cgit v1.2.3 From 7a19d6790a9800f925c8de24aac71796351e2c04 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Jun 2012 19:28:58 -0700 Subject: altos: More cleanups for moving files to altoslib Signed-off-by: Keith Packard --- altoslib/AltosEepromMega.java | 213 ++++++++++++++ altoslib/AltosEepromMegaIterable.java | 518 +++++++++++++++++++++++++++++++++ altoslib/AltosLink.java | 25 ++ altoslib/Makefile.am | 2 + altosui/Altos.java | 56 ---- altosui/AltosConfigTD.java | 2 + altosui/AltosConfigTDUI.java | 2 + altosui/AltosEepromMega.java | 218 -------------- altosui/AltosEepromMegaIterable.java | 523 ---------------------------------- altosui/AltosFlightStatusUpdate.java | 1 + altosui/AltosSerial.java | 68 ----- altosui/Makefile.am | 2 - 12 files changed, 763 insertions(+), 867 deletions(-) create mode 100644 altoslib/AltosEepromMega.java create mode 100644 altoslib/AltosEepromMegaIterable.java delete mode 100644 altosui/AltosEepromMega.java delete mode 100644 altosui/AltosEepromMegaIterable.java (limited to 'altosui') diff --git a/altoslib/AltosEepromMega.java b/altoslib/AltosEepromMega.java new file mode 100644 index 00000000..2628279e --- /dev/null +++ b/altoslib/AltosEepromMega.java @@ -0,0 +1,213 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public class AltosEepromMega { + public int cmd; + public int tick; + public boolean valid; + public String data; + public int a, b; + + public int data8[]; + + public static final int record_length = 32; + static final int header_length = 4; + static final int data_length = record_length - header_length; + + public int data8(int i) { + return data8[i]; + } + + public int data16(int i) { + return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16; + } + + public int data32(int i) { + return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24); + } + + /* AO_LOG_FLIGHT elements */ + public int flight() { return data16(0); } + public int ground_accel() { return data16(2); } + public int ground_pres() { return data32(4); } + public int ground_temp() { return data32(8); } + + /* AO_LOG_STATE elements */ + public int state() { return data16(0); } + public int reason() { return data16(2); } + + /* AO_LOG_SENSOR elements */ + public int pres() { return data32(0); } + public int temp() { return data32(4); } + public int accel_x() { return data16(8); } + public int accel_y() { return data16(10); } + public int accel_z() { return data16(12); } + public int gyro_x() { return data16(14); } + public int gyro_y() { return data16(16); } + public int gyro_z() { return data16(18); } + public int mag_x() { return data16(20); } + public int mag_y() { return data16(22); } + public int mag_z() { return data16(24); } + public int accel() { + int a = data16(26); + if (a != 0xffff) + return a; + return accel_y(); + } + + /* AO_LOG_VOLT elements */ + public int v_batt() { return data16(0); } + public int v_pbatt() { return data16(2); } + public int nsense() { return data16(4); } + public int sense(int i) { return data16(6 + i * 2); } + + public AltosEepromMega (AltosEepromChunk chunk, int start) throws ParseException { + cmd = chunk.data(start); + + valid = !chunk.erased(start, record_length); + if (valid) { + if (AltosConvert.checksum(chunk.data, start, record_length) != 0) + throw new ParseException(String.format("invalid checksum at 0x%x", + chunk.address + start), 0); + } else { + cmd = AltosLib.AO_LOG_INVALID; + } + + tick = chunk.data16(start+2); + + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = chunk.data(start + header_length + i); + } + + public AltosEepromMega (String line) { + valid = false; + tick = 0; + + if (line == null) { + cmd = AltosLib.AO_LOG_INVALID; + line = ""; + } else { + try { + String[] tokens = line.split("\\s+"); + + if (tokens[0].length() == 1) { + if (tokens.length != 2 + data_length) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } else { + cmd = tokens[0].codePointAt(0); + tick = Integer.parseInt(tokens[1],16); + valid = true; + data8 = new int[data_length]; + for (int i = 0; i < data_length; i++) + data8[i] = Integer.parseInt(tokens[2 + i],16); + } + } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { + cmd = AltosLib.AO_LOG_CONFIG_VERSION; + data = tokens[2]; + } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { + cmd = AltosLib.AO_LOG_MAIN_DEPLOY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { + cmd = AltosLib.AO_LOG_APOGEE_DELAY; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { + cmd = AltosLib.AO_LOG_RADIO_CHANNEL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Callsign:")) { + cmd = AltosLib.AO_LOG_CALLSIGN; + data = tokens[1].replaceAll("\"",""); + } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { + cmd = AltosLib.AO_LOG_ACCEL_CAL; + a = Integer.parseInt(tokens[3]); + b = Integer.parseInt(tokens[5]); + } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { + cmd = AltosLib.AO_LOG_RADIO_CAL; + a = Integer.parseInt(tokens[2]); + } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { + cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG; + a = Integer.parseInt(tokens[3]); + } else if (tokens[0].equals("manufacturer")) { + cmd = AltosLib.AO_LOG_MANUFACTURER; + data = tokens[1]; + } else if (tokens[0].equals("product")) { + cmd = AltosLib.AO_LOG_PRODUCT; + data = tokens[1]; + } else if (tokens[0].equals("serial-number")) { + cmd = AltosLib.AO_LOG_SERIAL_NUMBER; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("log-format")) { + cmd = AltosLib.AO_LOG_LOG_FORMAT; + a = Integer.parseInt(tokens[1]); + } else if (tokens[0].equals("software-version")) { + cmd = AltosLib.AO_LOG_SOFTWARE_VERSION; + data = tokens[1]; + } else if (tokens[0].equals("ms5607")) { + if (tokens[1].equals("reserved:")) { + cmd = AltosLib.AO_LOG_BARO_RESERVED; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("sens:")) { + cmd = AltosLib.AO_LOG_BARO_SENS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("off:")) { + cmd = AltosLib.AO_LOG_BARO_OFF; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tcs:")) { + cmd = AltosLib.AO_LOG_BARO_TCS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tco:")) { + cmd = AltosLib.AO_LOG_BARO_TCO; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tref:")) { + cmd = AltosLib.AO_LOG_BARO_TREF; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("tempsens:")) { + cmd = AltosLib.AO_LOG_BARO_TEMPSENS; + a = Integer.parseInt(tokens[2]); + } else if (tokens[1].equals("crc:")) { + cmd = AltosLib.AO_LOG_BARO_CRC; + a = Integer.parseInt(tokens[2]); + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } else { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } catch (NumberFormatException ne) { + cmd = AltosLib.AO_LOG_INVALID; + data = line; + } + } + } + + public AltosEepromMega(int in_cmd, int in_tick) { + cmd = in_cmd; + tick = in_tick; + valid = true; + } +} diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java new file mode 100644 index 00000000..28a298b3 --- /dev/null +++ b/altoslib/AltosEepromMegaIterable.java @@ -0,0 +1,518 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +/* + * AltosRecords with an index field so they can be sorted by tick while preserving + * the original ordering for elements with matching ticks + */ +class AltosOrderedMegaRecord extends AltosEepromMega implements Comparable { + + public int index; + + public AltosOrderedMegaRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) + throws ParseException { + super(line); + if (prev_tick_valid) { + tick |= (prev_tick & ~0xffff); + if (tick < prev_tick) { + if (prev_tick - tick > 0x8000) + tick += 0x10000; + } else { + if (tick - prev_tick > 0x8000) + tick -= 0x10000; + } + } + index = in_index; + } + + public AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { + super(in_cmd, in_tick); + a = in_a; + b = in_b; + index = in_index; + } + + public String toString() { + return String.format("%d.%d %04x %04x %04x", + cmd, index, tick, a, b); + } + + public int compareTo(AltosOrderedMegaRecord o) { + int tick_diff = tick - o.tick; + if (tick_diff != 0) + return tick_diff; + return index - o.index; + } +} + +public class AltosEepromMegaIterable extends AltosRecordIterable { + + static final int seen_flight = 1; + static final int seen_sensor = 2; + static final int seen_temp_volt = 4; + static final int seen_deploy = 8; + static final int seen_gps_time = 16; + static final int seen_gps_lat = 32; + static final int seen_gps_lon = 64; + + static final int seen_basic = seen_flight|seen_sensor; + + boolean has_accel; + boolean has_gps; + boolean has_ignite; + + AltosEepromMega flight_record; + AltosEepromMega gps_date_record; + + TreeSet records; + + AltosMs5607 baro; + + LinkedList list; + + class EepromState { + int seen; + int n_pad_samples; + double ground_pres; + int gps_tick; + int boost_tick; + int sensor_tick; + + EepromState() { + seen = 0; + n_pad_samples = 0; + ground_pres = 0.0; + gps_tick = 0; + } + } + + void update_state(AltosRecord state, AltosEepromMega record, EepromState eeprom) { + state.tick = record.tick; + switch (record.cmd) { + case AltosLib.AO_LOG_FLIGHT: + eeprom.seen |= seen_flight; + state.ground_accel = record.ground_accel(); + state.flight_accel = record.ground_accel(); + state.ground_pres = baro.set(record.ground_pres(), record.ground_temp()); + state.flight_pres = state.ground_pres; + state.flight = record.data16(0); + eeprom.boost_tick = record.tick; + break; + case AltosLib.AO_LOG_SENSOR: + state.accel = record.accel(); + state.pres = baro.set(record.pres(), record.temp()); + state.temp = baro.cc; + state.imu = new AltosIMU(); + state.imu.accel_x = record.accel_x(); + state.imu.accel_y = record.accel_y(); + state.imu.accel_z = record.accel_z(); + state.imu.gyro_x = record.gyro_x(); + state.imu.gyro_y = record.gyro_y(); + state.imu.gyro_z = record.gyro_z(); + state.mag = new AltosMag(); + state.mag.x = record.mag_x(); + state.mag.y = record.mag_y(); + state.mag.z = record.mag_z(); + if (state.state < AltosLib.ao_flight_boost) { + eeprom.n_pad_samples++; + eeprom.ground_pres += state.pres; + state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); + state.flight_pres = state.ground_pres; + } else { + state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; + } + state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; + if ((eeprom.seen & seen_sensor) == 0) + eeprom.sensor_tick = record.tick - 1; + state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick); + eeprom.seen |= seen_sensor; + eeprom.sensor_tick = record.tick; + has_accel = true; + break; + case AltosLib.AO_LOG_PRESSURE: + state.pres = record.b; + state.flight_pres = state.pres; + if (eeprom.n_pad_samples == 0) { + eeprom.n_pad_samples++; + state.ground_pres = state.pres; + } + eeprom.seen |= seen_sensor; + break; + case AltosLib.AO_LOG_TEMP_VOLT: + state.batt = record.v_batt(); + eeprom.seen |= seen_temp_volt; + break; + case AltosLib.AO_LOG_DEPLOY: + state.drogue = record.a; + state.main = record.b; + eeprom.seen |= seen_deploy; + has_ignite = true; + break; + case AltosLib.AO_LOG_STATE: + state.state = record.state(); + break; + case AltosLib.AO_LOG_GPS_TIME: + eeprom.gps_tick = state.tick; + AltosGPS old = state.gps; + state.gps = new AltosGPS(); + + /* GPS date doesn't get repeated through the file */ + if (old != null) { + state.gps.year = old.year; + state.gps.month = old.month; + state.gps.day = old.day; + } + state.gps.hour = (record.a & 0xff); + state.gps.minute = (record.a >> 8); + state.gps.second = (record.b & 0xff); + + int flags = (record.b >> 8); + state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0; + state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0; + state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> + AltosLib.AO_GPS_NUM_SAT_SHIFT; + state.new_gps = true; + has_gps = true; + break; + case AltosLib.AO_LOG_GPS_LAT: + int lat32 = record.a | (record.b << 16); + state.gps.lat = (double) lat32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_LON: + int lon32 = record.a | (record.b << 16); + state.gps.lon = (double) lon32 / 1e7; + break; + case AltosLib.AO_LOG_GPS_ALT: + state.gps.alt = record.a; + break; + case AltosLib.AO_LOG_GPS_SAT: + if (state.tick == eeprom.gps_tick) { + int svid = record.a; + int c_n0 = record.b >> 8; + state.gps.add_sat(svid, c_n0); + } + break; + case AltosLib.AO_LOG_GPS_DATE: + state.gps.year = (record.a & 0xff) + 2000; + state.gps.month = record.a >> 8; + state.gps.day = record.b & 0xff; + break; + + case AltosLib.AO_LOG_CONFIG_VERSION: + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + break; + case AltosLib.AO_LOG_CALLSIGN: + state.callsign = record.data; + break; + case AltosLib.AO_LOG_ACCEL_CAL: + state.accel_plus_g = record.a; + state.accel_minus_g = record.b; + break; + case AltosLib.AO_LOG_RADIO_CAL: + break; + case AltosLib.AO_LOG_MANUFACTURER: + break; + case AltosLib.AO_LOG_PRODUCT: + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + state.serial = record.a; + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + break; + case AltosLib.AO_LOG_BARO_RESERVED: + baro.reserved = record.a; + break; + case AltosLib.AO_LOG_BARO_SENS: + baro.sens =record.a; + break; + case AltosLib.AO_LOG_BARO_OFF: + baro.off =record.a; + break; + case AltosLib.AO_LOG_BARO_TCS: + baro.tcs =record.a; + break; + case AltosLib.AO_LOG_BARO_TCO: + baro.tco =record.a; + break; + case AltosLib.AO_LOG_BARO_TREF: + baro.tref =record.a; + break; + case AltosLib.AO_LOG_BARO_TEMPSENS: + baro.tempsens =record.a; + break; + case AltosLib.AO_LOG_BARO_CRC: + baro.crc =record.a; + break; + } + state.seen |= eeprom.seen; + } + + LinkedList make_list() { + LinkedList list = new LinkedList(); + Iterator iterator = records.iterator(); + AltosOrderedMegaRecord record = null; + AltosRecord state = new AltosRecord(); + boolean last_reported = false; + EepromState eeprom = new EepromState(); + + state.state = AltosLib.ao_flight_pad; + state.accel_plus_g = 15758; + state.accel_minus_g = 16294; + + /* Pull in static data from the flight and gps_date records */ + if (flight_record != null) + update_state(state, flight_record, eeprom); + if (gps_date_record != null) + update_state(state, gps_date_record, eeprom); + + while (iterator.hasNext()) { + record = iterator.next(); + if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + } + update_state(state, record, eeprom); + } + AltosRecord r = new AltosRecord(state); + r.time = (r.tick - eeprom.boost_tick) / 100.0; + list.add(r); + return list; + } + + public Iterator iterator() { + if (list == null) + list = make_list(); + return list.iterator(); + } + + public boolean has_gps() { return has_gps; } + public boolean has_accel() { return has_accel; } + public boolean has_ignite() { return has_ignite; } + + public void write_comments(PrintStream out) { + Iterator iterator = records.iterator(); + out.printf("# Comments\n"); + while (iterator.hasNext()) { + AltosOrderedMegaRecord record = iterator.next(); + switch (record.cmd) { + case AltosLib.AO_LOG_CONFIG_VERSION: + out.printf("# Config version: %s\n", record.data); + break; + case AltosLib.AO_LOG_MAIN_DEPLOY: + out.printf("# Main deploy: %s\n", record.a); + break; + case AltosLib.AO_LOG_APOGEE_DELAY: + out.printf("# Apogee delay: %s\n", record.a); + break; + case AltosLib.AO_LOG_RADIO_CHANNEL: + out.printf("# Radio channel: %s\n", record.a); + break; + case AltosLib.AO_LOG_CALLSIGN: + out.printf("# Callsign: %s\n", record.data); + break; + case AltosLib.AO_LOG_ACCEL_CAL: + out.printf ("# Accel cal: %d %d\n", record.a, record.b); + break; + case AltosLib.AO_LOG_RADIO_CAL: + out.printf ("# Radio cal: %d\n", record.a); + break; + case AltosLib.AO_LOG_MAX_FLIGHT_LOG: + out.printf ("# Max flight log: %d\n", record.a); + break; + case AltosLib.AO_LOG_MANUFACTURER: + out.printf ("# Manufacturer: %s\n", record.data); + break; + case AltosLib.AO_LOG_PRODUCT: + out.printf ("# Product: %s\n", record.data); + break; + case AltosLib.AO_LOG_SERIAL_NUMBER: + out.printf ("# Serial number: %d\n", record.a); + break; + case AltosLib.AO_LOG_SOFTWARE_VERSION: + out.printf ("# Software version: %s\n", record.data); + break; + case AltosLib.AO_LOG_BARO_RESERVED: + out.printf ("# Baro reserved: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_SENS: + out.printf ("# Baro sens: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_OFF: + out.printf ("# Baro off: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_TCS: + out.printf ("# Baro tcs: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_TCO: + out.printf ("# Baro tco: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_TREF: + out.printf ("# Baro tref: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_TEMPSENS: + out.printf ("# Baro tempsens: %d\n", record.a); + break; + case AltosLib.AO_LOG_BARO_CRC: + out.printf ("# Baro crc: %d\n", record.a); + break; + } + } + } + + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedMegaRecord good, AltosOrderedMegaRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + /* Make sure this looks like a good GPS value */ + if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) + flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); + flags |= AltosLib.AO_GPS_RUNNING; + flags |= AltosLib.AO_GPS_VALID; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + + /* + * Read the whole file, dumping records into a RB tree so + * we can enumerate them in time order -- the eeprom data + * are sometimes out of order with GPS data getting timestamps + * matching the first packet out of the GPS unit but not + * written until the final GPS packet has been received. + */ + public AltosEepromMegaIterable (FileInputStream input) { + records = new TreeSet(); + + AltosOrderedMegaRecord last_gps_time = null; + + baro = new AltosMs5607(); + + int index = 0; + int prev_tick = 0; + boolean prev_tick_valid = false; + boolean missing_time = false; + + try { + for (;;) { + String line = AltosRecord.gets(input); + if (line == null) + break; + AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid); + if (record == null) + break; + if (record.cmd == AltosLib.AO_LOG_INVALID) + continue; + prev_tick = record.tick; + if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) + prev_tick_valid = true; + if (record.cmd == AltosLib.AO_LOG_FLIGHT) { + flight_record = record; + continue; + } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { + gps_date_record = record; + continue; + } + + /* go back and fix up any missing time values */ + if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedMegaRecord old = iterator.next(); + if (old.cmd == AltosLib.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedMegaRecord add_gps_time = new AltosOrderedMegaRecord(AltosLib.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else + missing_time = true; + + records.add(add_gps_time); + record.index = index++; + } + } + records.add(record); + + /* Bail after reading the 'landed' record; we're all done */ + if (record.cmd == AltosLib.AO_LOG_STATE && + record.a == AltosLib.ao_flight_landed) + break; + } + } catch (IOException io) { + } catch (ParseException pe) { + } + try { + input.close(); + } catch (IOException ie) { + } + } +} diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 9b80e916..77b400fc 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -141,6 +141,31 @@ public abstract class AltosLink { return AltosLib.telemetry_len(telemetry); } + private void set_radio_freq(int frequency) { + if (monitor_mode) + printf("m 0\nc F %d\nm %x\n", + frequency, telemetry_len()); + else + printf("c F %d\n", frequency); + flush_output(); + } + + public void set_radio_frequency(double frequency, + boolean has_frequency, + boolean has_setting, + int cal) { + if (debug) + System.out.printf("set_radio_frequency %7.3f (freq %b) (set %b) %d\n", frequency, has_frequency, has_setting, cal); + if (frequency == 0) + return; + if (has_frequency) + set_radio_freq((int) Math.floor (frequency * 1000)); + else if (has_setting) + set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); + else + set_channel(AltosConvert.radio_frequency_to_channel(frequency)); + } + public void set_telemetry(int in_telemetry) { telemetry = in_telemetry; if (monitor_mode) diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 2e4a795a..f644d46a 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -17,6 +17,8 @@ AltosLib_JAVA = \ $(SRC)/AltosEepromChunk.java \ $(SRC)/AltosEepromIterable.java \ $(SRC)/AltosEepromLog.java \ + $(SRC)/AltosEepromMega.java \ + $(SRC)/AltosEepromMegaIterable.java \ $(SRC)/AltosEepromRecord.java \ $(SRC)/AltosEepromTeleScience.java \ $(SRC)/AltosFile.java \ diff --git a/altosui/Altos.java b/altosui/Altos.java index 334ddb07..351927ee 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -72,62 +72,6 @@ public class Altos extends AltosLib { static final int text_width = 20; - static void initialize_map() - { - string_to_state.put("startup", ao_flight_startup); - string_to_state.put("idle", ao_flight_idle); - string_to_state.put("pad", ao_flight_pad); - string_to_state.put("boost", ao_flight_boost); - string_to_state.put("fast", ao_flight_fast); - string_to_state.put("coast", ao_flight_coast); - string_to_state.put("drogue", ao_flight_drogue); - string_to_state.put("apogee", ao_flight_coast); - string_to_state.put("main", ao_flight_main); - string_to_state.put("landed", ao_flight_landed); - string_to_state.put("invalid", ao_flight_invalid); - map_initialized = true; - } - - static int telemetry_len(int telemetry) { - if (telemetry <= ao_telemetry_max) - return ao_telemetry_len[telemetry]; - throw new IllegalArgumentException(String.format("Invalid telemetry %d", - telemetry)); - } - - static String telemetry_name(int telemetry) { - if (telemetry <= ao_telemetry_max) - return ao_telemetry_name[telemetry]; - throw new IllegalArgumentException(String.format("Invalid telemetry %d", - telemetry)); - } - - static String[] state_to_string = { - "startup", - "idle", - "pad", - "boost", - "fast", - "coast", - "drogue", - "main", - "landed", - "invalid", - }; - - static String[] state_to_string_capital = { - "Startup", - "Idle", - "Pad", - "Boost", - "Fast", - "Coast", - "Drogue", - "Main", - "Landed", - "Invalid", - }; - static public int state(String state) { if (!map_initialized) initialize_map(); diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java index d3c452e1..4048166c 100644 --- a/altosui/AltosConfigTD.java +++ b/altosui/AltosConfigTD.java @@ -30,6 +30,8 @@ import java.util.concurrent.*; import libaltosJNI.*; +import org.altusmetrum.AltosLib.*; + public class AltosConfigTD implements ActionListener { class int_ref { diff --git a/altosui/AltosConfigTDUI.java b/altosui/AltosConfigTDUI.java index 9f6badc7..f2058f69 100644 --- a/altosui/AltosConfigTDUI.java +++ b/altosui/AltosConfigTDUI.java @@ -31,6 +31,8 @@ import java.util.concurrent.LinkedBlockingQueue; import libaltosJNI.*; +import org.altusmetrum.AltosLib.*; + public class AltosConfigTDUI extends AltosDialog implements ActionListener, ItemListener, DocumentListener diff --git a/altosui/AltosEepromMega.java b/altosui/AltosEepromMega.java deleted file mode 100644 index 8ae485cb..00000000 --- a/altosui/AltosEepromMega.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -public class AltosEepromMega { - public int cmd; - public int tick; - public boolean valid; - public String data; - int a, b; - - public int data8[]; - - static final int record_length = 32; - static final int header_length = 4; - static final int data_length = record_length - header_length; - - public int data8(int i) { - return data8[i]; - } - - public int data16(int i) { - return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16; - } - - public int data32(int i) { - return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24); - } - - /* AO_LOG_FLIGHT elements */ - public int flight() { return data16(0); } - public int ground_accel() { return data16(2); } - public int ground_pres() { return data32(4); } - public int ground_temp() { return data32(8); } - - /* AO_LOG_STATE elements */ - public int state() { return data16(0); } - public int reason() { return data16(2); } - - /* AO_LOG_SENSOR elements */ - public int pres() { return data32(0); } - public int temp() { return data32(4); } - public int accel_x() { return data16(8); } - public int accel_y() { return data16(10); } - public int accel_z() { return data16(12); } - public int gyro_x() { return data16(14); } - public int gyro_y() { return data16(16); } - public int gyro_z() { return data16(18); } - public int mag_x() { return data16(20); } - public int mag_y() { return data16(22); } - public int mag_z() { return data16(24); } - public int accel() { - int a = data16(26); - if (a != 0xffff) - return a; - return accel_y(); - } - - /* AO_LOG_VOLT elements */ - public int v_batt() { return data16(0); } - public int v_pbatt() { return data16(2); } - public int nsense() { return data16(4); } - public int sense(int i) { return data16(6 + i * 2); } - - public AltosEepromMega (AltosEepromChunk chunk, int start) throws ParseException { - cmd = chunk.data(start); - - valid = !chunk.erased(start, record_length); - if (valid) { - if (AltosConvert.checksum(chunk.data, start, record_length) != 0) - throw new ParseException(String.format("invalid checksum at 0x%x", - chunk.address + start), 0); - } else { - cmd = Altos.AO_LOG_INVALID; - } - - tick = chunk.data16(start+2); - - data8 = new int[data_length]; - for (int i = 0; i < data_length; i++) - data8[i] = chunk.data(start + header_length + i); - } - - public AltosEepromMega (String line) { - valid = false; - tick = 0; - - if (line == null) { - cmd = Altos.AO_LOG_INVALID; - line = ""; - } else { - try { - String[] tokens = line.split("\\s+"); - - if (tokens[0].length() == 1) { - if (tokens.length != 2 + data_length) { - cmd = Altos.AO_LOG_INVALID; - data = line; - } else { - cmd = tokens[0].codePointAt(0); - tick = Integer.parseInt(tokens[1],16); - valid = true; - data8 = new int[data_length]; - for (int i = 0; i < data_length; i++) - data8[i] = Integer.parseInt(tokens[2 + i],16); - } - } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { - cmd = Altos.AO_LOG_CONFIG_VERSION; - data = tokens[2]; - } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { - cmd = Altos.AO_LOG_MAIN_DEPLOY; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { - cmd = Altos.AO_LOG_APOGEE_DELAY; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { - cmd = Altos.AO_LOG_RADIO_CHANNEL; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Callsign:")) { - cmd = Altos.AO_LOG_CALLSIGN; - data = tokens[1].replaceAll("\"",""); - } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { - cmd = Altos.AO_LOG_ACCEL_CAL; - a = Integer.parseInt(tokens[3]); - b = Integer.parseInt(tokens[5]); - } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { - cmd = Altos.AO_LOG_RADIO_CAL; - a = Integer.parseInt(tokens[2]); - } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { - cmd = Altos.AO_LOG_MAX_FLIGHT_LOG; - a = Integer.parseInt(tokens[3]); - } else if (tokens[0].equals("manufacturer")) { - cmd = Altos.AO_LOG_MANUFACTURER; - data = tokens[1]; - } else if (tokens[0].equals("product")) { - cmd = Altos.AO_LOG_PRODUCT; - data = tokens[1]; - } else if (tokens[0].equals("serial-number")) { - cmd = Altos.AO_LOG_SERIAL_NUMBER; - a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("log-format")) { - cmd = Altos.AO_LOG_LOG_FORMAT; - a = Integer.parseInt(tokens[1]); - } else if (tokens[0].equals("software-version")) { - cmd = Altos.AO_LOG_SOFTWARE_VERSION; - data = tokens[1]; - } else if (tokens[0].equals("ms5607")) { - if (tokens[1].equals("reserved:")) { - cmd = Altos.AO_LOG_BARO_RESERVED; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("sens:")) { - cmd = Altos.AO_LOG_BARO_SENS; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("off:")) { - cmd = Altos.AO_LOG_BARO_OFF; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tcs:")) { - cmd = Altos.AO_LOG_BARO_TCS; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tco:")) { - cmd = Altos.AO_LOG_BARO_TCO; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tref:")) { - cmd = Altos.AO_LOG_BARO_TREF; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("tempsens:")) { - cmd = Altos.AO_LOG_BARO_TEMPSENS; - a = Integer.parseInt(tokens[2]); - } else if (tokens[1].equals("crc:")) { - cmd = Altos.AO_LOG_BARO_CRC; - a = Integer.parseInt(tokens[2]); - } else { - cmd = Altos.AO_LOG_INVALID; - data = line; - } - } else { - cmd = Altos.AO_LOG_INVALID; - data = line; - } - } catch (NumberFormatException ne) { - cmd = Altos.AO_LOG_INVALID; - data = line; - } - } - } - - public AltosEepromMega(int in_cmd, int in_tick) { - cmd = in_cmd; - tick = in_tick; - valid = true; - } -} diff --git a/altosui/AltosEepromMegaIterable.java b/altosui/AltosEepromMegaIterable.java deleted file mode 100644 index e2cd2785..00000000 --- a/altosui/AltosEepromMegaIterable.java +++ /dev/null @@ -1,523 +0,0 @@ -/* - * 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 altosui; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import java.io.*; -import java.util.*; -import java.text.*; -import java.util.prefs.*; -import java.util.concurrent.LinkedBlockingQueue; - -/* - * AltosRecords with an index field so they can be sorted by tick while preserving - * the original ordering for elements with matching ticks - */ -class AltosOrderedMegaRecord extends AltosEepromMega implements Comparable { - - public int index; - - public AltosOrderedMegaRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) - throws ParseException { - super(line); - if (prev_tick_valid) { - tick |= (prev_tick & ~0xffff); - if (tick < prev_tick) { - if (prev_tick - tick > 0x8000) - tick += 0x10000; - } else { - if (tick - prev_tick > 0x8000) - tick -= 0x10000; - } - } - index = in_index; - } - - public AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { - super(in_cmd, in_tick); - a = in_a; - b = in_b; - index = in_index; - } - - public String toString() { - return String.format("%d.%d %04x %04x %04x", - cmd, index, tick, a, b); - } - - public int compareTo(AltosOrderedMegaRecord o) { - int tick_diff = tick - o.tick; - if (tick_diff != 0) - return tick_diff; - return index - o.index; - } -} - -public class AltosEepromMegaIterable extends AltosRecordIterable { - - static final int seen_flight = 1; - static final int seen_sensor = 2; - static final int seen_temp_volt = 4; - static final int seen_deploy = 8; - static final int seen_gps_time = 16; - static final int seen_gps_lat = 32; - static final int seen_gps_lon = 64; - - static final int seen_basic = seen_flight|seen_sensor; - - boolean has_accel; - boolean has_gps; - boolean has_ignite; - - AltosEepromMega flight_record; - AltosEepromMega gps_date_record; - - TreeSet records; - - AltosMs5607 baro; - - LinkedList list; - - class EepromState { - int seen; - int n_pad_samples; - double ground_pres; - int gps_tick; - int boost_tick; - int sensor_tick; - - EepromState() { - seen = 0; - n_pad_samples = 0; - ground_pres = 0.0; - gps_tick = 0; - } - } - - void update_state(AltosRecord state, AltosEepromMega record, EepromState eeprom) { - state.tick = record.tick; - switch (record.cmd) { - case Altos.AO_LOG_FLIGHT: - eeprom.seen |= seen_flight; - state.ground_accel = record.ground_accel(); - state.flight_accel = record.ground_accel(); - state.ground_pres = baro.set(record.ground_pres(), record.ground_temp()); - state.flight_pres = state.ground_pres; - state.flight = record.data16(0); - eeprom.boost_tick = record.tick; - break; - case Altos.AO_LOG_SENSOR: - state.accel = record.accel(); - state.pres = baro.set(record.pres(), record.temp()); - state.temp = baro.cc; - state.imu = new AltosIMU(); - state.imu.accel_x = record.accel_x(); - state.imu.accel_y = record.accel_y(); - state.imu.accel_z = record.accel_z(); - state.imu.gyro_x = record.gyro_x(); - state.imu.gyro_y = record.gyro_y(); - state.imu.gyro_z = record.gyro_z(); - state.mag = new AltosMag(); - state.mag.x = record.mag_x(); - state.mag.y = record.mag_y(); - state.mag.z = record.mag_z(); - if (state.state < Altos.ao_flight_boost) { - eeprom.n_pad_samples++; - eeprom.ground_pres += state.pres; - state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); - state.flight_pres = state.ground_pres; - } else { - state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; - } - state.flight_accel = (state.flight_accel * 15 + state.accel) / 16; - if ((eeprom.seen & seen_sensor) == 0) - eeprom.sensor_tick = record.tick - 1; - state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick); - eeprom.seen |= seen_sensor; - eeprom.sensor_tick = record.tick; - has_accel = true; - break; - case Altos.AO_LOG_PRESSURE: - state.pres = record.b; - state.flight_pres = state.pres; - if (eeprom.n_pad_samples == 0) { - eeprom.n_pad_samples++; - state.ground_pres = state.pres; - } - eeprom.seen |= seen_sensor; - break; - case Altos.AO_LOG_TEMP_VOLT: - state.batt = record.v_batt(); - eeprom.seen |= seen_temp_volt; - break; - case Altos.AO_LOG_DEPLOY: - state.drogue = record.a; - state.main = record.b; - eeprom.seen |= seen_deploy; - has_ignite = true; - break; - case Altos.AO_LOG_STATE: - state.state = record.state(); - break; - case Altos.AO_LOG_GPS_TIME: - eeprom.gps_tick = state.tick; - AltosGPS old = state.gps; - state.gps = new AltosGPS(); - - /* GPS date doesn't get repeated through the file */ - if (old != null) { - state.gps.year = old.year; - state.gps.month = old.month; - state.gps.day = old.day; - } - state.gps.hour = (record.a & 0xff); - state.gps.minute = (record.a >> 8); - state.gps.second = (record.b & 0xff); - - int flags = (record.b >> 8); - state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0; - state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0; - state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >> - Altos.AO_GPS_NUM_SAT_SHIFT; - state.new_gps = true; - has_gps = true; - break; - case Altos.AO_LOG_GPS_LAT: - int lat32 = record.a | (record.b << 16); - state.gps.lat = (double) lat32 / 1e7; - break; - case Altos.AO_LOG_GPS_LON: - int lon32 = record.a | (record.b << 16); - state.gps.lon = (double) lon32 / 1e7; - break; - case Altos.AO_LOG_GPS_ALT: - state.gps.alt = record.a; - break; - case Altos.AO_LOG_GPS_SAT: - if (state.tick == eeprom.gps_tick) { - int svid = record.a; - int c_n0 = record.b >> 8; - state.gps.add_sat(svid, c_n0); - } - break; - case Altos.AO_LOG_GPS_DATE: - state.gps.year = (record.a & 0xff) + 2000; - state.gps.month = record.a >> 8; - state.gps.day = record.b & 0xff; - break; - - case Altos.AO_LOG_CONFIG_VERSION: - break; - case Altos.AO_LOG_MAIN_DEPLOY: - break; - case Altos.AO_LOG_APOGEE_DELAY: - break; - case Altos.AO_LOG_RADIO_CHANNEL: - break; - case Altos.AO_LOG_CALLSIGN: - state.callsign = record.data; - break; - case Altos.AO_LOG_ACCEL_CAL: - state.accel_plus_g = record.a; - state.accel_minus_g = record.b; - break; - case Altos.AO_LOG_RADIO_CAL: - break; - case Altos.AO_LOG_MANUFACTURER: - break; - case Altos.AO_LOG_PRODUCT: - break; - case Altos.AO_LOG_SERIAL_NUMBER: - state.serial = record.a; - break; - case Altos.AO_LOG_SOFTWARE_VERSION: - break; - case Altos.AO_LOG_BARO_RESERVED: - baro.reserved = record.a; - break; - case Altos.AO_LOG_BARO_SENS: - baro.sens =record.a; - break; - case Altos.AO_LOG_BARO_OFF: - baro.off =record.a; - break; - case Altos.AO_LOG_BARO_TCS: - baro.tcs =record.a; - break; - case Altos.AO_LOG_BARO_TCO: - baro.tco =record.a; - break; - case Altos.AO_LOG_BARO_TREF: - baro.tref =record.a; - break; - case Altos.AO_LOG_BARO_TEMPSENS: - baro.tempsens =record.a; - break; - case Altos.AO_LOG_BARO_CRC: - baro.crc =record.a; - break; - } - state.seen |= eeprom.seen; - } - - LinkedList make_list() { - LinkedList list = new LinkedList(); - Iterator iterator = records.iterator(); - AltosOrderedMegaRecord record = null; - AltosRecord state = new AltosRecord(); - boolean last_reported = false; - EepromState eeprom = new EepromState(); - - state.state = Altos.ao_flight_pad; - state.accel_plus_g = 15758; - state.accel_minus_g = 16294; - - /* Pull in static data from the flight and gps_date records */ - if (flight_record != null) - update_state(state, flight_record, eeprom); - if (gps_date_record != null) - update_state(state, gps_date_record, eeprom); - - while (iterator.hasNext()) { - record = iterator.next(); - if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - } - update_state(state, record, eeprom); - } - AltosRecord r = new AltosRecord(state); - r.time = (r.tick - eeprom.boost_tick) / 100.0; - list.add(r); - return list; - } - - public Iterator iterator() { - if (list == null) - list = make_list(); - return list.iterator(); - } - - public boolean has_gps() { return has_gps; } - public boolean has_accel() { return has_accel; } - public boolean has_ignite() { return has_ignite; } - - public void write_comments(PrintStream out) { - Iterator iterator = records.iterator(); - out.printf("# Comments\n"); - while (iterator.hasNext()) { - AltosOrderedMegaRecord record = iterator.next(); - switch (record.cmd) { - case Altos.AO_LOG_CONFIG_VERSION: - out.printf("# Config version: %s\n", record.data); - break; - case Altos.AO_LOG_MAIN_DEPLOY: - out.printf("# Main deploy: %s\n", record.a); - break; - case Altos.AO_LOG_APOGEE_DELAY: - out.printf("# Apogee delay: %s\n", record.a); - break; - case Altos.AO_LOG_RADIO_CHANNEL: - out.printf("# Radio channel: %s\n", record.a); - break; - case Altos.AO_LOG_CALLSIGN: - out.printf("# Callsign: %s\n", record.data); - break; - case Altos.AO_LOG_ACCEL_CAL: - out.printf ("# Accel cal: %d %d\n", record.a, record.b); - break; - case Altos.AO_LOG_RADIO_CAL: - out.printf ("# Radio cal: %d\n", record.a); - break; - case Altos.AO_LOG_MAX_FLIGHT_LOG: - out.printf ("# Max flight log: %d\n", record.a); - break; - case Altos.AO_LOG_MANUFACTURER: - out.printf ("# Manufacturer: %s\n", record.data); - break; - case Altos.AO_LOG_PRODUCT: - out.printf ("# Product: %s\n", record.data); - break; - case Altos.AO_LOG_SERIAL_NUMBER: - out.printf ("# Serial number: %d\n", record.a); - break; - case Altos.AO_LOG_SOFTWARE_VERSION: - out.printf ("# Software version: %s\n", record.data); - break; - case Altos.AO_LOG_BARO_RESERVED: - out.printf ("# Baro reserved: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_SENS: - out.printf ("# Baro sens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_OFF: - out.printf ("# Baro off: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCS: - out.printf ("# Baro tcs: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TCO: - out.printf ("# Baro tco: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TREF: - out.printf ("# Baro tref: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_TEMPSENS: - out.printf ("# Baro tempsens: %d\n", record.a); - break; - case Altos.AO_LOG_BARO_CRC: - out.printf ("# Baro crc: %d\n", record.a); - break; - } - } - } - - /* - * Given an AO_LOG_GPS_TIME record with correct time, and one - * missing time, rewrite the missing time values with the good - * ones, assuming that the difference between them is 'diff' seconds - */ - void update_time(AltosOrderedMegaRecord good, AltosOrderedMegaRecord bad) { - - int diff = (bad.tick - good.tick + 50) / 100; - - int hour = (good.a & 0xff); - int minute = (good.a >> 8); - int second = (good.b & 0xff); - int flags = (good.b >> 8); - int seconds = hour * 3600 + minute * 60 + second; - - /* Make sure this looks like a good GPS value */ - if ((flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT < 4) - flags = (flags & ~Altos.AO_GPS_NUM_SAT_MASK) | (4 << Altos.AO_GPS_NUM_SAT_SHIFT); - flags |= Altos.AO_GPS_RUNNING; - flags |= Altos.AO_GPS_VALID; - - int new_seconds = seconds + diff; - if (new_seconds < 0) - new_seconds += 24 * 3600; - int new_second = (new_seconds % 60); - int new_minutes = (new_seconds / 60); - int new_minute = (new_minutes % 60); - int new_hours = (new_minutes / 60); - int new_hour = (new_hours % 24); - - bad.a = new_hour + (new_minute << 8); - bad.b = new_second + (flags << 8); - } - - /* - * Read the whole file, dumping records into a RB tree so - * we can enumerate them in time order -- the eeprom data - * are sometimes out of order with GPS data getting timestamps - * matching the first packet out of the GPS unit but not - * written until the final GPS packet has been received. - */ - public AltosEepromMegaIterable (FileInputStream input) { - records = new TreeSet(); - - AltosOrderedMegaRecord last_gps_time = null; - - baro = new AltosMs5607(); - - int index = 0; - int prev_tick = 0; - boolean prev_tick_valid = false; - boolean missing_time = false; - - try { - for (;;) { - String line = AltosRecord.gets(input); - if (line == null) - break; - AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid); - if (record == null) - break; - if (record.cmd == Altos.AO_LOG_INVALID) - continue; - prev_tick = record.tick; - if (record.cmd < Altos.AO_LOG_CONFIG_VERSION) - prev_tick_valid = true; - if (record.cmd == Altos.AO_LOG_FLIGHT) { - flight_record = record; - continue; - } - - /* Two firmware bugs caused the loss of some GPS data. - * The flight date would never be recorded, and often - * the flight time would get overwritten by another - * record. Detect the loss of the GPS date and fix up the - * missing time records - */ - if (record.cmd == Altos.AO_LOG_GPS_DATE) { - gps_date_record = record; - continue; - } - - /* go back and fix up any missing time values */ - if (record.cmd == Altos.AO_LOG_GPS_TIME) { - last_gps_time = record; - if (missing_time) { - Iterator iterator = records.iterator(); - while (iterator.hasNext()) { - AltosOrderedMegaRecord old = iterator.next(); - if (old.cmd == Altos.AO_LOG_GPS_TIME && - old.a == -1 && old.b == -1) - { - update_time(record, old); - } - } - missing_time = false; - } - } - - if (record.cmd == Altos.AO_LOG_GPS_LAT) { - if (last_gps_time == null || last_gps_time.tick != record.tick) { - AltosOrderedMegaRecord add_gps_time = new AltosOrderedMegaRecord(Altos.AO_LOG_GPS_TIME, - record.tick, - -1, -1, index-1); - if (last_gps_time != null) - update_time(last_gps_time, add_gps_time); - else - missing_time = true; - - records.add(add_gps_time); - record.index = index++; - } - } - records.add(record); - - /* Bail after reading the 'landed' record; we're all done */ - if (record.cmd == Altos.AO_LOG_STATE && - record.a == Altos.ao_flight_landed) - break; - } - } catch (IOException io) { - } catch (ParseException pe) { - } - try { - input.close(); - } catch (IOException ie) { - } - } -} diff --git a/altosui/AltosFlightStatusUpdate.java b/altosui/AltosFlightStatusUpdate.java index a600bd02..d70fc7f8 100644 --- a/altosui/AltosFlightStatusUpdate.java +++ b/altosui/AltosFlightStatusUpdate.java @@ -27,6 +27,7 @@ import java.util.*; import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; +import org.altusmetrum.AltosLib.*; public class AltosFlightStatusUpdate implements ActionListener { diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 3abdb645..5768ba71 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -317,74 +317,6 @@ public class AltosSerial extends AltosLink implements Runnable { set_channel(AltosConvert.radio_frequency_to_channel(frequency)); } - public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - if (frequency == 0.0) - frequency = AltosPreferences.frequency(device.getSerial()); - config_data(); - set_radio_frequency(frequency, - config_data.radio_frequency != 0, - config_data.radio_setting != 0, - config_data.radio_calibration); - } - - public void set_telemetry(int in_telemetry) { - telemetry = in_telemetry; - if (altos != null) { - if (monitor_mode) - printf("m 0\nm %x\n", telemetry_len()); - flush_output(); - } - } - - void set_monitor(boolean monitor) { - monitor_mode = monitor; - if (altos != null) { - if (monitor) - printf("m %x\n", telemetry_len()); - else - printf("m 0\n"); - flush_output(); - } - } - - public void set_callsign(String callsign) { - if (altos != null) { - printf ("c c %s\n", callsign); - flush_output(); - } - } - - public AltosConfigData config_data() throws InterruptedException, TimeoutException { - if (config_data == null) - config_data = new AltosConfigData(this); - return config_data; - } - - public void start_remote() throws TimeoutException, InterruptedException { - if (debug) - System.out.printf("start remote %7.3f\n", frequency); - if (frequency == 0.0) - frequency = AltosUIPreferences.frequency(device.getSerial()); - set_radio_frequency(frequency); - set_callsign(AltosUIPreferences.callsign()); - printf("p\nE 0\n"); - flush_input(); - remote = true; - } - - public void stop_remote() throws InterruptedException { - if (debug) - System.out.printf("stop remote\n"); - try { - flush_input(); - } finally { - printf ("~\n"); - flush_output(); - } - remote = false; - } - public void set_frame(Frame in_frame) { frame = in_frame; } diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 9fc7b5b3..feda00c7 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -40,8 +40,6 @@ altosui_JAVA = \ AltosEepromList.java \ AltosEepromManage.java \ AltosEepromMonitor.java \ - AltosEepromMega.java \ - AltosEepromMegaIterable.java \ AltosEepromSelect.java \ AltosFlash.java \ AltosFlashUI.java \ -- cgit v1.2.3 From b8c363d9411fd5e79e3f806894dbc12bcc106b88 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Jun 2012 20:56:25 -0700 Subject: altosui: More changes to migrate code to altoslib Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 1 + altosui/Altos.java | 184 --------------------------------------- altosui/AltosEepromDownload.java | 10 +-- 3 files changed, 6 insertions(+), 189 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 27d72079..e74eaf99 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -185,6 +185,7 @@ public class AltosLib { public static final int AO_LOG_FORMAT_TINY = 2; public static final int AO_LOG_FORMAT_TELEMETRY = 3; public static final int AO_LOG_FORMAT_TELESCIENCE = 4; + public static final int AO_LOG_FORMAT_MEGAMETRUM = 5; public static final int AO_LOG_FORMAT_NONE = 127; public static boolean isspace(int c) { diff --git a/altosui/Altos.java b/altosui/Altos.java index 351927ee..78e56970 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -86,190 +86,6 @@ public class Altos extends AltosLib { return state_to_string[state]; } - static final int AO_GPS_VALID = (1 << 4); - static final int AO_GPS_RUNNING = (1 << 5); - static final int AO_GPS_DATE_VALID = (1 << 6); - static final int AO_GPS_NUM_SAT_SHIFT = 0; - static final int AO_GPS_NUM_SAT_MASK = 0xf; - - static final int AO_LOG_FORMAT_UNKNOWN = 0; - static final int AO_LOG_FORMAT_FULL = 1; - static final int AO_LOG_FORMAT_TINY = 2; - static final int AO_LOG_FORMAT_TELEMETRY = 3; - static final int AO_LOG_FORMAT_TELESCIENCE = 4; - static final int AO_LOG_FORMAT_MEGAMETRUM = 5; - static final int AO_LOG_FORMAT_NONE = 127; - - static boolean isspace(int c) { - switch (c) { - case ' ': - case '\t': - return true; - } - return false; - } - - static boolean ishex(int c) { - if ('0' <= c && c <= '9') - return true; - if ('a' <= c && c <= 'f') - return true; - if ('A' <= c && c <= 'F') - return true; - return false; - } - - static boolean ishex(String s) { - for (int i = 0; i < s.length(); i++) - if (!ishex(s.charAt(i))) - return false; - return true; - } - - static int fromhex(int c) { - 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; - return -1; - } - - static int fromhex(String s) throws NumberFormatException { - int c, v = 0; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - if (!ishex(c)) { - if (i == 0) - throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); - return v; - } - v = v * 16 + fromhex(c); - } - return v; - } - - static boolean isdec(int c) { - if ('0' <= c && c <= '9') - return true; - return false; - } - - static boolean isdec(String s) { - for (int i = 0; i < s.length(); i++) - if (!isdec(s.charAt(i))) - return false; - return true; - } - - static int fromdec(int c) { - if ('0' <= c && c <= '9') - return c - '0'; - return -1; - } - - static int int8(int[] bytes, int i) { - return (int) (byte) bytes[i]; - } - - static int uint8(int[] bytes, int i) { - return bytes[i]; - } - - static int int16(int[] bytes, int i) { - return (int) (short) (bytes[i] + (bytes[i+1] << 8)); - } - - static int uint16(int[] bytes, int i) { - return bytes[i] + (bytes[i+1] << 8); - } - - static int uint32(int[] bytes, int i) { - return bytes[i] + - (bytes[i+1] << 8) + - (bytes[i+2] << 16) + - (bytes[i+3] << 24); - } - - static final Charset unicode_set = Charset.forName("UTF-8"); - - static String string(int[] bytes, int s, int l) { - if (s + l > bytes.length) { - if (s > bytes.length) { - s = bytes.length; - l = 0; - } else { - l = bytes.length - s; - } - } - - int i; - for (i = l - 1; i >= 0; i--) - if (bytes[s+i] != 0) - break; - - l = i + 1; - byte[] b = new byte[l]; - - for (i = 0; i < l; i++) - b[i] = (byte) bytes[s+i]; - String n = new String(b, unicode_set); - return n; - } - - static int hexbyte(String s, int i) { - int c0, c1; - - if (s.length() < i + 2) - throw new NumberFormatException(String.format("invalid hex \"%s\"", s)); - c0 = s.charAt(i); - if (!Altos.ishex(c0)) - throw new NumberFormatException(String.format("invalid hex \"%c\"", c0)); - c1 = s.charAt(i+1); - if (!Altos.ishex(c1)) - throw new NumberFormatException(String.format("invalid hex \"%c\"", c1)); - return Altos.fromhex(c0) * 16 + Altos.fromhex(c1); - } - - static int[] hexbytes(String s) { - int n; - int[] r; - int i; - - if ((s.length() & 1) != 0) - throw new NumberFormatException(String.format("invalid line \"%s\"", s)); - n = s.length() / 2; - r = new int[n]; - for (i = 0; i < n; i++) - r[i] = Altos.hexbyte(s, i * 2); - return r; - } - - static int fromdec(String s) throws NumberFormatException { - int c, v = 0; - int sign = 1; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - if (i == 0 && c == '-') { - sign = -1; - } else if (!isdec(c)) { - if (i == 0) - throw new NumberFormatException(String.format("invalid number \"%s\"", s)); - return v; - } else - v = v * 10 + fromdec(c); - } - return v * sign; - } - - static String replace_extension(String input, String extension) { - int dot = input.lastIndexOf("."); - if (dot > 0) - input = input.substring(0,dot); - return input.concat(extension); - } - static public boolean initialized = false; static public boolean loaded_library = false; diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 080bfc99..d1e5fdf0 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -357,23 +357,23 @@ public class AltosEepromDownload implements Runnable { } switch (log_format) { - case Altos.AO_LOG_FORMAT_FULL: + case AltosLib.AO_LOG_FORMAT_FULL: extension = "eeprom"; CaptureFull(eechunk); break; - case Altos.AO_LOG_FORMAT_TINY: + case AltosLib.AO_LOG_FORMAT_TINY: extension = "eeprom"; CaptureTiny(eechunk); break; - case Altos.AO_LOG_FORMAT_TELEMETRY: + case AltosLib.AO_LOG_FORMAT_TELEMETRY: extension = "telem"; CaptureTelemetry(eechunk); break; - case Altos.AO_LOG_FORMAT_TELESCIENCE: + case AltosLib.AO_LOG_FORMAT_TELESCIENCE: extension = "science"; CaptureTeleScience(eechunk); break; - case Altos.AO_LOG_FORMAT_MEGAMETRUM: + case AltosLib.AO_LOG_FORMAT_MEGAMETRUM: extension = "mega"; CaptureMega(eechunk); } -- cgit v1.2.3 From 55747ce210d7d80d5b4fdaaf9dc7ee0f7bc8b0a3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jun 2012 18:58:56 -0700 Subject: altosui: Move product definitions from AltosUI to AltosLib Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 24 ++++++++++++ altosui/Altos.java | 85 ------------------------------------------ altosui/AltosBTDevice.java | 1 + altosui/AltosBTKnown.java | 10 ++++- altosui/AltosConfig.java | 2 +- altosui/AltosConfigureUI.java | 2 +- altosui/AltosDeviceDialog.java | 4 +- altosui/AltosUI.java | 1 + 8 files changed, 39 insertions(+), 90 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index e74eaf99..4a779c55 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -78,6 +78,30 @@ public class AltosLib { public static final int ao_flight_landed = 8; public static final int ao_flight_invalid = 9; + /* USB product IDs */ + public final static int vendor_altusmetrum = 0xfffe; + + public final static int product_altusmetrum = 0x000a; + public final static int product_telemetrum = 0x000b; + public final static int product_teledongle = 0x000c; + public final static int product_teleterra = 0x000d; + public final static int product_telebt = 0x000e; + public final static int product_telelaunch = 0x000f; + public final static int product_telelco = 0x0010; + public final static int product_telescience = 0x0011; + public final static int product_telepyro =0x0012; + public final static int product_megametrum = 0x0023; + public final static int product_megadongle = 0x0024; + public final static int product_altusmetrum_min = 0x000a; + public final static int product_altusmetrum_max = 0x0024; + + public final static int product_any = 0x10000; + public final static int product_basestation = 0x10000 + 1; + public final static int product_altimeter = 0x10000 + 2; + + /* Bluetooth "identifier" (bluetooth sucks) */ + public final static String bt_product_telebt = "TeleBT"; + /* Telemetry modes */ public static final int ao_telemetry_off = 0; public static final int ao_telemetry_min = 1; diff --git a/altosui/Altos.java b/altosui/Altos.java index 78e56970..e60b3aaa 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -108,89 +108,4 @@ public class Altos extends AltosLib { } return loaded_library; } - - static int usb_vendor_altusmetrum() { - load_library(); - return 0xfffe; - } - - static int usb_product_altusmetrum() { - load_library(); - return 0x000a; - } - - static int usb_product_altusmetrum_min() { - load_library(); - return 0x000a; - } - - static int usb_product_altusmetrum_max() { - load_library(); - return 0x0013; - } - - static int usb_product_telemetrum() { - load_library(); - return 0x000b; - } - - static int usb_product_teledongle() { - load_library(); - return 0x000c; - } - - static int usb_product_teleterra() { - load_library(); - return 0x000d; - } - - static int usb_product_telebt() { - load_library(); - return 0x000e; - } - - static int usb_product_telelaunch() { - load_library(); - return 0x000f; - } - - static int usb_product_telelco() { - load_library(); - return 0x0010; - } - - static int usb_product_telescience() { - load_library(); - return 0x0011; - } - - static int usb_product_telepyro() { - load_library(); - return 0x0012; - } - - public final static int vendor_altusmetrum = usb_vendor_altusmetrum(); - public final static int product_altusmetrum = usb_product_altusmetrum(); - public final static int product_telemetrum = usb_product_telemetrum(); - public final static int product_teledongle = usb_product_teledongle(); - public final static int product_teleterra = usb_product_teleterra(); - public final static int product_telebt = usb_product_telebt(); - public final static int product_telelaunch = usb_product_telelaunch(); - public final static int product_tele10 = usb_product_telelco(); - public final static int product_telescience = usb_product_telescience(); - public final static int product_telepyro = usb_product_telepyro(); - public final static int product_altusmetrum_min = usb_product_altusmetrum_min(); - public final static int product_altusmetrum_max = usb_product_altusmetrum_max(); - - public final static int product_any = 0x10000; - public final static int product_basestation = 0x10000 + 1; - - static String bt_product_telebt() { - load_library(); - return "TeleBT"; - } - - public final static String bt_product_telebt = bt_product_telebt(); - - public static AltosBTKnown bt_known = new AltosBTKnown(); } diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index 55b8f8fc..f6926b10 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -116,6 +116,7 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { } public AltosBTDevice(String name, String addr) { + Altos.load_library(); libaltos.altos_bt_fill_in(name, addr,this); } diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java index e30be057..021e4d0b 100644 --- a/altosui/AltosBTKnown.java +++ b/altosui/AltosBTKnown.java @@ -94,4 +94,12 @@ public class AltosBTKnown implements Iterable { bt_pref = AltosUIPreferences.bt_devices(); load(); } -} \ No newline at end of file + + static AltosBTKnown known; + + static public AltosBTKnown bt_known() { + if (known == null) + known = new AltosBTKnown(); + return known; + } +} diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 35fef080..cae41858 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -491,7 +491,7 @@ public class AltosConfig implements ActionListener { try { serial_line = new AltosSerial(device); try { - if (!device.matchProduct(Altos.product_telemetrum)) + if (!device.matchProduct(Altos.product_altimeter)) remote = true; init_ui(); } catch (InterruptedException ie) { diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index deb179d6..d0ed9325 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -344,7 +344,7 @@ public class AltosConfigureUI manage_bluetooth = new JButton("Manage Bluetooth"); manage_bluetooth.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - AltosBTManage.show(owner, Altos.bt_known); + AltosBTManage.show(owner, AltosBTKnown.bt_known()); } }); c.gridx = 0; diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index e53e75c1..fa9d0013 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -41,7 +41,7 @@ public class AltosDeviceDialog extends AltosDialog implements ActionListener { private AltosDevice[] devices() { java.util.List usb_devices = AltosUSBDevice.list(product); int num_devices = usb_devices.size(); - java.util.List bt_devices = Altos.bt_known.list(product); + java.util.List bt_devices = AltosBTKnown.bt_known().list(product); num_devices += bt_devices.size(); AltosDevice[] devices = new AltosDevice[num_devices]; @@ -169,7 +169,7 @@ public class AltosDeviceDialog extends AltosDialog implements ActionListener { if ("select".equals(e.getActionCommand())) value = (AltosDevice)(list.getSelectedValue()); if ("manage".equals(e.getActionCommand())) { - AltosBTManage.show(frame, Altos.bt_known); + AltosBTManage.show(frame, AltosBTKnown.bt_known()); update_devices(); return; } diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 538f8734..926d66f0 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -538,6 +538,7 @@ public class AltosUI extends AltosFrame { } public static void main(final String[] args) { + load_library(null); try { UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel()); } catch (Exception e) { -- cgit v1.2.3 From 4cb46b8a84a0dd5b8fcb479d7aa5157480e1bc67 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jun 2012 19:01:24 -0700 Subject: altosui: Add rudimentary MM support to altosui Decoded the MM sensor packets as if they were TM packets. Add the USB ids. Add class of 'altimeter' devices and match those instead of just telemetrum as appropriate. Signed-off-by: Keith Packard --- altoslib/AltosTelemetryRecord.java | 2 ++ altosui/AltosIdleMonitorUI.java | 2 +- altosui/AltosIgnite.java | 2 +- altosui/AltosUSBDevice.java | 7 ++++++- 4 files changed, 10 insertions(+), 3 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java index 4292dae8..6b6a252d 100644 --- a/altoslib/AltosTelemetryRecord.java +++ b/altoslib/AltosTelemetryRecord.java @@ -42,6 +42,7 @@ public abstract class AltosTelemetryRecord { final static int packet_type_location = 0x05; final static int packet_type_satellite = 0x06; final static int packet_type_companion = 0x07; + final static int packet_type_MM_sensor = 0x08; static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { AltosTelemetryRecord r; @@ -75,6 +76,7 @@ public abstract class AltosTelemetryRecord { case packet_type_TM_sensor: case packet_type_Tm_sensor: case packet_type_Tn_sensor: + case packet_type_MM_sensor: r = new AltosTelemetryRecordSensor(bytes, rssi); break; case packet_type_configuration: diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 02295ea9..2ee90937 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -325,7 +325,7 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay device = AltosDeviceDialog.show(in_owner, Altos.product_any); remote = false; - if (!device.matchProduct(Altos.product_telemetrum)) + if (!device.matchProduct(Altos.product_altimeter)) remote = true; serial = device.getSerial(); diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index c0cd44f1..45d37d16 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -178,7 +178,7 @@ public class AltosIgnite { serial = new AltosSerial(device); remote = false; - if (!device.matchProduct(Altos.product_telemetrum)) + if (!device.matchProduct(Altos.product_altimeter)) remote = true; } } \ No newline at end of file diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java index b11a3934..ed5f8307 100644 --- a/altosui/AltosUSBDevice.java +++ b/altosui/AltosUSBDevice.java @@ -71,7 +71,12 @@ public class AltosUSBDevice extends altos_device implements AltosDevice { if (want_product == Altos.product_basestation) return matchProduct(Altos.product_teledongle) || matchProduct(Altos.product_teleterra) || - matchProduct(Altos.product_telebt); + 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(); -- cgit v1.2.3 From 6f421818fd7062f03bfaf9e606d6a4cfdcb13b49 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 21 Jun 2012 09:50:18 -0700 Subject: altosui: Support MM telemetry packets Required restructuring the whole telemetry system to provide abstract interfaces to flight data. Signed-off-by: Keith Packard --- altoslib/AltosEepromIterable.java | 10 +- altoslib/AltosEepromMegaIterable.java | 32 ++-- altoslib/AltosLib.java | 20 +++ altoslib/AltosMs5607.java | 7 + altoslib/AltosRecord.java | 225 +++++++-------------------- altoslib/AltosRecordMM.java | 186 ++++++++++++++++++++++ altoslib/AltosRecordTM.java | 199 +++++++++++++++++++++++ altoslib/AltosTelemetry.java | 2 +- altoslib/AltosTelemetryIterable.java | 6 +- altoslib/AltosTelemetryRecord.java | 8 +- altoslib/AltosTelemetryRecordLegacy.java | 8 +- altoslib/AltosTelemetryRecordMegaData.java | 96 ++++++++++++ altoslib/AltosTelemetryRecordMegaSensor.java | 98 ++++++++++++ altoslib/AltosTelemetryRecordRaw.java | 6 +- altoslib/AltosTelemetryRecordSensor.java | 10 +- altoslib/Makefile.am | 4 + altosui/AltosCSV.java | 8 +- altosui/AltosIdleMonitorUI.java | 23 +-- 18 files changed, 735 insertions(+), 213 deletions(-) create mode 100644 altoslib/AltosRecordMM.java create mode 100644 altoslib/AltosRecordTM.java create mode 100644 altoslib/AltosTelemetryRecordMegaData.java create mode 100644 altoslib/AltosTelemetryRecordMegaSensor.java (limited to 'altosui') diff --git a/altoslib/AltosEepromIterable.java b/altoslib/AltosEepromIterable.java index a923d63b..f8acdc16 100644 --- a/altoslib/AltosEepromIterable.java +++ b/altoslib/AltosEepromIterable.java @@ -104,7 +104,7 @@ public class AltosEepromIterable extends AltosRecordIterable { } } - void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) { + void update_state(AltosRecordTM state, AltosEepromRecord record, EepromState eeprom) { state.tick = record.tick; switch (record.cmd) { case AltosLib.AO_LOG_FLIGHT: @@ -237,7 +237,7 @@ public class AltosEepromIterable extends AltosRecordIterable { LinkedList list = new LinkedList(); Iterator iterator = records.iterator(); AltosOrderedRecord record = null; - AltosRecord state = new AltosRecord(); + AltosRecordTM state = new AltosRecordTM(); boolean last_reported = false; EepromState eeprom = new EepromState(); @@ -254,13 +254,13 @@ public class AltosEepromIterable extends AltosRecordIterable { while (iterator.hasNext()) { record = iterator.next(); if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { - AltosRecord r = new AltosRecord(state); + AltosRecordTM r = state.clone(); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); } update_state(state, record, eeprom); } - AltosRecord r = new AltosRecord(state); + AltosRecordTM r = state.clone(); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); return list; @@ -399,7 +399,7 @@ public class AltosEepromIterable extends AltosRecordIterable { try { for (;;) { - String line = AltosRecord.gets(input); + String line = AltosLib.gets(input); if (line == null) break; AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid); diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java index 28a298b3..f62cc45b 100644 --- a/altoslib/AltosEepromMegaIterable.java +++ b/altoslib/AltosEepromMegaIterable.java @@ -108,7 +108,7 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { } } - void update_state(AltosRecord state, AltosEepromMega record, EepromState eeprom) { + void update_state(AltosRecordMM state, AltosEepromMega record, EepromState eeprom) { state.tick = record.tick; switch (record.cmd) { case AltosLib.AO_LOG_FLIGHT: @@ -122,7 +122,8 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { break; case AltosLib.AO_LOG_SENSOR: state.accel = record.accel(); - state.pres = baro.set(record.pres(), record.temp()); + baro.set(record.pres(), record.temp()); + state.pres = baro.pa; state.temp = baro.cc; state.imu = new AltosIMU(); state.imu.accel_x = record.accel_x(); @@ -161,15 +162,20 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { eeprom.seen |= seen_sensor; break; case AltosLib.AO_LOG_TEMP_VOLT: - state.batt = record.v_batt(); + state.v_batt = record.v_batt(); + state.v_pyro = record.v_pbatt(); + for (int i = 0; i < AltosRecordMM.num_sense; i++) + state.sense[i] = record.sense(i); eeprom.seen |= seen_temp_volt; break; - case AltosLib.AO_LOG_DEPLOY: - state.drogue = record.a; - state.main = record.b; - eeprom.seen |= seen_deploy; - has_ignite = true; - break; +// +// case AltosLib.AO_LOG_DEPLOY: +// state.drogue = record.a; +// state.main = record.b; +// eeprom.seen |= seen_deploy; +// has_ignite = true; +// break; + case AltosLib.AO_LOG_STATE: state.state = record.state(); break; @@ -278,7 +284,7 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { LinkedList list = new LinkedList(); Iterator iterator = records.iterator(); AltosOrderedMegaRecord record = null; - AltosRecord state = new AltosRecord(); + AltosRecordMM state = new AltosRecordMM(); boolean last_reported = false; EepromState eeprom = new EepromState(); @@ -295,13 +301,13 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { while (iterator.hasNext()) { record = iterator.next(); if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { - AltosRecord r = new AltosRecord(state); + AltosRecordMM r = state.clone(); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); } update_state(state, record, eeprom); } - AltosRecord r = new AltosRecord(state); + AltosRecordMM r = state.clone(); r.time = (r.tick - eeprom.boost_tick) / 100.0; list.add(r); return list; @@ -442,7 +448,7 @@ public class AltosEepromMegaIterable extends AltosRecordIterable { try { for (;;) { - String line = AltosRecord.gets(input); + String line = AltosLib.gets(input); if (line == null) break; AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid); diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 4a779c55..2402331e 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -20,6 +20,7 @@ package org.altusmetrum.AltosLib; import java.awt.*; import java.util.*; import java.text.*; +import java.io.*; import java.nio.charset.Charset; public class AltosLib { @@ -304,6 +305,10 @@ public class AltosLib { (bytes[i+3] << 24); } + public static int int32(int[] bytes, int i) { + return (int) uint32(bytes, i); + } + public static final Charset unicode_set = Charset.forName("UTF-8"); public static String string(int[] bytes, int s, int l) { @@ -375,6 +380,21 @@ public class AltosLib { return v * sign; } + public static String gets(FileInputStream s) throws IOException { + int c; + String line = ""; + + while ((c = s.read()) != -1) { + if (c == '\r') + continue; + if (c == '\n') { + return line; + } + line = line + (char) c; + } + return null; + } + public static String replace_extension(String input, String extension) { int dot = input.lastIndexOf("."); if (dot > 0) diff --git a/altoslib/AltosMs5607.java b/altoslib/AltosMs5607.java index a7b902e2..5fd997d8 100644 --- a/altoslib/AltosMs5607.java +++ b/altoslib/AltosMs5607.java @@ -73,4 +73,11 @@ public class AltosMs5607 { convert(); return pa; } + + public AltosMs5607() { + raw_pres = AltosRecord.MISSING; + raw_temp = AltosRecord.MISSING; + pa = AltosRecord.MISSING; + cc = AltosRecord.MISSING; + } } diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index 10ef3061..e468f84b 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -22,8 +22,7 @@ import java.text.*; import java.util.HashMap; import java.io.*; -public class AltosRecord implements Comparable { - public final static int MISSING = 0x7fffffff; +public class AltosRecord implements Comparable , Cloneable { public static final int seen_flight = 1; public static final int seen_sensor = 2; @@ -33,8 +32,13 @@ public class AltosRecord implements Comparable { public static final int seen_gps_lat = 32; public static final int seen_gps_lon = 64; public static final int seen_companion = 128; - public int seen; + public int seen; + + public final static int MISSING = 0x7fffffff; + + /* Every AltosRecord implementation provides these fields */ + public int version; public String callsign; public int serial; @@ -44,31 +48,13 @@ public class AltosRecord implements Comparable { public int state; public int tick; - public int accel; - public int pres; - public int temp; - public int batt; - public int drogue; - public int main; - - public int ground_accel; - public int ground_pres; - public int accel_plus_g; - public int accel_minus_g; - - public double acceleration; - public double speed; - public double height; - - public int flight_accel; - public int flight_vel; - public int flight_pres; + /* Current flight dynamic state */ + public double acceleration; /* m/s² */ + public double speed; /* m/s */ + public double height; /* m */ public AltosGPS gps; - public boolean new_gps; - - public AltosIMU imu; - public AltosMag mag; + public boolean new_gps; public double time; /* seconds since boost */ @@ -83,45 +69,42 @@ public class AltosRecord implements Comparable { public AltosRecordCompanion companion; /* - * Values for our MP3H6115A pressure sensor - * - * From the data sheet: + * Abstract methods that convert record data + * to standard units: * - * Pressure range: 15-115 kPa - * Voltage at 115kPa: 2.82 - * Output scale: 27mV/kPa - * - * - * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa - * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa + * pressure: Pa + * voltage: V + * acceleration: m/s² + * speed: m/s + * height: m + * temperature: °C */ - public static final double counts_per_kPa = 27 * 2047 / 3300; - public static final double counts_at_101_3kPa = 1674.0; + public double raw_pressure() { return MISSING; } - public static double - barometer_to_pressure(double count) - { - return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; - } + public double filtered_pressure() { return MISSING; } - public double raw_pressure() { - if (pres == MISSING) - return MISSING; - return barometer_to_pressure(pres); - } + public double ground_pressure() { return MISSING; } - public double filtered_pressure() { - if (flight_pres == MISSING) - return MISSING; - return barometer_to_pressure(flight_pres); - } + public double battery_voltage() { return MISSING; } - public double ground_pressure() { - if (ground_pres == MISSING) - return MISSING; - return barometer_to_pressure(ground_pres); - } + public double main_voltage() { return MISSING; } + + public double drogue_voltage() { return MISSING; } + + public double temperature() { return MISSING; } + + public double acceleration() { return MISSING; } + + public double accel_speed() { return MISSING; } + + public AltosIMU imu() { return null; } + + public AltosMag mag() { return null; } + + /* + * Convert various pressure values to altitude + */ public double raw_altitude() { double p = raw_pressure(); @@ -138,8 +121,9 @@ public class AltosRecord implements Comparable { } public double filtered_altitude() { - if (height != MISSING && ground_pres != MISSING) - return height + ground_altitude(); + double ga = ground_altitude(); + if (height != MISSING && ga != MISSING) + return height + ga; double p = filtered_pressure(); if (p == MISSING) @@ -167,94 +151,17 @@ public class AltosRecord implements Comparable { return r - g; } - public double battery_voltage() { - if (batt == MISSING) - return MISSING; - return AltosConvert.cc_battery_to_voltage(batt); - } - - public double main_voltage() { - if (main == MISSING) - return MISSING; - return AltosConvert.cc_ignitor_to_voltage(main); - } - - public double drogue_voltage() { - if (drogue == MISSING) - return MISSING; - return AltosConvert.cc_ignitor_to_voltage(drogue); - } - - /* Value for the CC1111 built-in temperature sensor - * Output voltage at 0°C = 0.755V - * Coefficient = 0.00247V/°C - * Reference voltage = 1.25V - * - * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 - * = (value - 19791.268) / 32768 * 1.25 / 0.00247 - */ - - public static double - thermometer_to_temperature(double thermo) - { - return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; - } - - public double temperature() { - if (temp == MISSING) - return MISSING; - return thermometer_to_temperature(temp); - } - - public double accel_counts_per_mss() { - double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; - - return counts_per_g / 9.80665; - } - - public double acceleration() { - if (acceleration != MISSING) - return acceleration; - - if (ground_accel == MISSING || accel == MISSING) - return MISSING; - return (ground_accel - accel) / accel_counts_per_mss(); - } - - public double accel_speed() { - if (speed != MISSING) - return speed; - if (flight_vel == MISSING) - return MISSING; - return flight_vel / (accel_counts_per_mss() * 100.0); - } - public String state() { return AltosLib.state_name(state); } - public static String gets(FileInputStream s) throws IOException { - int c; - String line = ""; - - while ((c = s.read()) != -1) { - if (c == '\r') - continue; - if (c == '\n') { - return line; - } - line = line + (char) c; - } - return null; - } - public int compareTo(AltosRecord o) { return tick - o.tick; } - public AltosRecord(AltosRecord old) { - version = old.version; + public void copy(AltosRecord old) { seen = old.seen; + version = old.version; callsign = old.callsign; serial = old.serial; flight = old.flight; @@ -262,32 +169,27 @@ public class AltosRecord implements Comparable { status = old.status; state = old.state; tick = old.tick; - accel = old.accel; - pres = old.pres; - temp = old.temp; - batt = old.batt; - drogue = old.drogue; - main = old.main; - flight_accel = old.flight_accel; - ground_accel = old.ground_accel; - flight_vel = old.flight_vel; - flight_pres = old.flight_pres; - ground_pres = old.ground_pres; - accel_plus_g = old.accel_plus_g; - accel_minus_g = old.accel_minus_g; acceleration = old.acceleration; speed = old.speed; height = old.height; gps = new AltosGPS(old.gps); new_gps = false; companion = old.companion; - imu = old.imu; - mag = old.mag; + } + + public AltosRecord clone() { + try { + AltosRecord n = (AltosRecord) super.clone(); + n.copy(this); + return n; + } catch (CloneNotSupportedException e) { + return null; + } } public AltosRecord() { - version = 0; seen = 0; + version = 0; callsign = "N0CALL"; serial = 0; flight = 0; @@ -295,19 +197,6 @@ public class AltosRecord implements Comparable { status = 0; state = AltosLib.ao_flight_startup; tick = 0; - accel = MISSING; - pres = MISSING; - temp = MISSING; - batt = MISSING; - drogue = MISSING; - main = MISSING; - flight_accel = 0; - ground_accel = 0; - flight_vel = 0; - flight_pres = 0; - ground_pres = 0; - accel_plus_g = 0; - accel_minus_g = 0; acceleration = MISSING; speed = MISSING; height = MISSING; diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java new file mode 100644 index 00000000..8b3d745a --- /dev/null +++ b/altoslib/AltosRecordMM.java @@ -0,0 +1,186 @@ +/* + * 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 class AltosRecordMM extends AltosRecord { + + public int accel; + public int pres; + public int temp; + + public int v_batt; + public int v_pyro; + public int sense[]; + + public int ground_accel; + public int ground_pres; + public int accel_plus_g; + public int accel_minus_g; + + public int flight_accel; + public int flight_vel; + public int flight_pres; + + public final static int num_sense = 6; + + public AltosIMU imu; + public AltosMag mag; + + static double adc(int raw) { + return raw / 4095.0; + } + + public double raw_pressure() { + if (pres != MISSING) + return pres / 100.0; + return MISSING; + } + + public double filtered_pressure() { + return raw_pressure(); + } + + public double ground_pressure() { + if (ground_pres != MISSING) + return ground_pres / 100.0; + return MISSING; + } + + public double battery_voltage() { + if (v_batt != MISSING) + return 3.3 * adc(v_batt) * 27.0 / (15.0 + 27.0); + return MISSING; + } + + static double pyro(int raw) { + if (raw != MISSING) + return 3.3 * adc(raw) * 27.0 / (100.0 + 27.0); + return MISSING; + } + + public double main_voltage() { + return pyro(sense[1]); + } + + public double drogue_voltage() { + return pyro(sense[0]); + } + + public double temperature() { + if (temp != MISSING) + return temp / 100.0; + return MISSING; + } + + public AltosIMU imu() { return imu; } + + public AltosMag mag() { return mag; } + + double accel_counts_per_mss() { + double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; + + return counts_per_g / 9.80665; + } + + public double acceleration() { + System.out.printf("MM record acceleration %g ground_accel %d accel %d accel_minus_g %d accel_plus_g %d\n", + acceleration, ground_accel, accel, accel_minus_g, accel_plus_g); + if (acceleration != MISSING) + return acceleration; + + if (ground_accel == MISSING || accel == MISSING) + return MISSING; + + if (accel_minus_g == MISSING || accel_plus_g == MISSING) + return MISSING; + + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public double accel_speed() { + return speed; + } + + public void copy (AltosRecordMM old) { + super.copy(old); + + accel = old.accel; + pres = old.pres; + temp = old.temp; + + v_batt = old.v_batt; + v_pyro = old.v_pyro; + sense = new int[num_sense]; + + for (int i = 0; i < num_sense; i++) + sense[i] = old.sense[i]; + + ground_accel = old.ground_accel; + ground_pres = old.ground_pres; + accel_plus_g = old.accel_plus_g; + accel_minus_g = old.accel_minus_g; + + flight_accel = old.flight_accel; + flight_vel = old.flight_vel; + flight_pres = old.flight_pres; + + imu = old.imu; + mag = old.mag; + } + + public AltosRecordMM clone() { + AltosRecordMM n = (AltosRecordMM) super.clone(); + n.copy(this); + return n; + } + + void make_missing() { + + accel = MISSING; + pres = MISSING; + temp = MISSING; + + v_batt = MISSING; + v_pyro = MISSING; + sense = new int[num_sense]; + for (int i = 0; i < num_sense; i++) + sense[i] = MISSING; + + ground_accel = MISSING; + ground_pres = MISSING; + accel_plus_g = MISSING; + accel_minus_g = MISSING; + + flight_accel = 0; + flight_vel = 0; + flight_pres = 0; + + imu = new AltosIMU(); + mag = new AltosMag(); + } + + public AltosRecordMM(AltosRecord old) { + super.copy(old); + make_missing(); + } + + public AltosRecordMM() { + super(); + make_missing(); + } +} diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java new file mode 100644 index 00000000..afb70790 --- /dev/null +++ b/altoslib/AltosRecordTM.java @@ -0,0 +1,199 @@ +/* + * 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 class AltosRecordTM extends AltosRecord { + public int accel; + public int pres; + public int temp; + public int batt; + public int drogue; + public int main; + + public int ground_accel; + public int ground_pres; + public int accel_plus_g; + public int accel_minus_g; + + public int flight_accel; + public int flight_vel; + public int flight_pres; + + /* + * Values for our MP3H6115A pressure sensor + * + * From the data sheet: + * + * Pressure range: 15-115 kPa + * Voltage at 115kPa: 2.82 + * Output scale: 27mV/kPa + * + * + * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa + * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa + */ + + static final double counts_per_kPa = 27 * 2047 / 3300; + static final double counts_at_101_3kPa = 1674.0; + + static double + barometer_to_pressure(double count) + { + return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0; + } + + public double raw_pressure() { + if (pres == MISSING) + return MISSING; + return barometer_to_pressure(pres); + } + + public double filtered_pressure() { + if (flight_pres == MISSING) + return MISSING; + return barometer_to_pressure(flight_pres); + } + + public double ground_pressure() { + if (ground_pres == MISSING) + return MISSING; + return barometer_to_pressure(ground_pres); + } + + public double battery_voltage() { + if (batt == MISSING) + return MISSING; + return AltosConvert.cc_battery_to_voltage(batt); + } + + public double main_voltage() { + if (main == MISSING) + return MISSING; + return AltosConvert.cc_ignitor_to_voltage(main); + } + + public double drogue_voltage() { + if (drogue == MISSING) + return MISSING; + return AltosConvert.cc_ignitor_to_voltage(drogue); + } + + /* Value for the CC1111 built-in temperature sensor + * Output voltage at 0°C = 0.755V + * Coefficient = 0.00247V/°C + * Reference voltage = 1.25V + * + * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 + * = (value - 19791.268) / 32768 * 1.25 / 0.00247 + */ + + static double + thermometer_to_temperature(double thermo) + { + return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; + } + + public double temperature() { + if (temp == MISSING) + return MISSING; + return thermometer_to_temperature(temp); + } + + double accel_counts_per_mss() { + double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2; + + return counts_per_g / 9.80665; + } + + public double acceleration() { + if (acceleration != MISSING) + return acceleration; + + if (ground_accel == MISSING || accel == MISSING) + return MISSING; + return (ground_accel - accel) / accel_counts_per_mss(); + } + + public double accel_speed() { + if (speed != MISSING) + return speed; + if (flight_vel == MISSING) + return MISSING; + return flight_vel / (accel_counts_per_mss() * 100.0); + } + + public void copy(AltosRecordTM old) { + super.copy(old); + + version = old.version; + callsign = old.callsign; + serial = old.serial; + flight = old.flight; + rssi = old.rssi; + status = old.status; + state = old.state; + tick = old.tick; + accel = old.accel; + pres = old.pres; + temp = old.temp; + batt = old.batt; + drogue = old.drogue; + main = old.main; + flight_accel = old.flight_accel; + ground_accel = old.ground_accel; + flight_vel = old.flight_vel; + flight_pres = old.flight_pres; + ground_pres = old.ground_pres; + accel_plus_g = old.accel_plus_g; + accel_minus_g = old.accel_minus_g; + } + + public AltosRecordTM clone() { + AltosRecordTM n = (AltosRecordTM) super.clone(); + n.copy(this); + return n; + } + + void make_missing() { + accel = MISSING; + pres = MISSING; + temp = MISSING; + batt = MISSING; + drogue = MISSING; + main = MISSING; + + flight_accel = 0; + flight_vel = 0; + flight_pres = 0; + + ground_accel = 0; + ground_pres = 0; + accel_plus_g = 0; + accel_minus_g = 0; + } + + public AltosRecordTM(AltosRecord old) { + super.copy(old); + make_missing(); + } + + public AltosRecordTM() { + super(); + make_missing(); + } +} diff --git a/altoslib/AltosTelemetry.java b/altoslib/AltosTelemetry.java index 04abb1f3..ee244824 100644 --- a/altoslib/AltosTelemetry.java +++ b/altoslib/AltosTelemetry.java @@ -84,7 +84,7 @@ import java.util.HashMap; * */ -public class AltosTelemetry extends AltosRecord { +public abstract class AltosTelemetry extends AltosRecord { /* * General header fields diff --git a/altoslib/AltosTelemetryIterable.java b/altoslib/AltosTelemetryIterable.java index f4b4029f..e95c15e0 100644 --- a/altoslib/AltosTelemetryIterable.java +++ b/altoslib/AltosTelemetryIterable.java @@ -45,7 +45,7 @@ public class AltosTelemetryIterable extends AltosRecordIterable { try { for (;;) { - String line = AltosRecord.gets(input); + String line = AltosLib.gets(input); if (line == null) { break; } @@ -67,11 +67,11 @@ public class AltosTelemetryIterable extends AltosRecordIterable { saw_boost = true; boost_tick = record.tick; } - if (record.accel != AltosRecord.MISSING) + if (record.acceleration() != AltosRecord.MISSING) has_accel = true; if (record.gps != null) has_gps = true; - if (record.main != AltosRecord.MISSING) + if (record.main_voltage() != AltosRecord.MISSING) has_ignite = true; if (previous != null && previous.tick != record.tick) records.add(previous); diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java index 6b6a252d..6a8cfd35 100644 --- a/altoslib/AltosTelemetryRecord.java +++ b/altoslib/AltosTelemetryRecord.java @@ -43,6 +43,7 @@ public abstract class AltosTelemetryRecord { final static int packet_type_satellite = 0x06; final static int packet_type_companion = 0x07; final static int packet_type_MM_sensor = 0x08; + final static int packet_type_MM_data = 0x09; static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException { AltosTelemetryRecord r; @@ -76,7 +77,6 @@ public abstract class AltosTelemetryRecord { case packet_type_TM_sensor: case packet_type_Tm_sensor: case packet_type_Tn_sensor: - case packet_type_MM_sensor: r = new AltosTelemetryRecordSensor(bytes, rssi); break; case packet_type_configuration: @@ -91,6 +91,12 @@ public abstract class AltosTelemetryRecord { case packet_type_companion: r = new AltosTelemetryRecordCompanion(bytes); break; + case packet_type_MM_sensor: + r = new AltosTelemetryRecordMegaSensor(bytes, rssi); + break; + case packet_type_MM_data: + r = new AltosTelemetryRecordMegaData(bytes); + break; default: r = new AltosTelemetryRecordRaw(bytes); break; diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java index 85071d9c..3976a07a 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -232,7 +232,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { final static String AO_TELEM_SAT_SVID = "s_v"; final static String AO_TELEM_SAT_C_N_0 = "s_c"; - AltosRecord record; + AltosRecordTM record; private void parse_v4(String[] words, int i) throws ParseException { AltosTelemetryMap map = new AltosTelemetryMap(words, i); @@ -366,7 +366,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { String[] words = line.split("\\s+"); int i = 0; - record = new AltosRecord(); + record = new AltosRecordTM(); if (words[i].equals("CRC") && words[i+1].equals("INVALID")) { i += 2; @@ -388,7 +388,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { } /* - * Given a hex dump of a legacy telemetry line, construct an AltosRecord from that + * Given a hex dump of a legacy telemetry line, construct an AltosRecordTM from that */ int[] bytes; @@ -422,7 +422,7 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord { static final int AO_GPS_COURSE_VALID = (1 << 7); public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) { - record = new AltosRecord(); + record = new AltosRecordTM(); bytes = in_bytes; record.version = 4; diff --git a/altoslib/AltosTelemetryRecordMegaData.java b/altoslib/AltosTelemetryRecordMegaData.java new file mode 100644 index 00000000..cc35cd83 --- /dev/null +++ b/altoslib/AltosTelemetryRecordMegaData.java @@ -0,0 +1,96 @@ +/* + * 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.AltosLib; + + +public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw { + + int state; + + int v_batt; + int v_pyro; + int sense[]; + + int ground_pres; + int ground_accel; + int accel_plus_g; + int accel_minus_g; + + int acceleration; + int speed; + int height; + + public AltosTelemetryRecordMegaData(int[] in_bytes) { + super(in_bytes); + + state = int8(5); + + v_batt = int16(6); + v_pyro = int16(8); + + sense = new int[6]; + + for (int i = 0; i < 6; i++) { + sense[i] = int8(10 + i) << 4; + sense[i] |= sense[i] >> 8; + } + + ground_pres = int32(16); + ground_accel = int16(20); + accel_plus_g = int16(22); + accel_minus_g = int16(24); + + acceleration = int16(26); + speed = int16(28); + height = int16(30); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord n = super.update_state(previous); + + AltosRecordMM next; + if (!(n instanceof AltosRecordMM)) { + System.out.printf("data making record MM\n"); + next = new AltosRecordMM(n); + } else { + System.out.printf ("data already has MM\n"); + next = (AltosRecordMM) n; + } + + next.state = state; + + next.v_batt = v_batt; + next.v_pyro = v_pyro; + + for (int i = 0; i < 6; i++) + next.sense[i] = sense[i]; + + next.ground_accel = ground_accel; + next.ground_pres = ground_pres; + next.accel_plus_g = accel_plus_g; + next.accel_minus_g = accel_minus_g; + + next.acceleration = acceleration / 16.0; + next.speed = speed / 16.0; + next.height = height; + + next.seen |= AltosRecord.seen_flight | AltosRecord.seen_temp_volt; + + return next; + } +} diff --git a/altoslib/AltosTelemetryRecordMegaSensor.java b/altoslib/AltosTelemetryRecordMegaSensor.java new file mode 100644 index 00000000..85a32d12 --- /dev/null +++ b/altoslib/AltosTelemetryRecordMegaSensor.java @@ -0,0 +1,98 @@ +/* + * 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.AltosLib; + + +public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { + int accel; + int pres; + int temp; + + int accel_x; + int accel_y; + int accel_z; + + int gyro_x; + int gyro_y; + int gyro_z; + + int mag_x; + int mag_y; + int mag_z; + + int rssi; + + public AltosTelemetryRecordMegaSensor(int[] in_bytes, int in_rssi) { + super(in_bytes); + + accel = int16(6); + pres = int32(8); + temp = int16(12); + + accel_x = int16(14); + accel_y = int16(16); + accel_z = int16(18); + + gyro_x = int16(20); + gyro_y = int16(22); + gyro_z = int16(24); + + mag_x = int16(26); + mag_y = int16(28); + mag_z = int16(30); + + rssi = in_rssi; + System.out.printf ("telem record accel: %d\n", accel); + } + + public AltosRecord update_state(AltosRecord previous) { + AltosRecord n = super.update_state(previous); + + AltosRecordMM next; + if (!(n instanceof AltosRecordMM)) { + System.out.printf("sensor making MM\n"); + next = new AltosRecordMM(n); + } else { + System.out.printf("sensor has MM\n"); + next = (AltosRecordMM) n; + } + + System.out.printf("telem update_state accel: %d\n", accel); + next.accel = accel; + next.pres = pres; + next.temp = temp; + + next.imu.accel_x = accel_x; + next.imu.accel_y = accel_y; + next.imu.accel_z = accel_z; + + next.imu.gyro_x = gyro_x; + next.imu.gyro_y = gyro_y; + next.imu.gyro_z = gyro_z; + + next.mag.x = mag_x; + next.mag.y = mag_y; + next.mag.z = mag_z; + + next.rssi = rssi; + + next.seen |= AltosRecord.seen_sensor; + + return next; + } +} diff --git a/altoslib/AltosTelemetryRecordRaw.java b/altoslib/AltosTelemetryRecordRaw.java index 43d0f17a..dc1b8947 100644 --- a/altoslib/AltosTelemetryRecordRaw.java +++ b/altoslib/AltosTelemetryRecordRaw.java @@ -49,6 +49,10 @@ public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { return AltosLib.uint32(bytes, off + 1); } + public int int32(int off) { + return AltosLib.int32(bytes, off + 1); + } + public String string(int off, int l) { return AltosLib.string(bytes, off + 1, l); } @@ -63,7 +67,7 @@ public class AltosTelemetryRecordRaw extends AltosTelemetryRecord { public AltosRecord update_state(AltosRecord previous) { AltosRecord next; if (previous != null) - next = new AltosRecord(previous); + next = previous.clone(); else next = new AltosRecord(); next.serial = serial; diff --git a/altoslib/AltosTelemetryRecordSensor.java b/altoslib/AltosTelemetryRecordSensor.java index cfaf90b0..319a91b3 100644 --- a/altoslib/AltosTelemetryRecordSensor.java +++ b/altoslib/AltosTelemetryRecordSensor.java @@ -61,8 +61,14 @@ public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw { rssi = in_rssi; } - public AltosRecord update_state(AltosRecord previous) { - AltosRecord next = super.update_state(previous); + public AltosRecord update_state(AltosRecord prev) { + AltosRecord n = super.update_state(prev); + + AltosRecordTM next; + if (!(n instanceof AltosRecordTM)) + next = new AltosRecordTM(n); + else + next = (AltosRecordTM) n; next.state = state; if (type == packet_type_TM_sensor) diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index f644d46a..ac97c9cb 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -35,6 +35,8 @@ AltosLib_JAVA = \ $(SRC)/AltosRecordCompanion.java \ $(SRC)/AltosRecordIterable.java \ $(SRC)/AltosRecord.java \ + $(SRC)/AltosRecordTM.java \ + $(SRC)/AltosRecordMM.java \ $(SRC)/AltosReplayReader.java \ $(SRC)/AltosState.java \ $(SRC)/AltosTelemetry.java \ @@ -50,6 +52,8 @@ AltosLib_JAVA = \ $(SRC)/AltosTelemetryRecordRaw.java \ $(SRC)/AltosTelemetryRecordSatellite.java \ $(SRC)/AltosTelemetryRecordSensor.java \ + $(SRC)/AltosTelemetryRecordMegaSensor.java \ + $(SRC)/AltosTelemetryRecordMegaData.java \ $(SRC)/AltosMs5607.java \ $(SRC)/AltosIMU.java \ $(SRC)/AltosMag.java diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index be86a454..c876d9ca 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -146,8 +146,8 @@ public class AltosCSV implements AltosWriter { } void write_advanced(AltosRecord record) { - AltosIMU imu = record.imu; - AltosMag mag = record.mag; + AltosIMU imu = record.imu(); + AltosMag mag = record.mag(); if (imu == null) imu = new AltosIMU(); @@ -263,7 +263,7 @@ public class AltosCSV implements AltosWriter { write_general(record); out.printf(","); write_flight(record); out.printf(","); write_basic(record); out.printf(","); - if (record.imu != null || record.mag != null) + if (record.imu() != null || record.mag() != null) write_advanced(record); if (record.gps != null) { out.printf(","); @@ -287,7 +287,7 @@ public class AltosCSV implements AltosWriter { if (record.state == Altos.ao_flight_startup) return; if (!header_written) { - write_header(record.imu != null || record.mag != null, + write_header(record.imu() != null || record.mag() != null, record.gps != null, record.companion != null); header_written = true; } diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 2ee90937..949e3926 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -204,17 +204,18 @@ class AltosIdleMonitor extends Thread { record.state = Altos.ao_flight_idle; record.tick = adc.tick; - record.accel = adc.accel; - record.pres = adc.pres; - record.batt = adc.batt; - record.temp = adc.temp; - record.drogue = adc.drogue; - record.main = adc.main; - - record.ground_accel = record.accel; - record.ground_pres = record.pres; - record.accel_plus_g = config_data.accel_cal_plus; - record.accel_minus_g = config_data.accel_cal_minus; + +// record.accel = adc.accel; +// record.pres = adc.pres; +// record.batt = adc.batt; +// record.temp = adc.temp; +// record.drogue = adc.drogue; +// record.main = adc.main; + +// record.ground_accel = record.accel; +// record.ground_pres = record.pres; +// record.accel_plus_g = config_data.accel_cal_plus; +// record.accel_minus_g = config_data.accel_cal_minus; record.acceleration = 0; record.speed = 0; record.height = 0; -- cgit v1.2.3 From 9dcb4e2ab60ecf0cc7371c1b1a620be952fa8776 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Jun 2012 22:19:01 -0700 Subject: altosui: AltosSerial and AltosLink both tried to provide frequency setting AltosLink owns all of the device configuration, so remove that from AltosSerial and make sure that AltosLink provides the right function signatures (wasn't using the new direct frequency setting command). Signed-off-by: Keith Packard --- altoslib/AltosLink.java | 28 ++++++++----------------- altosui/AltosSerial.java | 53 ------------------------------------------------ 2 files changed, 9 insertions(+), 72 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 77b400fc..a39204ac 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -166,6 +166,15 @@ public abstract class AltosLink { set_channel(AltosConvert.radio_frequency_to_channel(frequency)); } + public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { + frequency = in_frequency; + config_data(); + set_radio_frequency(frequency, + config_data.radio_frequency != 0, + config_data.radio_setting != 0, + config_data.radio_calibration); + } + public void set_telemetry(int in_telemetry) { telemetry = in_telemetry; if (monitor_mode) @@ -200,31 +209,12 @@ public abstract class AltosLink { flush_output(); } - public void set_radio_frequency(double frequency, - boolean has_setting, - int cal) { - if (debug) - System.out.printf("set_radio_frequency %7.3f %b %d\n", frequency, has_setting, cal); - if (has_setting) - set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); - else - set_channel(AltosConvert.radio_frequency_to_channel(frequency)); - } - public AltosConfigData config_data() throws InterruptedException, TimeoutException { if (config_data == null) config_data = new AltosConfigData(this); return config_data; } - public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException { - frequency = in_frequency; - config_data(); - set_radio_frequency(frequency, - config_data.radio_setting != 0, - config_data.radio_calibration); - } - public void set_callsign(String callsign) { printf ("c c %s\n", callsign); flush_output(); diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 5768ba71..8b60dd54 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -264,59 +264,6 @@ public class AltosSerial extends AltosLink implements Runnable { flush_output(); } - private int telemetry_len() { - return Altos.telemetry_len(telemetry); - } - - private void set_channel(int channel) { - if (altos != null) { - if (monitor_mode) - printf("m 0\nc r %d\nm %x\n", - channel, telemetry_len()); - else - printf("c r %d\n", channel); - flush_output(); - } - } - - private void set_radio_setting(int setting) { - if (altos != null) { - if (monitor_mode) - printf("m 0\nc R %d\nm %x\n", - setting, telemetry_len()); - else - printf("c R %d\n", setting); - flush_output(); - } - } - - private void set_radio_freq(int frequency) { - if (altos != null) { - if (monitor_mode) - printf("m 0\nc F %d\nm %x\n", - frequency, telemetry_len()); - else - printf("c F %d\n", frequency); - flush_output(); - } - } - - public void set_radio_frequency(double frequency, - boolean has_frequency, - boolean has_setting, - int cal) { - if (debug) - System.out.printf("set_radio_frequency %7.3f (freq %b) (set %b) %d\n", frequency, has_frequency, has_setting, cal); - if (frequency == 0) - return; - if (has_frequency) - set_radio_freq((int) Math.floor (frequency * 1000)); - else if (has_setting) - set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal)); - else - set_channel(AltosConvert.radio_frequency_to_channel(frequency)); - } - public void set_frame(Frame in_frame) { frame = in_frame; } -- cgit v1.2.3 From f11f05c5d634de2a80c34d0d3dc93925980f52e6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 26 Jun 2012 22:20:50 -0700 Subject: altosui: Make libaltos recognise new USB ids libaltos has a small range of 'AltusMetrum' products to avoid opening other devices. We've got more IDs, so open up the range. Signed-off-by: Keith Packard --- altosui/libaltos/libaltos.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 48e00a44..1cc27cbe 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -23,12 +23,8 @@ #define USB_VENDOR_FSF 0xfffe #define USB_VENDOR_ALTUSMETRUM USB_VENDOR_FSF #define USB_PRODUCT_ALTUSMETRUM 0x000a -#define USB_PRODUCT_TELEMETRUM 0x000b -#define USB_PRODUCT_TELEDONGLE 0x000c -#define USB_PRODUCT_TELETERRA 0x000d -#define USB_PRODUCT_TELEBT 0x000e #define USB_PRODUCT_ALTUSMETRUM_MIN 0x000a -#define USB_PRODUCT_ALTUSMETRUM_MAX 0x0013 +#define USB_PRODUCT_ALTUSMETRUM_MAX 0x00ff #define USB_IS_ALTUSMETRUM(v,p) ((v) == USB_VENDOR_ALTUSMETRUM && \ (USB_PRODUCT_ALTUSMETRUM_MIN <= (p) && \ -- cgit v1.2.3 From ea957f9e6144f8411ac84ee2905700f55f5a6e8a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 3 Jul 2012 00:29:43 -0700 Subject: altosui: Fix flight data download for TM. Look for MM flights when graphing A couple of minor fixes, the first to not force the log format so that TM/Tm data will be downloaded correctly and the second to expand the set of files to include '.mega' files when plotting data. Signed-off-by: Keith Packard --- altosui/AltosDataChooser.java | 2 +- altosui/AltosEepromDownload.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index 0d629b3c..4bd51c39 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -77,7 +77,7 @@ public class AltosDataChooser extends JFileChooser { frame = in_frame; setDialogTitle("Select Flight Record File"); setFileFilter(new FileNameExtensionFilter("Flight data file", - "telem", "eeprom")); + "telem", "eeprom", "mega")); setCurrentDirectory(AltosUIPreferences.logdir()); } } diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index d1e5fdf0..4a35c2f1 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -319,11 +319,9 @@ public class AltosEepromDownload implements Runnable { done = false; start = true; -// if (flights.config_data.serial == 0) -// throw new IOException("no serial number found"); + if (flights.config_data.serial == 0) + throw new IOException("no serial number found"); - log_format = 5; - System.out.printf ("log format: %d\n", log_format); /* Reset per-capture variables */ flight = 0; year = 0; -- cgit v1.2.3 From 675ccd41e3b668cd4e1d2dd282dd317a00d00151 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 00:35:21 -0700 Subject: Get AltOS version numbers into Mac 'about' dialog Generate Info.plist from Info.plist.in to correctly set the VERSION information. This also changes some strings around to make them look better Signed-off-by: Keith Packard --- altosui/AltosUI.app/Contents/Info.plist | 44 ------------------------------- altosui/Info.plist.in | 46 +++++++++++++++++++++++++++++++++ altosui/Makefile.am | 4 ++- configure.ac | 1 + 4 files changed, 50 insertions(+), 45 deletions(-) delete mode 100644 altosui/AltosUI.app/Contents/Info.plist create mode 100644 altosui/Info.plist.in (limited to 'altosui') diff --git a/altosui/AltosUI.app/Contents/Info.plist b/altosui/AltosUI.app/Contents/Info.plist deleted file mode 100644 index 60842804..00000000 --- a/altosui/AltosUI.app/Contents/Info.plist +++ /dev/null @@ -1,44 +0,0 @@ - - - - - CFBundleName - altosui - CFBundleVersion - 100.0 - CFBundleAllowMixedLocalizations - true - CFBundleExecutable - JavaApplicationStub - CFBundleDevelopmentRegion - English - CFBundlePackageType - APPL - CFBundleSignature - ???? - CFBundleGetInfoString - AltOS UI version 0.7 - CFBundleInfoDictionaryVersion - 6.0 - CFBundleIconFile - AltosUIIcon.icns - Java - - MainClass - altosui.AltosUI - JVMVersion - 1.5+ - ClassPath - - $JAVAROOT/altosui.jar - $JAVAROOT/freetts.jar - - VMOptions - - -Xms512M - -Xmx512M - -Dosgi.clean=true - - - - diff --git a/altosui/Info.plist.in b/altosui/Info.plist.in new file mode 100644 index 00000000..46dea171 --- /dev/null +++ b/altosui/Info.plist.in @@ -0,0 +1,46 @@ + + + + + CFBundleName + AltosUI + CFBundleVersion + @VERSION@ + CFBundleAllowMixedLocalizations + true + CFBundleExecutable + JavaApplicationStub + CFBundleDevelopmentRegion + English + CFBundlePackageType + APPL + CFBundleIdentifier + org.altusmetrum.altosui + CFBundleSignature + Altu + CFBundleGetInfoString + AltOS UI version @VERSION@ + CFBundleInfoDictionaryVersion + 6.0 + CFBundleIconFile + AltosUIIcon.icns + Java + + MainClass + altosui.AltosUI + JVMVersion + 1.5+ + ClassPath + + $JAVAROOT/altosui.jar + $JAVAROOT/freetts.jar + + VMOptions + + -Xms512M + -Xmx512M + -Dosgi.clean=true + + + + diff --git a/altosui/Makefile.am b/altosui/Makefile.am index feda00c7..b22405aa 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -165,7 +165,8 @@ FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCO LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC) LINUX_EXTRA=altosui-fat -MACOSX_FILES=$(FAT_FILES) libaltos.dylib +MACOSX_INFO_PLIST=Info.plist +MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) MACOSX_EXTRA=$(FIRMWARE) WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON) @@ -311,6 +312,7 @@ $(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) -rm -rf macosx mkdir macosx cp -a AltosUI.app macosx/ + cp -p Info.plist macosx/AltosUI.app/Contents mkdir -p macosx/AltOS 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 diff --git a/configure.ac b/configure.ac index a3004811..e78f5873 100644 --- a/configure.ac +++ b/configure.ac @@ -141,6 +141,7 @@ Makefile altoslib/Makefile altosui/Makefile altosui/AltosVersion.java +altosui/Info.plist altosui/libaltos/Makefile altosdroid/Makefile altosdroid/local.properties -- cgit v1.2.3 From 7be98836e69a222b2f9f4baacddcf12d168e2207 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 13:40:54 -0700 Subject: Add megametrum outline to doc dir And install it alongside telemetrum-outline Signed-off-by: Keith Packard --- altosui/Makefile.am | 2 +- altosui/altos-windows.nsi | 1 + debian/docs | 1 + doc/megametrum-outline.pdf | Bin 0 -> 4349 bytes doc/megametrum-outline.svg | 244 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 doc/megametrum-outline.pdf create mode 100644 doc/megametrum-outline.svg (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index b22405aa..1c8ea491 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -151,7 +151,7 @@ FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf ALTOS_DOC=$(top_srcdir)/doc/altos.pdf TELEMETRY_DOC=$(top_srcdir)/doc/telemetry.pdf -TEMPLATE_DOC=$(top_srcdir)/doc/telemetrum-outline.pdf +TEMPLATE_DOC=$(top_srcdir)/doc/telemetrum-outline.pdf $(top_srcdir)/doc/megametrum-outline.pdf DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TELEMETRY_DOC) $(TEMPLATE_DOC) diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index e5e01d79..92c985a9 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -126,6 +126,7 @@ Section "Documentation" File "../doc/altos.pdf" File "../doc/telemetry.pdf" File "../doc/telemetrum-outline.pdf" + File "../doc/megametrum-outline.pdf" SectionEnd Section "Uninstaller" diff --git a/debian/docs b/debian/docs index 6652abf7..3ac75ad4 100644 --- a/debian/docs +++ b/debian/docs @@ -7,3 +7,4 @@ doc/telemetry.pdf doc/altos.html doc/altos.pdf doc/telemetrum-outline.pdf +doc/megametrum-outline.pdf diff --git a/doc/megametrum-outline.pdf b/doc/megametrum-outline.pdf new file mode 100644 index 00000000..f8fc26e2 Binary files /dev/null and b/doc/megametrum-outline.pdf differ diff --git a/doc/megametrum-outline.svg b/doc/megametrum-outline.svg new file mode 100644 index 00000000..e8d74d38 --- /dev/null +++ b/doc/megametrum-outline.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UP + + -- cgit v1.2.3 From 846a6298e4a8bfbe87bb24d7b0802c0bf6f233be Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 13:53:30 -0700 Subject: Report RSSI values in monitor idle UI (trac #44) This adds a new 's' command to TeleDongle to report RSSI value from last received packet, and then has AltosUI request that value when closing the remote link. Signed-off-by: Keith Packard --- altosui/AltosIdleMonitorUI.java | 46 ++++++++++++++++++++++++++++------------- src/core/ao_packet.h | 2 ++ src/drivers/ao_packet.c | 11 ++++++---- src/drivers/ao_packet_master.c | 7 ++++++- 4 files changed, 47 insertions(+), 19 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 949e3926..eb6ec5e7 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -178,8 +178,23 @@ class AltosIdleMonitor extends Thread { AltosADC adc; AltosGPS gps; + int AltosRSSI() throws TimeoutException, InterruptedException { + serial.printf("s\n"); + String line = serial.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + if (items.length < 2) + return 0; + if (!items[0].equals("RSSI:")) + return 0; + int rssi = Integer.parseInt(items[1]); + return rssi; + } + void update_state() throws InterruptedException, TimeoutException { - AltosRecord record = new AltosRecord(); + AltosRecordTM record = new AltosRecordTM(); + int rssi; try { if (remote) { @@ -191,31 +206,34 @@ class AltosIdleMonitor extends Thread { adc = new AltosADC(serial); gps = new AltosGPSQuery(serial, config_data); } finally { - if (remote) + if (remote) { serial.stop_remote(); + rssi = AltosRSSI(); + } else + rssi = 0; } record.version = 0; record.callsign = config_data.callsign; record.serial = config_data.serial; record.flight = config_data.log_available() > 0 ? 255 : 0; - record.rssi = 0; + record.rssi = rssi; record.status = 0; record.state = Altos.ao_flight_idle; record.tick = adc.tick; -// record.accel = adc.accel; -// record.pres = adc.pres; -// record.batt = adc.batt; -// record.temp = adc.temp; -// record.drogue = adc.drogue; -// record.main = adc.main; - -// record.ground_accel = record.accel; -// record.ground_pres = record.pres; -// record.accel_plus_g = config_data.accel_cal_plus; -// record.accel_minus_g = config_data.accel_cal_minus; + record.accel = adc.accel; + record.pres = adc.pres; + record.batt = adc.batt; + record.temp = adc.temp; + record.drogue = adc.drogue; + record.main = adc.main; + + record.ground_accel = record.accel; + record.ground_pres = record.pres; + record.accel_plus_g = config_data.accel_cal_plus; + record.accel_minus_g = config_data.accel_cal_minus; record.acceleration = 0; record.speed = 0; record.height = 0; diff --git a/src/core/ao_packet.h b/src/core/ao_packet.h index 618ccda4..f232a878 100644 --- a/src/core/ao_packet.h +++ b/src/core/ao_packet.h @@ -67,6 +67,8 @@ ao_packet_pollchar(void) __critical; #if PACKET_HAS_MASTER /* ao_packet_master.c */ +extern __xdata uint8_t ao_packet_last_rssi; + void ao_packet_master_init(void); #endif diff --git a/src/drivers/ao_packet.c b/src/drivers/ao_packet.c index e020c003..d813b25f 100644 --- a/src/drivers/ao_packet.c +++ b/src/drivers/ao_packet.c @@ -27,7 +27,11 @@ static __pdata uint8_t rx_seq; __xdata struct ao_task ao_packet_task; __xdata uint8_t ao_packet_enable; + +#if PACKET_HAS_MASTER __xdata uint8_t ao_packet_master_sleeping; +__xdata uint8_t ao_packet_last_rssi; +#endif void ao_packet_send(void) @@ -80,6 +84,9 @@ ao_packet_recv(void) if (!(ao_rx_packet.status & AO_RADIO_STATUS_CRC_OK)) return 0; +#if PACKET_HAS_MASTER + ao_packet_last_rssi = ao_rx_packet.rssi; +#endif /* Accept packets with matching call signs, or any packet if * our callsign hasn't been configured */ @@ -130,10 +137,6 @@ ao_packet_recv(void) return 1; } -#ifndef PACKET_HAS_MASTER -#define PACKET_HAS_MASTER 1 -#endif - #if PACKET_HAS_MASTER void ao_packet_flush(void) diff --git a/src/drivers/ao_packet_master.c b/src/drivers/ao_packet_master.c index 66f94288..e97a6648 100644 --- a/src/drivers/ao_packet_master.c +++ b/src/drivers/ao_packet_master.c @@ -137,10 +137,15 @@ ao_packet_forward(void) __reentrant #endif } - +static void +ao_packet_signal(void) +{ + printf ("RSSI: %d\n", AO_RSSI_FROM_RADIO(ao_packet_last_rssi)); +} __code struct ao_cmds ao_packet_master_cmds[] = { { ao_packet_forward, "p\0Remote packet link." }, + { ao_packet_signal, "s\0Report signal strength." }, { 0, NULL }, }; -- cgit v1.2.3 From f078a591cf2fafe89bb1bb883f49d80750129d44 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 14:28:53 -0700 Subject: altosui: Remove a bunch of debugging printfs These aren't useful at this point. Signed-off-by: Keith Packard --- altoslib/AltosLog.java | 1 - altoslib/AltosPreferences.java | 2 -- altoslib/AltosRecordMM.java | 2 -- altoslib/AltosTelemetryRecordMegaData.java | 2 -- altoslib/AltosTelemetryRecordMegaSensor.java | 4 ---- altosui/AltosBTDevice.java | 2 -- altosui/AltosBTDeviceIterator.java | 2 -- altosui/AltosBTKnown.java | 2 -- altosui/AltosBTManage.java | 3 --- altosui/AltosConfigTD.java | 7 ++----- altosui/AltosConfigureUI.java | 1 - altosui/AltosFlashUI.java | 7 ------- altosui/AltosLaunchUI.java | 1 - 13 files changed, 2 insertions(+), 34 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosLog.java b/altoslib/AltosLog.java index 08c45ca8..55a25bb4 100644 --- a/altoslib/AltosLog.java +++ b/altoslib/AltosLog.java @@ -62,7 +62,6 @@ class AltosLog implements Runnable { boolean open (AltosRecord telem) throws IOException { AltosFile a = new AltosFile(telem); - System.out.printf("open %s\n", a.toString()); log_file = new FileWriter(a, true); if (log_file != null) { while (!pending_queue.isEmpty()) { diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index 43c7088d..9ab80cf5 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -306,7 +306,6 @@ public class AltosPreferences { public static void set_launcher_serial(int new_launcher_serial) { launcher_serial = new_launcher_serial; - System.out.printf("set launcher serial to %d\n", new_launcher_serial); synchronized (preferences) { preferences.putInt(launcherSerialPreference, launcher_serial); flush_preferences(); @@ -319,7 +318,6 @@ public class AltosPreferences { public static void set_launcher_channel(int new_launcher_channel) { launcher_channel = new_launcher_channel; - System.out.printf("set launcher channel to %d\n", new_launcher_channel); synchronized (preferences) { preferences.putInt(launcherChannelPreference, launcher_channel); flush_preferences(); diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java index 8b3d745a..055cf85f 100644 --- a/altoslib/AltosRecordMM.java +++ b/altoslib/AltosRecordMM.java @@ -98,8 +98,6 @@ public class AltosRecordMM extends AltosRecord { } public double acceleration() { - System.out.printf("MM record acceleration %g ground_accel %d accel %d accel_minus_g %d accel_plus_g %d\n", - acceleration, ground_accel, accel, accel_minus_g, accel_plus_g); if (acceleration != MISSING) return acceleration; diff --git a/altoslib/AltosTelemetryRecordMegaData.java b/altoslib/AltosTelemetryRecordMegaData.java index cc35cd83..8f55d238 100644 --- a/altoslib/AltosTelemetryRecordMegaData.java +++ b/altoslib/AltosTelemetryRecordMegaData.java @@ -65,10 +65,8 @@ public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw { AltosRecordMM next; if (!(n instanceof AltosRecordMM)) { - System.out.printf("data making record MM\n"); next = new AltosRecordMM(n); } else { - System.out.printf ("data already has MM\n"); next = (AltosRecordMM) n; } diff --git a/altoslib/AltosTelemetryRecordMegaSensor.java b/altoslib/AltosTelemetryRecordMegaSensor.java index 85a32d12..93c001de 100644 --- a/altoslib/AltosTelemetryRecordMegaSensor.java +++ b/altoslib/AltosTelemetryRecordMegaSensor.java @@ -57,7 +57,6 @@ public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { mag_z = int16(30); rssi = in_rssi; - System.out.printf ("telem record accel: %d\n", accel); } public AltosRecord update_state(AltosRecord previous) { @@ -65,14 +64,11 @@ public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw { AltosRecordMM next; if (!(n instanceof AltosRecordMM)) { - System.out.printf("sensor making MM\n"); next = new AltosRecordMM(n); } else { - System.out.printf("sensor has MM\n"); next = (AltosRecordMM) n; } - System.out.printf("telem update_state accel: %d\n", accel); next.accel = accel; next.pres = pres; next.temp = temp; diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index f6926b10..5e353fdd 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -87,7 +87,6 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { public boolean matchProduct(int want_product) { - System.out.printf("matchProduct %s %d\n", toString(), want_product); // if (!isAltusMetrum()) // return false; @@ -107,7 +106,6 @@ public class AltosBTDevice extends altos_bt_device implements AltosDevice { if (!(o instanceof AltosBTDevice)) return false; AltosBTDevice other = (AltosBTDevice) o; - System.out.printf("AltosBTDevice equals %s == %s\n", toString(), other.toString()); return getName().equals(other.getName()) && getAddr().equals(other.getAddr()); } diff --git a/altosui/AltosBTDeviceIterator.java b/altosui/AltosBTDeviceIterator.java index 7c360705..58ed86d5 100644 --- a/altosui/AltosBTDeviceIterator.java +++ b/altosui/AltosBTDeviceIterator.java @@ -26,7 +26,6 @@ public class AltosBTDeviceIterator implements Iterator { SWIGTYPE_p_altos_bt_list list; public boolean hasNext() { - System.out.printf ("BT has next?\n"); if (list == null) return false; if (current != null) @@ -35,7 +34,6 @@ public class AltosBTDeviceIterator implements Iterator { return false; current = new AltosBTDevice(); while (libaltos.altos_bt_list_next(list, current) != 0) { - System.out.printf("Got BT device %s\n", current.toString()); // if (current.matchProduct(product)) return true; } diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java index 021e4d0b..6a8e53cb 100644 --- a/altosui/AltosBTKnown.java +++ b/altosui/AltosBTKnown.java @@ -31,7 +31,6 @@ public class AltosBTKnown implements Iterable { private void set_address(String name, String addr) { bt_pref.put(name, addr); - System.out.printf("saving known %s %s\n", name, addr); } private void remove(String name) { @@ -44,7 +43,6 @@ public class AltosBTKnown implements Iterable { for (int i = 0; i < names.length; i++) { String name = names[i]; String addr = get_address(name); - System.out.printf("Known device %s %s\n", name, addr); devices.add(new AltosBTDevice(name, addr)); } } catch (BackingStoreException be) { diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index d2899d65..aeb964bb 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -126,7 +126,6 @@ public class AltosBTManage extends AltosDialog implements ActionListener, Iterab public void add_known() { for (AltosBTDevice device : visible_devices.selected_list()) { - System.out.printf("Add known %s\n", device.toString()); known_devices.add(device); visible_devices.remove(device); } @@ -134,7 +133,6 @@ public class AltosBTManage extends AltosDialog implements ActionListener, Iterab public void remove_known() { for (AltosBTDevice device : known_devices.selected_list()) { - System.out.printf("Remove known %s\n", device.toString()); known_devices.remove(device); visible_devices.add(device); } @@ -151,7 +149,6 @@ public class AltosBTManage extends AltosDialog implements ActionListener, Iterab public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); - System.out.printf("manage command %s\n", command); if ("ok".equals(command)) { bt_thread.interrupt(); commit(); diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java index 4048166c..324a5988 100644 --- a/altosui/AltosConfigTD.java +++ b/altosui/AltosConfigTD.java @@ -144,10 +144,8 @@ public class AltosConfigTD implements ActionListener { get_string(line, "Config version", config_version); get_int(line, "serial-number", serial); get_int(line, "Radio channel:", radio_channel); - if (get_int(line, "Radio cal:", radio_calibration)) - System.out.printf("got radio cal %d\n", radio_calibration.get()); - if (get_int(line, "Frequency:", radio_frequency)) - System.out.printf("got radio freq %d\n", radio_frequency.get()); + get_int(line, "Radio cal:", radio_calibration); + get_int(line, "Frequency:", radio_frequency); get_int(line, "Radio setting:", radio_setting); get_string(line,"software-version", version); get_string(line,"product", product); @@ -205,7 +203,6 @@ public class AltosConfigTD implements ActionListener { break; } } - System.out.printf("config_version %s\n", config_version.get()); if (been_there) break; if (!config_version.get().equals("0.0")) diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index d0ed9325..ace245a0 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -291,7 +291,6 @@ public class AltosConfigureUI final UIManager.LookAndFeelInfo[] look_and_feels = UIManager.getInstalledLookAndFeels(); - System.out.printf("look_and_feels %d\n", look_and_feels.length); look_and_feel_value = new JComboBox(look_and_feels); DelegatingRenderer.install(look_and_feel_value); diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 4ab73a6d..66991d10 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -235,22 +235,17 @@ public class AltosFlashUI public void run() { ui.flash = flash; ui.update_rom_config_info(current_config); - System.out.printf("Done updating rom config info\n"); await_rom_config.release(); } }); - System.out.printf("Waiting for rom configuration updates\n"); await_rom_config.acquire(); - System.out.printf("Got rom config update\n"); if (ui.rom_config != null) { - System.out.printf("rom_config not null\n"); flash.set_romconfig(ui.rom_config); flash.flash(); } } catch (InterruptedException ee) { final Exception e = ee; - System.out.printf("exception %s\n", e.toString()); SwingUtilities.invokeLater(new Runnable() { public void run() { ui.exception(e); @@ -258,7 +253,6 @@ public class AltosFlashUI }); } catch (IOException ee) { final Exception e = ee; - System.out.printf("exception %s\n", e.toString()); SwingUtilities.invokeLater(new Runnable() { public void run() { ui.exception(e); @@ -266,7 +260,6 @@ public class AltosFlashUI }); } catch (AltosSerialInUseException ee) { final Exception e = ee; - System.out.printf("exception %s\n", e.toString()); SwingUtilities.invokeLater(new Runnable() { public void run() { ui.exception(e); diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index eb76243d..44481544 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -336,7 +336,6 @@ public class AltosLaunchUI public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); - System.out.printf("cmd %s\n", cmd); if (cmd.equals("armed") || cmd.equals("igniter")) { stop_arm_timer(); } -- cgit v1.2.3 From b5f6d4e5251a825395c93916afa3af659c678498 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jul 2012 19:15:32 -0700 Subject: altosui: Abstract remote connection timeout stuff This moves some of the logic for managing when to present the 'cancel' dialog for remote operations to altoslib. Signed-off-by: Keith Packard --- altoslib/AltosLink.java | 69 +++++++++++++++++++++++++++++++---- altosui/AltosSerial.java | 95 ++++++++++++++---------------------------------- 2 files changed, 88 insertions(+), 76 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index a39204ac..779c8496 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -60,16 +60,66 @@ public abstract class AltosLink { return null; } - public String get_reply(int timeout) throws InterruptedException { - try { - return get_reply_no_dialog(timeout); - } catch (TimeoutException te) { - return null; + public String get_reply() throws InterruptedException { + return get_reply(5000); + } + + + public abstract boolean can_cancel_reply(); + public abstract boolean show_reply_timeout(); + public abstract void hide_reply_timeout(); + + public boolean reply_abort; + public int in_reply; + + boolean reply_timeout_shown = false; + + private boolean check_reply_timeout() { + if (!reply_timeout_shown) + reply_timeout_shown = show_reply_timeout(); + return reply_abort; + } + + private void cleanup_reply_timeout() { + if (reply_timeout_shown) { + reply_timeout_shown = false; + hide_reply_timeout(); } } - public String get_reply() throws InterruptedException { - return get_reply(5000); + + public String get_reply(int timeout) throws InterruptedException { + boolean can_cancel = can_cancel_reply(); + String reply = null; + + if (!can_cancel && remote) + System.out.printf("Uh-oh, reading remote serial device from swing thread\n"); + + if (remote && can_cancel) + timeout = 500; + try { + ++in_reply; + + flush_output(); + + reply_abort = false; + reply_timeout_shown = false; + for (;;) { + AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); + if (line != null) { + cleanup_reply_timeout(); + reply = line.line; + break; + } + if (!remote || !can_cancel || check_reply_timeout()) { + reply = null; + break; + } + } + } finally { + --in_reply; + } + return reply; } public void add_telem(AltosLine line) throws InterruptedException { @@ -124,7 +174,10 @@ public abstract class AltosLink { public void flush_input() throws InterruptedException { - flush_input(100); + if (remote) + flush_input(500); + else + flush_input(100); } diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 8b60dd54..35704d40 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -102,21 +102,7 @@ public class AltosSerial extends AltosLink implements Runnable { } } - boolean abort; JDialog timeout_dialog; - boolean timeout_started = false; - - private void stop_timeout_dialog() { - if (timeout_started) { - timeout_started = false; - Runnable r = new Runnable() { - public void run() { - timeout_dialog.setVisible(false); - } - }; - SwingUtilities.invokeLater(r); - } - } private void start_timeout_dialog_internal() { @@ -135,69 +121,42 @@ public class AltosSerial extends AltosLink implements Runnable { if (o == null) return; if (options[0].equals(o)) - abort = true; + reply_abort = true; timeout_dialog.dispose(); timeout_dialog = null; } - private boolean check_timeout() { - if (!timeout_started && frame != null) { - if (!SwingUtilities.isEventDispatchThread()) { - timeout_started = true; - Runnable r = new Runnable() { - public void run() { - start_timeout_dialog_internal(); - } - }; - SwingUtilities.invokeLater(r); - } - } - return abort; - } + /* + * These are required by the AltosLink implementation + */ - public void flush_input() throws InterruptedException { - if (remote) - flush_input(500); - else - flush_input(100); + public boolean can_cancel_reply() { + /* + * Can cancel any replies not called from the dispatch thread + */ + return !SwingUtilities.isEventDispatchThread(); } - int in_reply; - - public String get_reply(int timeout) throws InterruptedException { - boolean can_cancel = true; - String reply = null; - - try { - ++in_reply; + public boolean show_reply_timeout() { + if (!SwingUtilities.isEventDispatchThread() && frame != null) { + Runnable r = new Runnable() { + public void run() { + start_timeout_dialog_internal(); + } + }; + SwingUtilities.invokeLater(r); + return true; + } + return false; + } - if (SwingUtilities.isEventDispatchThread()) { - can_cancel = false; - if (remote) - System.out.printf("Uh-oh, reading remote serial device from swing thread\n"); - } - flush_output(); - if (remote && can_cancel) { - timeout = 500; - } - abort = false; - timeout_started = false; - for (;;) { - AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS); - if (line != null) { - stop_timeout_dialog(); - reply = line.line; - break; + public void hide_reply_timeout() { + Runnable r = new Runnable() { + public void run() { + timeout_dialog.setVisible(false); } - if (!remote || !can_cancel || check_timeout()) { - reply = null; - break; - } - } - } finally { - --in_reply; - } - return reply; + }; + SwingUtilities.invokeLater(r); } public void close() { -- cgit v1.2.3 From 52196975c447851f14619213c1de5101d334eebc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 16 Jul 2012 15:35:11 -0700 Subject: altosui: Move serial datastream parser to altoslib instead of having it in altosui Signed-off-by: Keith Packard --- altoslib/AltosLink.java | 47 +++++++++++++++++++++++++++++++++++++++++++++++ altosui/AltosSerial.java | 42 ++---------------------------------------- 2 files changed, 49 insertions(+), 40 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index 779c8496..d59e73ba 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -24,6 +24,11 @@ import java.util.*; import java.text.*; public abstract class AltosLink { + + public final static int ERROR = -1; + public final static int TIMEOUT = -2; + + public abstract int getchar(); public abstract void print(String data); public abstract void close(); @@ -88,6 +93,48 @@ public abstract class AltosLink { } + public void run () { + int c; + byte[] line_bytes = null; + int line_count = 0; + + try { + for (;;) { + c = getchar(); + if (Thread.interrupted()) + break; + if (c == ERROR) { + add_telem (new AltosLine()); + add_reply (new AltosLine()); + break; + } + if (c == TIMEOUT) + continue; + if (c == '\r') + continue; + synchronized(this) { + if (c == '\n') { + if (line_count != 0) { + add_bytes(line_bytes, line_count); + line_count = 0; + } + } else { + if (line_bytes == null) { + line_bytes = new byte[256]; + } else if (line_count == line_bytes.length) { + byte[] new_line_bytes = new byte[line_count * 2]; + System.arraycopy(line_bytes, 0, new_line_bytes, 0, line_count); + line_bytes = new_line_bytes; + } + line_bytes[line_count] = (byte) c; + line_count++; + } + } + } + } catch (InterruptedException e) { + } + } + public String get_reply(int timeout) throws InterruptedException { boolean can_cancel = can_cancel_reply(); String reply = null; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 35704d40..c4e9c697 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -53,46 +53,8 @@ public class AltosSerial extends AltosLink implements Runnable { int line_count; Frame frame; - public void run () { - int c; - byte[] line_bytes = null; - int line_count = 0; - - try { - for (;;) { - c = libaltos.altos_getchar(altos, 0); - if (Thread.interrupted()) - break; - if (c == libaltosConstants.LIBALTOS_ERROR) { - add_telem (new AltosLine()); - add_reply (new AltosLine()); - break; - } - if (c == libaltosConstants.LIBALTOS_TIMEOUT) - continue; - if (c == '\r') - continue; - synchronized(this) { - if (c == '\n') { - if (line_count != 0) { - add_bytes(line_bytes, line_count); - line_count = 0; - } - } else { - if (line_bytes == null) { - line_bytes = new byte[256]; - } else if (line_count == line_bytes.length) { - byte[] new_line_bytes = new byte[line_count * 2]; - System.arraycopy(line_bytes, 0, new_line_bytes, 0, line_count); - line_bytes = new_line_bytes; - } - line_bytes[line_count] = (byte) c; - line_count++; - } - } - } - } catch (InterruptedException e) { - } + public int getchar() { + return libaltos.altos_getchar(altos, 0); } public void flush_output() { -- cgit v1.2.3 From eda636c5f309b85282b4142118ee65673d28d137 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 16 Jul 2012 15:36:20 -0700 Subject: altosui: Skip unknown data when parsing ADC for idle monitoring This resolves an infinite loop when talking to megametrum. Signed-off-by: Keith Packard --- altosui/AltosIdleMonitorUI.java | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index eb6ec5e7..ce608d2b 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -84,6 +84,7 @@ class AltosADC { i += 2; continue; } + i++; } break; } -- cgit v1.2.3 From f6921c9040b1f1fc4408d163532b0695a3611195 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 17 Jul 2012 21:04:23 -0700 Subject: altoslib: Move idle monitor managing code to altoslib More stuff to be shared (potentially) Signed-off-by: Keith Packard --- altoslib/AltosIdleMonitor.java | 445 +++++++++++++++++++++++++++++++++ altoslib/AltosIdleMonitorListener.java | 28 +++ altoslib/AltosIdleRecordTM.java | 268 ++++++++++++++++++++ altoslib/Makefile.am | 2 + altosui/AltosIdleMonitorUI.java | 266 +------------------- 5 files changed, 752 insertions(+), 257 deletions(-) create mode 100644 altoslib/AltosIdleMonitor.java create mode 100644 altoslib/AltosIdleMonitorListener.java create mode 100644 altoslib/AltosIdleRecordTM.java (limited to 'altosui') diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java new file mode 100644 index 00000000..cd518c28 --- /dev/null +++ b/altoslib/AltosIdleMonitor.java @@ -0,0 +1,445 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosSensorTM { + int tick; + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + + public AltosSensorTM(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + for (int i = 0; i < items.length;) { + if (items[i].equals("tick:")) { + tick = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("accel:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pres:")) { + pres = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + drogue = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + break; + } + } +} + +class AltosSensorMM { + int tick; + int sense[]; + int v_batt; + int v_pyro; + int accel; + int accel_ref; + + public AltosSensorMM(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + sense = new int[6]; + for (int i = 0; i < items.length;) { + if (items[i].equals("tick:")) { + tick = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("0:")) { + sense[0] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("1:")) { + sense[1] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("2:")) { + sense[2] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("3:")) { + sense[3] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("4:")) { + sense[4] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("5:")) { + sense[5] = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("6:")) { + v_batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("7:")) { + v_pyro = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("8:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("9:")) { + accel_ref = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + for (int i = 0; i < sense.length; i++) + System.out.printf("sense[%d]: %d\n", i, sense[i]); + break; + } + } +} + +class AltosIMUQuery extends AltosIMU { + + public AltosIMUQuery (AltosLink link) throws InterruptedException, TimeoutException { + link.printf("I\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("Accel:")) + continue; + String[] items = line.split("\\s+"); + if (items.length >= 8) { + accel_x = Integer.parseInt(items[1]); + accel_y = Integer.parseInt(items[2]); + accel_z = Integer.parseInt(items[3]); + gyro_x = Integer.parseInt(items[5]); + gyro_y = Integer.parseInt(items[6]); + gyro_z = Integer.parseInt(items[7]); + } + break; + } + } +} + +class AltosMs5607Query extends AltosMs5607 { + public AltosMs5607Query (AltosLink link) throws InterruptedException, TimeoutException { + link.printf("v\nB\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + String[] items = line.split("\\s+"); + if (line.startsWith("Pressure:")) { + if (items.length >= 2) + raw_pres = Integer.parseInt(items[1]); + } else if (line.startsWith("Temperature:")) { + if (items.length >= 2) + raw_temp = Integer.parseInt(items[1]); + } else if (line.startsWith("ms5607 reserved:")) { + if (items.length >= 3) + reserved = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 sens:")) { + if (items.length >= 3) + sens = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 off:")) { + if (items.length >= 3) + off = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tcs:")) { + if (items.length >= 3) + tcs = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tco:")) { + if (items.length >= 3) + tco = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tref:")) { + if (items.length >= 3) + tref = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 tempsens:")) { + if (items.length >= 3) + tempsens = Integer.parseInt(items[2]); + } else if (line.startsWith("ms5607 crc:")) { + if (items.length >= 3) + crc = Integer.parseInt(items[2]); + } else if (line.startsWith("Altitude")) + break; + } + convert(); + } +} + +class AltosGPSQuery extends AltosGPS { + public AltosGPSQuery (AltosLink link, AltosConfigData config_data) + throws TimeoutException, InterruptedException { + boolean says_done = config_data.compare_version("1.0") >= 0; + link.printf("g\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] bits = line.split("\\s+"); + if (bits.length == 0) + continue; + if (line.startsWith("Date:")) { + if (bits.length < 2) + continue; + String[] d = bits[1].split(":"); + if (d.length < 3) + continue; + year = Integer.parseInt(d[0]) + 2000; + month = Integer.parseInt(d[1]); + day = Integer.parseInt(d[2]); + continue; + } + if (line.startsWith("Time:")) { + if (bits.length < 2) + continue; + String[] d = bits[1].split("/"); + if (d.length < 3) + continue; + hour = Integer.parseInt(d[0]); + minute = Integer.parseInt(d[1]); + second = Integer.parseInt(d[2]); + continue; + } + if (line.startsWith("Lat/Lon:")) { + if (bits.length < 3) + continue; + lat = Integer.parseInt(bits[1]) * 1.0e-7; + lon = Integer.parseInt(bits[2]) * 1.0e-7; + continue; + } + if (line.startsWith("Alt:")) { + if (bits.length < 2) + continue; + alt = Integer.parseInt(bits[1]); + continue; + } + if (line.startsWith("Flags:")) { + if (bits.length < 2) + continue; + int status = Integer.decode(bits[1]); + connected = (status & AltosLib.AO_GPS_RUNNING) != 0; + locked = (status & AltosLib.AO_GPS_VALID) != 0; + if (!says_done) + break; + continue; + } + if (line.startsWith("Sats:")) { + if (bits.length < 2) + continue; + nsat = Integer.parseInt(bits[1]); + cc_gps_sat = new AltosGPSSat[nsat]; + for (int i = 0; i < nsat; i++) { + int svid = Integer.parseInt(bits[2+i*2]); + int cc_n0 = Integer.parseInt(bits[3+i*2]); + cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0); + } + } + if (line.startsWith("done")) + break; + if (line.startsWith("Syntax error")) + break; + } + } +} + +public class AltosIdleMonitor extends Thread { + AltosLink link; + AltosIdleMonitorListener listener; + AltosState state; + boolean remote; + double frequency; + AltosState previous_state; + AltosConfigData config_data; + AltosGPS gps; + + int AltosRSSI() throws TimeoutException, InterruptedException { + link.printf("s\n"); + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + if (items.length < 2) + return 0; + if (!items[0].equals("RSSI:")) + return 0; + int rssi = Integer.parseInt(items[1]); + return rssi; + } + + void update_state() throws InterruptedException, TimeoutException { + AltosRecord record; + int rssi; + + try { + if (remote) { + link.set_radio_frequency(frequency); + link.start_remote(); + } else + link.flush_input(); + config_data = new AltosConfigData(link); + if (config_data.product.startsWith("TeleMetrum")) { + AltosRecordTM record_tm = new AltosRecordTM(); + AltosSensorTM sensor = new AltosSensorTM(link); + record_tm.accel = sensor.accel; + record_tm.pres = sensor.pres; + record_tm.batt = sensor.batt; + record_tm.temp = sensor.temp; + record_tm.drogue = sensor.drogue; + record_tm.main = sensor.main; + record_tm.ground_accel = record_tm.accel; + record_tm.ground_pres = record_tm.pres; + record_tm.accel_plus_g = config_data.accel_cal_plus; + record_tm.accel_minus_g = config_data.accel_cal_minus; + record_tm.tick = sensor.tick; + record = record_tm; + } else if (config_data.product.startsWith("MegaMetrum")) { + AltosRecordMM record_mm = new AltosRecordMM(); + AltosSensorMM sensor = new AltosSensorMM(link); + AltosMs5607 ms5607 = new AltosMs5607Query(link); + AltosIMU imu = new AltosIMUQuery(link); + + record_mm.accel_plus_g = config_data.accel_cal_plus; + record_mm.accel_minus_g = config_data.accel_cal_minus; + + record_mm.ground_accel = sensor.accel; + record_mm.accel = sensor.accel; + record_mm.ground_pres = ms5607.pa; + record_mm.pres = ms5607.pa; + record_mm.temp = ms5607.cc; + + record_mm.v_batt = sensor.v_batt; + record_mm.v_pyro = sensor.v_pyro; + record_mm.sense = sensor.sense; + + record_mm.imu = imu; + + record = record_mm; + } else + record = new AltosRecord(); + + gps = new AltosGPSQuery(link, config_data); + } finally { + if (remote) { + link.stop_remote(); + rssi = AltosRSSI(); + } else + rssi = 0; + } + + record.version = 0; + record.callsign = config_data.callsign; + record.serial = config_data.serial; + record.flight = config_data.log_available() > 0 ? 255 : 0; + record.rssi = rssi; + record.status = 0; + record.state = AltosLib.ao_flight_idle; + + record.gps = gps; + state = new AltosState (record, state); + } + + public void set_frequency(double in_frequency) { + frequency = in_frequency; + } + + public void post_state() { + listener.update(state); + } + + public void run() { + try { + for (;;) { + try { + update_state(); + post_state(); + } catch (TimeoutException te) { + } + Thread.sleep(1000); + } + } catch (InterruptedException ie) { + link.close(); + } + } + + public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) + throws FileNotFoundException, InterruptedException, TimeoutException { + listener = in_listener; + link = in_link; + remote = in_remote; + state = null; + } +} diff --git a/altoslib/AltosIdleMonitorListener.java b/altoslib/AltosIdleMonitorListener.java new file mode 100644 index 00000000..3c18bfaa --- /dev/null +++ b/altoslib/AltosIdleMonitorListener.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +public interface AltosIdleMonitorListener { + public void update(AltosState state); +} \ No newline at end of file diff --git a/altoslib/AltosIdleRecordTM.java b/altoslib/AltosIdleRecordTM.java new file mode 100644 index 00000000..112b847e --- /dev/null +++ b/altoslib/AltosIdleRecordTM.java @@ -0,0 +1,268 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosLib; + +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +class AltosADCTM { + int tick; + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + + public AltosADCTM(AltosLink link) throws InterruptedException, TimeoutException { + link.printf("a\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) { + throw new TimeoutException(); + } + if (!line.startsWith("tick:")) + continue; + String[] items = line.split("\\s+"); + for (int i = 0; i < items.length;) { + if (items[i].equals("tick:")) { + tick = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("accel:")) { + accel = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("pres:")) { + pres = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("temp:")) { + temp = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("drogue:")) { + drogue = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("main:")) { + main = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + break; + } + } +} + +class AltosGPSQuery extends AltosGPS { + public AltosGPSQuery (AltosLink link, AltosConfigData config_data) + throws TimeoutException, InterruptedException { + boolean says_done = config_data.compare_version("1.0") >= 0; + link.printf("g\n"); + for (;;) { + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] bits = line.split("\\s+"); + if (bits.length == 0) + continue; + if (line.startsWith("Date:")) { + if (bits.length < 2) + continue; + String[] d = bits[1].split(":"); + if (d.length < 3) + continue; + year = Integer.parseInt(d[0]) + 2000; + month = Integer.parseInt(d[1]); + day = Integer.parseInt(d[2]); + continue; + } + if (line.startsWith("Time:")) { + if (bits.length < 2) + continue; + String[] d = bits[1].split("/"); + if (d.length < 3) + continue; + hour = Integer.parseInt(d[0]); + minute = Integer.parseInt(d[1]); + second = Integer.parseInt(d[2]); + continue; + } + if (line.startsWith("Lat/Lon:")) { + if (bits.length < 3) + continue; + lat = Integer.parseInt(bits[1]) * 1.0e-7; + lon = Integer.parseInt(bits[2]) * 1.0e-7; + continue; + } + if (line.startsWith("Alt:")) { + if (bits.length < 2) + continue; + alt = Integer.parseInt(bits[1]); + continue; + } + if (line.startsWith("Flags:")) { + if (bits.length < 2) + continue; + int status = Integer.decode(bits[1]); + connected = (status & AltosLib.AO_GPS_RUNNING) != 0; + locked = (status & AltosLib.AO_GPS_VALID) != 0; + if (!says_done) + break; + continue; + } + if (line.startsWith("Sats:")) { + if (bits.length < 2) + continue; + nsat = Integer.parseInt(bits[1]); + cc_gps_sat = new AltosGPSSat[nsat]; + for (int i = 0; i < nsat; i++) { + int svid = Integer.parseInt(bits[2+i*2]); + int cc_n0 = Integer.parseInt(bits[3+i*2]); + cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0); + } + } + if (line.startsWith("done")) + break; + if (line.startsWith("Syntax error")) + break; + } + } +} + +public class AltosIdleMonitor extends Thread { + AltosLink link; + AltosIdleMonitorListener listener; + AltosState state; + boolean remote; + double frequency; + AltosState previous_state; + AltosConfigData config_data; + AltosADC adc; + AltosGPS gps; + + int AltosRSSI() throws TimeoutException, InterruptedException { + link.printf("s\n"); + String line = link.get_reply_no_dialog(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + if (items.length < 2) + return 0; + if (!items[0].equals("RSSI:")) + return 0; + int rssi = Integer.parseInt(items[1]); + return rssi; + } + + void update_state() throws InterruptedException, TimeoutException { + AltosRecordTM record = new AltosRecordTM(); + int rssi; + + try { + if (remote) { + link.set_radio_frequency(frequency); + link.start_remote(); + } else + link.flush_input(); + config_data = new AltosConfigData(link); + adc = new AltosADC(link); + gps = new AltosGPSQuery(link, config_data); + } finally { + if (remote) { + link.stop_remote(); + rssi = AltosRSSI(); + } else + rssi = 0; + } + + record.version = 0; + record.callsign = config_data.callsign; + record.serial = config_data.serial; + record.flight = config_data.log_available() > 0 ? 255 : 0; + record.rssi = rssi; + record.status = 0; + record.state = AltosLib.ao_flight_idle; + + record.tick = adc.tick; + + record.accel = adc.accel; + record.pres = adc.pres; + record.batt = adc.batt; + record.temp = adc.temp; + record.drogue = adc.drogue; + record.main = adc.main; + + record.ground_accel = record.accel; + record.ground_pres = record.pres; + record.accel_plus_g = config_data.accel_cal_plus; + record.accel_minus_g = config_data.accel_cal_minus; + record.acceleration = 0; + record.speed = 0; + record.height = 0; + record.gps = gps; + state = new AltosState (record, state); + } + + public void set_frequency(double in_frequency) { + frequency = in_frequency; + } + + public void post_state() { + listener.update(state); + } + + public void run() { + try { + for (;;) { + try { + update_state(); + post_state(); + } catch (TimeoutException te) { + } + Thread.sleep(1000); + } + } catch (InterruptedException ie) { + link.close(); + } + } + + public AltosIdleMonitor(AltosIdleMonitorListener in_listener, AltosLink in_link, boolean in_remote) + throws FileNotFoundException, InterruptedException, TimeoutException { + listener = in_listener; + link = in_link; + remote = in_remote; + state = null; + } +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index ac97c9cb..a39623ee 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -27,6 +27,8 @@ AltosLib_JAVA = \ $(SRC)/AltosGPS.java \ $(SRC)/AltosGPSSat.java \ $(SRC)/AltosGreatCircle.java \ + $(SRC)/AltosIdleMonitor.java \ + $(SRC)/AltosIdleMonitorListener.java \ $(SRC)/AltosLine.java \ $(SRC)/AltosLink.java \ $(SRC)/AltosLog.java \ diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index ce608d2b..46ca3e5d 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -29,260 +29,7 @@ import java.util.prefs.*; import java.util.concurrent.*; import org.altusmetrum.AltosLib.*; -class AltosADC { - int tick; - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; - - public AltosADC(AltosSerial serial) throws InterruptedException, TimeoutException { - serial.printf("a\n"); - for (;;) { - String line = serial.get_reply_no_dialog(5000); - if (line == null) { - throw new TimeoutException(); - } - if (!line.startsWith("tick:")) - continue; - String[] items = line.split("\\s+"); - for (int i = 0; i < items.length;) { - if (items[i].equals("tick:")) { - tick = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("accel:")) { - accel = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("pres:")) { - pres = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("temp:")) { - temp = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("batt:")) { - batt = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("drogue:")) { - drogue = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - if (items[i].equals("main:")) { - main = Integer.parseInt(items[i+1]); - i += 2; - continue; - } - i++; - } - break; - } - } -} - -class AltosGPSQuery extends AltosGPS { - public AltosGPSQuery (AltosSerial serial, AltosConfigData config_data) - throws TimeoutException, InterruptedException { - boolean says_done = config_data.compare_version("1.0") >= 0; - serial.printf("g\n"); - for (;;) { - String line = serial.get_reply_no_dialog(5000); - if (line == null) - throw new TimeoutException(); - String[] bits = line.split("\\s+"); - if (bits.length == 0) - continue; - if (line.startsWith("Date:")) { - if (bits.length < 2) - continue; - String[] d = bits[1].split(":"); - if (d.length < 3) - continue; - year = Integer.parseInt(d[0]) + 2000; - month = Integer.parseInt(d[1]); - day = Integer.parseInt(d[2]); - continue; - } - if (line.startsWith("Time:")) { - if (bits.length < 2) - continue; - String[] d = bits[1].split("/"); - if (d.length < 3) - continue; - hour = Integer.parseInt(d[0]); - minute = Integer.parseInt(d[1]); - second = Integer.parseInt(d[2]); - continue; - } - if (line.startsWith("Lat/Lon:")) { - if (bits.length < 3) - continue; - lat = Integer.parseInt(bits[1]) * 1.0e-7; - lon = Integer.parseInt(bits[2]) * 1.0e-7; - continue; - } - if (line.startsWith("Alt:")) { - if (bits.length < 2) - continue; - alt = Integer.parseInt(bits[1]); - continue; - } - if (line.startsWith("Flags:")) { - if (bits.length < 2) - continue; - int status = Integer.decode(bits[1]); - connected = (status & Altos.AO_GPS_RUNNING) != 0; - locked = (status & Altos.AO_GPS_VALID) != 0; - if (!says_done) - break; - continue; - } - if (line.startsWith("Sats:")) { - if (bits.length < 2) - continue; - nsat = Integer.parseInt(bits[1]); - cc_gps_sat = new AltosGPSSat[nsat]; - for (int i = 0; i < nsat; i++) { - int svid = Integer.parseInt(bits[2+i*2]); - int cc_n0 = Integer.parseInt(bits[3+i*2]); - cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0); - } - } - if (line.startsWith("done")) - break; - if (line.startsWith("Syntax error")) - break; - } - } -} - -class AltosIdleMonitor extends Thread { - AltosDevice device; - AltosSerial serial; - AltosIdleMonitorUI ui; - AltosState state; - boolean remote; - double frequency; - AltosState previous_state; - AltosConfigData config_data; - AltosADC adc; - AltosGPS gps; - - int AltosRSSI() throws TimeoutException, InterruptedException { - serial.printf("s\n"); - String line = serial.get_reply_no_dialog(5000); - if (line == null) - throw new TimeoutException(); - String[] items = line.split("\\s+"); - if (items.length < 2) - return 0; - if (!items[0].equals("RSSI:")) - return 0; - int rssi = Integer.parseInt(items[1]); - return rssi; - } - - void update_state() throws InterruptedException, TimeoutException { - AltosRecordTM record = new AltosRecordTM(); - int rssi; - - try { - if (remote) { - serial.set_radio_frequency(frequency); - serial.start_remote(); - } else - serial.flush_input(); - config_data = new AltosConfigData(serial); - adc = new AltosADC(serial); - gps = new AltosGPSQuery(serial, config_data); - } finally { - if (remote) { - serial.stop_remote(); - rssi = AltosRSSI(); - } else - rssi = 0; - } - - record.version = 0; - record.callsign = config_data.callsign; - record.serial = config_data.serial; - record.flight = config_data.log_available() > 0 ? 255 : 0; - record.rssi = rssi; - record.status = 0; - record.state = Altos.ao_flight_idle; - - record.tick = adc.tick; - - record.accel = adc.accel; - record.pres = adc.pres; - record.batt = adc.batt; - record.temp = adc.temp; - record.drogue = adc.drogue; - record.main = adc.main; - - record.ground_accel = record.accel; - record.ground_pres = record.pres; - record.accel_plus_g = config_data.accel_cal_plus; - record.accel_minus_g = config_data.accel_cal_minus; - record.acceleration = 0; - record.speed = 0; - record.height = 0; - record.gps = gps; - state = new AltosState (record, state); - } - - void set_frequency(double in_frequency) { - frequency = in_frequency; - } - - public void post_state() { - Runnable r = new Runnable() { - public void run() { - ui.update(state); - } - }; - SwingUtilities.invokeLater(r); - } - - public void run() { - try { - for (;;) { - try { - update_state(); - post_state(); - } catch (TimeoutException te) { - if (AltosSerial.debug) - System.out.printf ("monitor idle data timeout\n"); - } - Thread.sleep(1000); - } - } catch (InterruptedException ie) { - serial.close(); - } - } - - public AltosIdleMonitor(AltosIdleMonitorUI in_ui, AltosDevice in_device, boolean in_remote) - throws FileNotFoundException, AltosSerialInUseException, InterruptedException, TimeoutException { - device = in_device; - ui = in_ui; - serial = new AltosSerial(device); - remote = in_remote; - state = null; - } -} - -public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener { +public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay, AltosFontListener, AltosIdleMonitorListener { AltosDevice device; JTabbedPane pane; AltosPad pad; @@ -333,8 +80,13 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay } } - public void update(AltosState state) { - show (state, 0); + public void update(final AltosState state) { + Runnable r = new Runnable() { + public void run() { + show(state, 0); + } + }; + SwingUtilities.invokeLater(r); } Container bag; @@ -427,7 +179,7 @@ public class AltosIdleMonitorUI extends AltosFrame implements AltosFlightDisplay pack(); setVisible(true); - thread = new AltosIdleMonitor(this, device, remote); + thread = new AltosIdleMonitor((AltosIdleMonitorListener) this, (AltosLink) new AltosSerial (device), (boolean) remote); status_update = new AltosFlightStatusUpdate(flightStatus); -- cgit v1.2.3 From 700818c8ff0518e79bff2f0e80b2cc3cb3b48bf0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 17 Jul 2012 21:04:58 -0700 Subject: altosui: Accept variations in spacing for igniter status reply Megametrum uses different white space; just deal with it here. Signed-off-by: Keith Packard --- altosui/AltosIgnite.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java index 45d37d16..f84db0b9 100644 --- a/altosui/AltosIgnite.java +++ b/altosui/AltosIgnite.java @@ -110,12 +110,23 @@ public class AltosIgnite { String line = serial.get_reply(5000); if (line == null) throw new TimeoutException(); - if (get_string(line, "Igniter: drogue Status: ", status_name)) + String[] items = line.split("\\s+"); + + if (items.length < 4) + continue; + + if (!items[0].equals("Igniter:")) + continue; + + if (!items[2].equals("Status:")) + continue; + + if (items[1].equals("drogue")) { if (igniter == Apogee) - status = status(status_name.get()); - if (get_string(line, "Igniter: main Status: ", status_name)) { + status = status(items[3]); + } else if (items[1].equals("main")) { if (igniter == Main) - status = status(status_name.get()); + status = status(items[3]); break; } } -- cgit v1.2.3 From f164e48cbeff521d45737794e2046a08322951d6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 18 Jul 2012 00:01:51 -0700 Subject: altosui: Make scan UI handle incremental telem data The new telem format doesn't send everything in each telem packet, so we need to handle updating information incrementally in the scan results. This involved clearing old scan data when switching frequencies and then updating existing entries with new data as it arrives. Signed-off-by: Keith Packard --- altoslib/AltosIdleMonitor.java | 2 -- altoslib/AltosTelemetryReader.java | 5 +++++ altosui/AltosScanUI.java | 42 +++++++++++++++++++++++++++++--------- 3 files changed, 37 insertions(+), 12 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index cd518c28..57c4da71 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -162,8 +162,6 @@ class AltosSensorMM { } i++; } - for (int i = 0; i < sense.length; i++) - System.out.printf("sense[%d]: %d\n", i, sense[i]); break; } } diff --git a/altoslib/AltosTelemetryReader.java b/altoslib/AltosTelemetryReader.java index 911a099a..bdb44eef 100644 --- a/altoslib/AltosTelemetryReader.java +++ b/altoslib/AltosTelemetryReader.java @@ -44,6 +44,11 @@ public class AltosTelemetryReader extends AltosFlightReader { telem.clear(); } + public void reset() { + previous = null; + flush(); + } + public void close(boolean interrupted) { link.remove_monitor(telem); log.close(); diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 44eeda6d..ef6389b6 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -59,29 +59,50 @@ class AltosScanResult { } public boolean equals(AltosScanResult other) { - return (callsign.equals(other.callsign) && - serial == other.serial && - flight == other.flight && + return (serial == other.serial && frequency.frequency == other.frequency.frequency && telemetry == other.telemetry); } + + public boolean up_to_date(AltosScanResult other) { + if (flight == 0 && other.flight != 0) { + flight = other.flight; + return false; + } + if (callsign.equals("N0CALL") && !other.callsign.equals("N0CALL")) { + callsign = other.callsign; + return false; + } + return true; + } } class AltosScanResults extends LinkedList implements ListModel { LinkedList listeners = new LinkedList(); + void changed(ListDataEvent de) { + for (ListDataListener l : listeners) + l.contentsChanged(de); + } + public boolean add(AltosScanResult r) { - for (AltosScanResult old : this) - if (old.equals(r)) + int i = 0; + for (AltosScanResult old : this) { + if (old.equals(r)) { + if (!old.up_to_date(r)) + changed (new ListDataEvent(this, + ListDataEvent.CONTENTS_CHANGED, + i, i)); return true; + } + i++; + } super.add(r); - ListDataEvent de = new ListDataEvent(this, - ListDataEvent.INTERVAL_ADDED, - this.size() - 2, this.size() - 1); - for (ListDataListener l : listeners) - l.contentsChanged(de); + changed(new ListDataEvent(this, + ListDataEvent.INTERVAL_ADDED, + this.size() - 2, this.size() - 1)); return true; } @@ -205,6 +226,7 @@ public class AltosScanUI void set_frequency() throws InterruptedException, TimeoutException { reader.set_frequency(frequencies[frequency_index].frequency); + reader.reset(); } void next() throws InterruptedException, TimeoutException { -- cgit v1.2.3 From 15ebd9c75aa57572040e3b1ee41e6f3eb8cf92ee Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 19 Jul 2012 09:46:20 -0700 Subject: altosui: Delay starting KML output for flight and GPS coords Don't start outputing KML data until the telem record containing flight number and GPS coordinates are present. Signed-off-by: Keith Packard --- altosui/AltosKML.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'altosui') diff --git a/altosui/AltosKML.java b/altosui/AltosKML.java index 2993607b..ff0734b8 100644 --- a/altosui/AltosKML.java +++ b/altosui/AltosKML.java @@ -133,6 +133,12 @@ public class AltosKML implements AltosWriter { if (gps == null) return; + if ((record.seen & (AltosRecord.seen_flight)) == 0) + return; + if ((record.seen & (AltosRecord.seen_gps_lat)) == 0) + return; + if ((record.seen & (AltosRecord.seen_gps_lon)) == 0) + return; if (!started) { start(record); started = true; -- cgit v1.2.3 From 233ab58df8ac8e1fdeab8d4c2f6c8c9d3f6e7be1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 22 Jul 2012 11:53:44 -0700 Subject: altosui: Move AltosIgnite.java to altoslib To be shared with altosdroid eventually Signed-off-by: Keith Packard --- altoslib/AltosIgnite.java | 180 +++++++++++++++++++++++++++++++++++++++++ altoslib/Makefile.am | 1 + altosui/AltosIgnite.java | 195 --------------------------------------------- altosui/AltosIgniteUI.java | 7 +- altosui/Makefile.am | 1 - 5 files changed, 186 insertions(+), 198 deletions(-) create mode 100644 altoslib/AltosIgnite.java delete mode 100644 altosui/AltosIgnite.java (limited to 'altosui') diff --git a/altoslib/AltosIgnite.java b/altoslib/AltosIgnite.java new file mode 100644 index 00000000..cc814337 --- /dev/null +++ b/altoslib/AltosIgnite.java @@ -0,0 +1,180 @@ +/* + * 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.AltosLib; + +import java.io.*; +import java.util.concurrent.*; + +public class AltosIgnite { + AltosLink link; + boolean remote; + boolean link_started; + + public final static int None = 0; + public final static int Apogee = 1; + public final static int Main = 2; + + public final static int Unknown = 0; + public final static int Ready = 1; + public final static int Active = 2; + public final static int Open = 3; + + private void start_link() throws InterruptedException, TimeoutException { + link_started = true; + if (remote) + link.start_remote(); + } + + private void stop_link() throws InterruptedException { + if (!link_started) + return; + link_started = false; + if (link == null) + return; + if (remote) + link.stop_remote(); + } + + class string_ref { + String value; + + public String get() { + return value; + } + public void set(String i) { + value = i; + } + public string_ref() { + value = null; + } + } + + private boolean get_string(String line, String label, string_ref s) { + if (line.startsWith(label)) { + String quoted = line.substring(label.length()).trim(); + + if (quoted.startsWith("\"")) + quoted = quoted.substring(1); + if (quoted.endsWith("\"")) + quoted = quoted.substring(0,quoted.length()-1); + s.set(quoted); + return true; + } else { + return false; + } + } + + private int status(String status_name) { + if (status_name.equals("unknown")) + return Unknown; + if (status_name.equals("ready")) + return Ready; + if (status_name.equals("active")) + return Active; + if (status_name.equals("open")) + return Open; + return Unknown; + } + + public int status(int igniter) throws InterruptedException, TimeoutException { + int status = Unknown; + if (link == null) + return status; + string_ref status_name = new string_ref(); + try { + start_link(); + link.printf("t\n"); + for (;;) { + String line = link.get_reply(5000); + if (line == null) + throw new TimeoutException(); + String[] items = line.split("\\s+"); + + if (items.length < 4) + continue; + + if (!items[0].equals("Igniter:")) + continue; + + if (!items[2].equals("Status:")) + continue; + + if (items[1].equals("drogue")) { + if (igniter == Apogee) + status = status(items[3]); + } else if (items[1].equals("main")) { + if (igniter == Main) + status = status(items[3]); + break; + } + } + } finally { + stop_link(); + } + return status; + } + + public static String status_string(int status) { + switch (status) { + case Unknown: return "Unknown"; + case Ready: return "Ready"; + case Active: return "Active"; + case Open: return "Open"; + default: return "Unknown"; + } + } + + public void fire(int igniter) { + if (link == null) + return; + try { + start_link(); + switch (igniter) { + case Main: + link.printf("i DoIt main\n"); + break; + case Apogee: + link.printf("i DoIt drogue\n"); + break; + } + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + } finally { + try { + stop_link(); + } catch (InterruptedException ie) { + } + } + } + + public void close() { + try { + stop_link(); + } catch (InterruptedException ie) { + } + link.close(); + link = null; + } + + public AltosIgnite(AltosLink in_link, boolean in_remote) + throws FileNotFoundException, TimeoutException, InterruptedException { + + link = in_link; + remote = in_remote; + } +} \ No newline at end of file diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index a39623ee..1f42140b 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -29,6 +29,7 @@ AltosLib_JAVA = \ $(SRC)/AltosGreatCircle.java \ $(SRC)/AltosIdleMonitor.java \ $(SRC)/AltosIdleMonitorListener.java \ + $(SRC)/AltosIgnite.java \ $(SRC)/AltosLine.java \ $(SRC)/AltosLink.java \ $(SRC)/AltosLog.java \ diff --git a/altosui/AltosIgnite.java b/altosui/AltosIgnite.java deleted file mode 100644 index f84db0b9..00000000 --- a/altosui/AltosIgnite.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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 altosui; - -import java.io.*; -import java.util.concurrent.*; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.table.*; -import javax.swing.event.*; -import org.altusmetrum.AltosLib.*; - -public class AltosIgnite { - AltosDevice device; - AltosSerial serial; - boolean remote; - boolean serial_started; - final static int None = 0; - final static int Apogee = 1; - final static int Main = 2; - - final static int Unknown = 0; - final static int Ready = 1; - final static int Active = 2; - final static int Open = 3; - - private void start_serial() throws InterruptedException, TimeoutException { - serial_started = true; - if (remote) - serial.start_remote(); - } - - private void stop_serial() throws InterruptedException { - if (!serial_started) - return; - serial_started = false; - if (serial == null) - return; - if (remote) - serial.stop_remote(); - } - - class string_ref { - String value; - - public String get() { - return value; - } - public void set(String i) { - value = i; - } - public string_ref() { - value = null; - } - } - - private boolean get_string(String line, String label, string_ref s) { - if (line.startsWith(label)) { - String quoted = line.substring(label.length()).trim(); - - if (quoted.startsWith("\"")) - quoted = quoted.substring(1); - if (quoted.endsWith("\"")) - quoted = quoted.substring(0,quoted.length()-1); - s.set(quoted); - return true; - } else { - return false; - } - } - - private int status(String status_name) { - if (status_name.equals("unknown")) - return Unknown; - if (status_name.equals("ready")) - return Ready; - if (status_name.equals("active")) - return Active; - if (status_name.equals("open")) - return Open; - return Unknown; - } - - public int status(int igniter) throws InterruptedException, TimeoutException { - int status = Unknown; - if (serial == null) - return status; - string_ref status_name = new string_ref(); - try { - start_serial(); - serial.printf("t\n"); - for (;;) { - String line = serial.get_reply(5000); - if (line == null) - throw new TimeoutException(); - String[] items = line.split("\\s+"); - - if (items.length < 4) - continue; - - if (!items[0].equals("Igniter:")) - continue; - - if (!items[2].equals("Status:")) - continue; - - if (items[1].equals("drogue")) { - if (igniter == Apogee) - status = status(items[3]); - } else if (items[1].equals("main")) { - if (igniter == Main) - status = status(items[3]); - break; - } - } - } finally { - stop_serial(); - } - return status; - } - - public static String status_string(int status) { - switch (status) { - case Unknown: return "Unknown"; - case Ready: return "Ready"; - case Active: return "Active"; - case Open: return "Open"; - default: return "Unknown"; - } - } - - public void fire(int igniter) { - if (serial == null) - return; - try { - start_serial(); - switch (igniter) { - case Main: - serial.printf("i DoIt main\n"); - break; - case Apogee: - serial.printf("i DoIt drogue\n"); - break; - } - } catch (InterruptedException ie) { - } catch (TimeoutException te) { - } finally { - try { - stop_serial(); - } catch (InterruptedException ie) { - } - } - } - - public void close() { - try { - stop_serial(); - } catch (InterruptedException ie) { - } - serial.close(); - serial = null; - } - - public void set_frame(Frame frame) { - serial.set_frame(frame); - } - - public AltosIgnite(AltosDevice in_device) - throws FileNotFoundException, AltosSerialInUseException, TimeoutException, InterruptedException { - - device = in_device; - serial = new AltosSerial(device); - remote = false; - - if (!device.matchProduct(Altos.product_altimeter)) - remote = true; - } -} \ No newline at end of file diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 076d99b2..78eba8e6 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -72,12 +72,15 @@ public class AltosIgniteUI public void run () { try { - ignite = new AltosIgnite(device); + AltosSerial serial = new AltosSerial(device); + serial.set_frame(owner); + ignite = new AltosIgnite(serial, + !device.matchProduct(Altos.product_altimeter)); + } catch (Exception e) { send_exception(e); return; } - ignite.set_frame(owner); for (;;) { Runnable r; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 1c8ea491..19db6698 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -55,7 +55,6 @@ altosui_JAVA = \ AltosHexfile.java \ Altos.java \ AltosIdleMonitorUI.java \ - AltosIgnite.java \ AltosIgniteUI.java \ AltosLaunch.java \ AltosLaunchUI.java \ -- cgit v1.2.3 From 0bf21399d3d47d58410df4c6ce89fc20fcd42c89 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 29 Jul 2012 19:34:00 -0700 Subject: altosui: Handle Monitor Idle errors better Deal with missing data by checking for MISSING in more places. Handle serial communication failures during send by reporting back from libaltos. Signed-off-by: Keith Packard --- altoslib/AltosIdleMonitor.java | 67 +++++++++++++++++------------------------- altoslib/AltosLink.java | 20 +++++++++++-- altoslib/AltosRecord.java | 2 +- altoslib/AltosRecordTM.java | 16 +++++----- altoslib/AltosState.java | 2 ++ altosui/AltosSerial.java | 14 +++++++-- altosui/libaltos/libaltos.c | 4 +-- 7 files changed, 70 insertions(+), 55 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index 57c4da71..27ea3a2b 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -23,16 +23,10 @@ import java.text.*; import java.util.prefs.*; import java.util.concurrent.*; -class AltosSensorTM { - int tick; - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; +class AltosSensorTM extends AltosRecordTM { - public AltosSensorTM(AltosLink link) throws InterruptedException, TimeoutException { + public AltosSensorTM(AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException { + super(); link.printf("a\n"); for (;;) { String line = link.get_reply_no_dialog(5000); @@ -82,6 +76,10 @@ class AltosSensorTM { } break; } + ground_accel = config_data.accel_cal_plus; + ground_pres = pres; + accel_plus_g = config_data.accel_cal_plus; + accel_minus_g = config_data.accel_cal_minus; } } @@ -253,7 +251,7 @@ class AltosGPSQuery extends AltosGPS { if (line.startsWith("Date:")) { if (bits.length < 2) continue; - String[] d = bits[1].split(":"); + String[] d = bits[1].split("/"); if (d.length < 3) continue; year = Integer.parseInt(d[0]) + 2000; @@ -264,7 +262,7 @@ class AltosGPSQuery extends AltosGPS { if (line.startsWith("Time:")) { if (bits.length < 2) continue; - String[] d = bits[1].split("/"); + String[] d = bits[1].split(":"); if (d.length < 3) continue; hour = Integer.parseInt(d[0]); @@ -339,8 +337,7 @@ public class AltosIdleMonitor extends Thread { } void update_state() throws InterruptedException, TimeoutException { - AltosRecord record; - int rssi; + AltosRecord record = null; try { if (remote) { @@ -350,20 +347,7 @@ public class AltosIdleMonitor extends Thread { link.flush_input(); config_data = new AltosConfigData(link); if (config_data.product.startsWith("TeleMetrum")) { - AltosRecordTM record_tm = new AltosRecordTM(); - AltosSensorTM sensor = new AltosSensorTM(link); - record_tm.accel = sensor.accel; - record_tm.pres = sensor.pres; - record_tm.batt = sensor.batt; - record_tm.temp = sensor.temp; - record_tm.drogue = sensor.drogue; - record_tm.main = sensor.main; - record_tm.ground_accel = record_tm.accel; - record_tm.ground_pres = record_tm.pres; - record_tm.accel_plus_g = config_data.accel_cal_plus; - record_tm.accel_minus_g = config_data.accel_cal_minus; - record_tm.tick = sensor.tick; - record = record_tm; + record = new AltosSensorTM(link, config_data); } else if (config_data.product.startsWith("MegaMetrum")) { AltosRecordMM record_mm = new AltosRecordMM(); AltosSensorMM sensor = new AltosSensorMM(link); @@ -390,24 +374,27 @@ public class AltosIdleMonitor extends Thread { record = new AltosRecord(); gps = new AltosGPSQuery(link, config_data); + + record.version = 0; + record.callsign = config_data.callsign; + record.serial = config_data.serial; + record.flight = config_data.log_available() > 0 ? 255 : 0; + record.status = 0; + record.state = AltosLib.ao_flight_idle; + record.gps = gps; + record.new_gps = true; + state = new AltosState (record, state); } finally { if (remote) { link.stop_remote(); - rssi = AltosRSSI(); - } else - rssi = 0; + if (record != null) + record.rssi = AltosRSSI(); + } else { + if (record != null) + record.rssi = 0; + } } - record.version = 0; - record.callsign = config_data.callsign; - record.serial = config_data.serial; - record.flight = config_data.log_available() > 0 ? 255 : 0; - record.rssi = rssi; - record.status = 0; - record.state = AltosLib.ao_flight_idle; - - record.gps = gps; - state = new AltosState (record, state); } public void set_frequency(double in_frequency) { diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index d59e73ba..fd5db7e9 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -101,15 +101,23 @@ public abstract class AltosLink { try { for (;;) { c = getchar(); - if (Thread.interrupted()) + if (Thread.interrupted()) { + if (debug) + System.out.printf("INTERRUPTED\n"); break; + } if (c == ERROR) { + if (debug) + System.out.printf("ERROR\n"); add_telem (new AltosLine()); add_reply (new AltosLine()); break; } - if (c == TIMEOUT) + if (c == TIMEOUT) { + if (debug) + System.out.printf("TIMEOUT\n"); continue; + } if (c == '\r') continue; synchronized(this) { @@ -180,6 +188,14 @@ public abstract class AltosLink { reply_queue.put (line); } + public void abort_reply() { + try { + add_telem (new AltosLine()); + add_reply (new AltosLine()); + } catch (InterruptedException e) { + } + } + public void add_string(String line) throws InterruptedException { if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) { add_telem(new AltosLine(line)); diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index e468f84b..8722bc05 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -127,7 +127,7 @@ public class AltosRecord implements Comparable , Cloneable { double p = filtered_pressure(); if (p == MISSING) - return MISSING; + return raw_altitude(); return AltosConvert.pressure_to_altitude(p); } diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java index afb70790..37accef6 100644 --- a/altoslib/AltosRecordTM.java +++ b/altoslib/AltosRecordTM.java @@ -177,14 +177,14 @@ public class AltosRecordTM extends AltosRecord { drogue = MISSING; main = MISSING; - flight_accel = 0; - flight_vel = 0; - flight_pres = 0; - - ground_accel = 0; - ground_pres = 0; - accel_plus_g = 0; - accel_minus_g = 0; + flight_accel = MISSING; + flight_vel = MISSING; + flight_pres = MISSING; + + ground_accel = MISSING; + ground_pres = MISSING; + accel_plus_g = MISSING; + accel_minus_g = MISSING; } public AltosRecordTM(AltosRecord old) { diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index e20ec9a7..3b37a3d4 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -38,6 +38,7 @@ public class AltosState { public boolean boost; /* under power */ public double ground_altitude; + public double altitude; public double height; public double speed; public double acceleration; @@ -82,6 +83,7 @@ public class AltosState { data = cur; ground_altitude = data.ground_altitude(); + altitude = data.raw_altitude(); height = data.filtered_height(); report_time = System.currentTimeMillis(); diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index c4e9c697..8b692fa9 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -54,13 +54,19 @@ public class AltosSerial extends AltosLink implements Runnable { Frame frame; public int getchar() { + if (altos == null) + return ERROR; return libaltos.altos_getchar(altos, 0); } public void flush_output() { super.flush_output(); if (altos != null) { - libaltos.altos_flush(altos); + if (libaltos.altos_flush(altos) != 0) { + libaltos.altos_close(altos); + altos = null; + abort_reply(); + } } } @@ -155,7 +161,11 @@ public class AltosSerial extends AltosLink implements Runnable { private void putc(char c) { if (altos != null) - libaltos.altos_putchar(altos, c); + if (libaltos.altos_putchar(altos, c) != 0) { + libaltos.altos_close(altos); + altos = null; + abort_reply(); + } } public void print(String data) { diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 1cc27cbe..515432f9 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -221,7 +221,7 @@ altos_flush(struct altos_file *file) #endif if (ret < 0) { altos_set_last_posix_error(); - return -errno; + return -last_error.code; } if (ret) { memmove(file->out_data, file->out_data + ret, @@ -247,7 +247,7 @@ altos_putchar(struct altos_file *file, char c) ret = 0; if (file->out_used == USB_BUF_SIZE) ret = altos_flush(file); - return 0; + return ret; } #ifdef USE_POLL -- cgit v1.2.3 From 743dca54012758d3ae54312d542b34afa88495cd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 29 Jul 2012 19:35:15 -0700 Subject: altosui: Remove duplicate values from info table. Add altitude No need to have state/call/serial/flight data, those are all in the header. Having altitude makes Monitor Idle slightly more useful. Signed-off-by: Keith Packard --- altosui/AltosInfoTable.java | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java index aa6a6d4e..c1400976 100644 --- a/altosui/AltosInfoTable.java +++ b/altosui/AltosInfoTable.java @@ -40,18 +40,38 @@ public class AltosInfoTable extends JTable { return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10; } + int text_width(String t) { + FontMetrics infoValueMetrics = getFontMetrics(Altos.table_value_font); + + return infoValueMetrics.stringWidth(t); + } + + void set_layout() { + setRowHeight(desired_row_height()); + for (int i = 0; i < info_columns * 2; i++) + { + TableColumn column = getColumnModel().getColumn(i); + + if ((i & 1) == 0) + column.setPreferredWidth(text_width(" Satellites Visible ")); + else + column.setPreferredWidth(text_width(" 179°59.99999' ")); + } + } + public AltosInfoTable() { super(new AltosFlightInfoTableModel(info_rows, info_columns)); model = (AltosFlightInfoTableModel) getModel(); setFont(Altos.table_value_font); setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS); setShowGrid(true); - setRowHeight(desired_row_height()); + set_layout(); doLayout(); } public void set_font() { setFont(Altos.table_value_font); + set_layout(); doLayout(); } @@ -95,13 +115,8 @@ public class AltosInfoTable extends JTable { if (state == null) return; info_reset(); - info_add_row(0, "Rocket state", "%s", state.data.state()); - info_add_row(0, "Callsign", "%s", state.data.callsign); - info_add_row(0, "Rocket serial", "%6d", state.data.serial); - info_add_row(0, "Rocket flight", "%6d", state.data.flight); - - info_add_row(0, "RSSI", "%6d dBm", state.data.rssi); - info_add_row(0, "CRC Errors", "%6d", crc_errors); + info_add_row(0, "Altitude", "%6.0f m", state.altitude); + info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude); info_add_row(0, "Height", "%6.0f m", state.height); info_add_row(0, "Max height", "%6.0f m", state.max_height); info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration); @@ -114,7 +129,8 @@ public class AltosInfoTable extends JTable { info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense); if (state.main_sense != AltosRecord.MISSING) info_add_row(0, "Main", "%9.2f V", state.main_sense); - info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude); + info_add_row(0, "CRC Errors", "%6d", crc_errors); + if (state.gps == null || !state.gps.connected) { info_add_row(1, "GPS", "not available"); } else { -- cgit v1.2.3 From c56dead72f65e7468017656347dba531ab2ca480 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Tue, 31 Jul 2012 20:05:35 +1200 Subject: Ignore autogenerated file: altosui/Info.plist Signed-off-by: Mike Beattie --- altosui/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'altosui') diff --git a/altosui/.gitignore b/altosui/.gitignore index 6d65611f..6d2d8c23 100644 --- a/altosui/.gitignore +++ b/altosui/.gitignore @@ -5,6 +5,7 @@ fat/ Manifest.txt Manifest-fat.txt AltosVersion.java +Info.plist libaltosJNI classes altosui -- cgit v1.2.3 From 82a37d70e3cacf792c1aa18f8c0d2a19d6f321ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 4 Aug 2012 22:58:48 -0700 Subject: altosui: Move 'implements Runnable' from AltosSerial to AltosLink AltosLink is the class providing the 'run' method, after all... Signed-off-by: Keith Packard --- altoslib/AltosLink.java | 2 +- altosui/AltosSerial.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index fd5db7e9..415c3c64 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -23,7 +23,7 @@ import java.util.concurrent.*; import java.util.*; import java.text.*; -public abstract class AltosLink { +public abstract class AltosLink implements Runnable { public final static int ERROR = -1; public final static int TIMEOUT = -2; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 8b692fa9..6cee1609 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -41,7 +41,7 @@ import libaltosJNI.*; * threads. */ -public class AltosSerial extends AltosLink implements Runnable { +public class AltosSerial extends AltosLink { static java.util.List devices_opened = Collections.synchronizedList(new LinkedList()); -- cgit v1.2.3 From 659c0cd3ee4b9581c12ac2cd1b4162bf07a921ce Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 19 Aug 2012 10:02:16 -0700 Subject: altosui: Check for JRE 1.7 in Windows installer altosui runs fine with version 1.7 (on Linux at least), so allow that version to satisfy the java check instead of requiring the user to down-grade to 1.6 Signed-off-by: Keith Packard --- altosui/altos-windows.nsi | 3 +++ 1 file changed, 3 insertions(+) (limited to 'altosui') diff --git a/altosui/altos-windows.nsi b/altosui/altos-windows.nsi index 92c985a9..986919d4 100644 --- a/altosui/altos-windows.nsi +++ b/altosui/altos-windows.nsi @@ -1,6 +1,7 @@ !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" @@ -42,6 +43,8 @@ Function DetectJRE "CurrentVersion" StrCmp $2 ${JRE_VERSION} done + StrCmp $2 ${JRE_ALTERNATE} done + Call GetJRE done: -- cgit v1.2.3 From d65d921b9b2340fa23d3b55b4ae755324d392303 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Sep 2012 12:20:08 -0700 Subject: altosui: Catch errors in state value when saving flight logs Use AltosLib.state_name() instead of directly accessing the state_to_string array so that any invalid state values are caught and replaced with 'invalid' instead of raising an exception. Signed-off-by: Keith Packard --- altosui/AltosEepromDownload.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index 4a35c2f1..b04890cd 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -336,7 +336,7 @@ public class AltosEepromDownload implements Runnable { state = 0; state_block = log.start_block; for (block = log.start_block; !done && block < log.end_block; block++) { - monitor.set_value(Altos.state_to_string[state], state, block - state_block); + monitor.set_value(AltosLib.state_name(state), state, block - state_block); AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block, block == log.start_block); -- cgit v1.2.3 From 9682e9e6fe730417a77b47795fbe1f06c9a51177 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Sep 2012 12:29:32 -0700 Subject: altosui: Use helper functions to access arrays in AltosLib class These deal with out-of-range values correctly, instead of causing exceptions that will just break stuff. Signed-off-by: Keith Packard --- altoslib/AltosLib.java | 18 ++++++++++++------ altosui/Altos.java | 14 -------------- altosui/AltosFlightStatsTable.java | 2 +- altosui/AltosScanUI.java | 2 +- 4 files changed, 14 insertions(+), 22 deletions(-) (limited to 'altosui') diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 2402331e..d36b2ff7 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -111,7 +111,7 @@ public class AltosLib { public static final int ao_telemetry_0_8 = 3; public static final int ao_telemetry_max = 3; - public static final String[] ao_telemetry_name = { + private static final String[] ao_telemetry_name = { "Off", "Standard Telemetry", "TeleMetrum v0.9", "TeleMetrum v0.8" }; @@ -121,13 +121,13 @@ public class AltosLib { public static final int ao_telemetry_0_9_len = 95; public static final int ao_telemetry_0_8_len = 94; - public static final int[] ao_telemetry_len = { + private static final int[] ao_telemetry_len = { 0, 32, 95, 94 }; - public static HashMap string_to_state = new HashMap(); + private static HashMap string_to_state = new HashMap(); - public static boolean map_initialized = false; + private static boolean map_initialized = false; public static void initialize_map() { @@ -159,7 +159,7 @@ public class AltosLib { telemetry)); } - public static String[] state_to_string = { + private static String[] state_to_string = { "startup", "idle", "pad", @@ -172,7 +172,7 @@ public class AltosLib { "invalid", }; - public static String[] state_to_string_capital = { + private static String[] state_to_string_capital = { "Startup", "Idle", "Pad", @@ -199,6 +199,12 @@ public class AltosLib { return state_to_string[state]; } + public static String state_name_capital(int state) { + if (state < 0 || state_to_string.length <= state) + return "invalid"; + return state_to_string_capital[state]; + } + public static final int AO_GPS_VALID = (1 << 4); public static final int AO_GPS_RUNNING = (1 << 5); public static final int AO_GPS_DATE_VALID = (1 << 6); diff --git a/altosui/Altos.java b/altosui/Altos.java index e60b3aaa..cd17a93e 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -72,20 +72,6 @@ public class Altos extends AltosLib { static final int text_width = 20; - static public int state(String state) { - if (!map_initialized) - initialize_map(); - if (string_to_state.containsKey(state)) - return string_to_state.get(state); - return ao_flight_invalid; - } - - static public String state_name(int state) { - if (state < 0 || state_to_string.length <= state) - return "invalid"; - return state_to_string[state]; - } - static public boolean initialized = false; static public boolean loaded_library = false; diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index c311b231..14e3bf8f 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -103,7 +103,7 @@ public class AltosFlightStatsTable extends JComponent { String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_main]), String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main]))); for (int s = Altos.ao_flight_boost; s <= Altos.ao_flight_main; s++) { - new FlightStat(layout, y++, String.format("%s time", Altos.state_to_string_capital[s]), + new FlightStat(layout, y++, String.format("%s time", AltosLib.state_name_capital(s)), String.format("%6.2f s", stats.state_end[s] - stats.state_start[s])); } new FlightStat(layout, y++, "Flight Time", diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index ef6389b6..9da1290f 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -427,7 +427,7 @@ public class AltosScanUI telemetry_boxes = new JCheckBox[Altos.ao_telemetry_max - Altos.ao_telemetry_min + 1]; for (int k = Altos.ao_telemetry_min; k <= Altos.ao_telemetry_max; k++) { int j = k - Altos.ao_telemetry_min; - telemetry_boxes[j] = new JCheckBox(Altos.ao_telemetry_name[k]); + telemetry_boxes[j] = new JCheckBox(AltosLib.telemetry_name(k)); c.gridy = 3 + j; pane.add(telemetry_boxes[j], c); telemetry_boxes[j].setActionCommand("telemetry"); -- cgit v1.2.3 From 67da878f740a387d0092631ad672e024d26e4192 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 10 Sep 2012 09:16:04 -0700 Subject: altosui: Use units conversion functions everywhere. Provide a configuration option to select imperial units and use them everywhere Signed-off-by: Keith Packard --- altosui/AltosAscent.java | 12 ++++++------ altosui/AltosConfigureUI.java | 27 +++++++++++++++++++++++++++ altosui/AltosDescent.java | 10 +++++++--- altosui/AltosDisplayThread.java | 24 ++++++++++++------------ altosui/AltosFlightStatsTable.java | 12 ++++++------ altosui/AltosFlightStatusTableModel.java | 11 ++++++++--- 6 files changed, 66 insertions(+), 30 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index 38b3b30f..a158eb21 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -169,14 +169,14 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { max_value.setFont(Altos.value_font); } - void show(String format, double v) { + void show(AltosUnits units, double v) { if (v == AltosRecord.MISSING) { value.setText("Missing"); max_value.setText("Missing"); } else { - value.setText(String.format(format, v)); + value.setText(units.show(8, v)); if (v > max || max == AltosRecord.MISSING) { - max_value.setText(String.format(format, v)); + max_value.setText(units.show(8, v)); max = v; } } @@ -221,7 +221,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { class Height extends AscentValueHold { void show (AltosState state, int crc_errors) { - show("%6.0f m", state.height); + show(AltosConvert.height, state.height); } public Height (GridBagLayout layout, int y) { super (layout, y, "Height"); @@ -235,7 +235,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { double speed = state.speed; if (!state.ascent) speed = state.baro_speed; - show("%6.0f m/s", speed); + show(AltosConvert.speed, speed); } public Speed (GridBagLayout layout, int y) { super (layout, y, "Speed"); @@ -246,7 +246,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay { class Accel extends AscentValueHold { void show (AltosState state, int crc_errors) { - show("%6.0f m/s²", state.acceleration); + show(AltosConvert.accel, state.acceleration); } public Accel (GridBagLayout layout, int y) { super (layout, y, "Acceleration"); diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index ace245a0..da82e8e0 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -91,6 +91,8 @@ public class AltosConfigureUI JLabel callsign_label; JTextField callsign_value; + JRadioButton imperial_units; + JLabel font_size_label; JComboBox font_size_value; @@ -236,6 +238,31 @@ public class AltosConfigureUI pane.add(callsign_value, c); callsign_value.setToolTipText("Callsign sent in packet mode"); + /* 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.serial_debug()); + 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; diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 664c5ea6..62258814 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -119,6 +119,10 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { value.setVisible(false); } + void show(AltosUnits units, double v) { + value.setText(units.show(8, v)); + } + void show(String format, double v) { value.setText(String.format(format, v)); } @@ -239,7 +243,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { class Height extends DescentValue { void show (AltosState state, int crc_errors) { - show("%6.0f m", state.height); + show(AltosConvert.height, state.height); } public Height (GridBagLayout layout, int x, int y) { super (layout, x, y, "Height"); @@ -253,7 +257,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { double speed = state.speed; if (!state.ascent) speed = state.baro_speed; - show("%6.0f m/s", speed); + show(AltosConvert.speed, speed); } public Speed (GridBagLayout layout, int x, int y) { super (layout, x, y, "Speed"); @@ -346,7 +350,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay { class Range extends DescentValue { void show (AltosState state, int crc_errors) { - show("%6.0f m", state.range); + show(AltosConvert.distance, state.range); } public Range (GridBagLayout layout, int x, int y) { super (layout, x, y, "Range"); diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java index 03ce4efd..cf69c414 100644 --- a/altosui/AltosDisplayThread.java +++ b/altosui/AltosDisplayThread.java @@ -102,15 +102,15 @@ public class AltosDisplayThread extends Thread { state.state < Altos.ao_flight_landed && state.range >= 0) { - voice.speak("Height %d, bearing %s %d, elevation %d, range %d.\n", - (int) (state.height + 0.5), - state.from_pad.bearing_words( - AltosGreatCircle.BEARING_VOICE), + voice.speak("Height %s, bearing %s %d, elevation %d, range %s.\n", + AltosConvert.height.say(state.height), + state.from_pad.bearing_words( + AltosGreatCircle.BEARING_VOICE), (int) (state.from_pad.bearing + 0.5), (int) (state.elevation + 0.5), - (int) (state.range + 0.5)); + AltosConvert.distance.say(state.range)); } else if (state.state > Altos.ao_flight_pad) { - voice.speak("%d meters", (int) (state.height + 0.5)); + voice.speak(AltosConvert.height.say_units(state.height)); } else { reported_landing = 0; } @@ -129,9 +129,9 @@ public class AltosDisplayThread extends Thread { else voice.speak("rocket may have crashed"); if (state.from_pad != null) - voice.speak("Bearing %d degrees, range %d meters.", + voice.speak("Bearing %d degrees, range %s.", (int) (state.from_pad.bearing + 0.5), - (int) (state.from_pad.distance + 0.5)); + AltosConvert.distance.say_units(state.from_pad.distance)); ++reported_landing; if (state.state != Altos.ao_flight_landed) { state.state = Altos.ao_flight_landed; @@ -202,13 +202,13 @@ public class AltosDisplayThread extends Thread { voice.speak(state.data.state()); if ((old_state == null || old_state.state <= Altos.ao_flight_boost) && state.state > Altos.ao_flight_boost) { - voice.speak("max speed: %d meters per second.", - (int) (state.max_speed + 0.5)); + voice.speak("max speed: %s.", + AltosConvert.speed.say_units(state.max_speed + 0.5)); ret = true; } else if ((old_state == null || old_state.state < Altos.ao_flight_drogue) && state.state >= Altos.ao_flight_drogue) { - voice.speak("max height: %d meters.", - (int) (state.max_height + 0.5)); + voice.speak("max height: %s.", + AltosConvert.height.say_units(state.max_height + 0.5)); ret = true; } } diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index 14e3bf8f..87ba6aa8 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -84,17 +84,17 @@ public class AltosFlightStatsTable extends JComponent { String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height))); new FlightStat(layout, y++, "Maximum speed", String.format("%5.0f m/s", stats.max_speed), - String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.max_speed)), - String.format("Mach %5.3f", AltosConvert.meters_to_mach(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))); if (stats.max_acceleration != AltosRecord.MISSING) { new FlightStat(layout, y++, "Maximum boost acceleration", String.format("%5.0f m/s²", stats.max_acceleration), String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), - String.format("%5.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); + String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_acceleration))); new FlightStat(layout, y++, "Average boost acceleration", String.format("%5.0f m/s²", stats.state_accel[Altos.ao_flight_boost]), String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[Altos.ao_flight_boost])), - String.format("%5.2f G", AltosConvert.meters_to_g(stats.state_accel[Altos.ao_flight_boost]))); + String.format("%5.0f G", AltosConvert.meters_to_g(stats.state_accel[Altos.ao_flight_boost]))); } new FlightStat(layout, y++, "Drogue descent rate", String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_drogue]), @@ -104,10 +104,10 @@ public class AltosFlightStatsTable extends JComponent { String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main]))); for (int s = Altos.ao_flight_boost; s <= Altos.ao_flight_main; s++) { new FlightStat(layout, y++, String.format("%s time", AltosLib.state_name_capital(s)), - String.format("%6.2f s", stats.state_end[s] - stats.state_start[s])); + String.format("%6.0f s", stats.state_end[s] - stats.state_start[s])); } new FlightStat(layout, y++, "Flight Time", - String.format("%6.2f s", stats.state_end[Altos.ao_flight_main] - + String.format("%6.0f s", stats.state_end[Altos.ao_flight_main] - stats.state_start[Altos.ao_flight_boost])); } diff --git a/altosui/AltosFlightStatusTableModel.java b/altosui/AltosFlightStatusTableModel.java index 75bf16eb..c2cf8cd1 100644 --- a/altosui/AltosFlightStatusTableModel.java +++ b/altosui/AltosFlightStatusTableModel.java @@ -30,7 +30,12 @@ import java.util.concurrent.LinkedBlockingQueue; import org.altusmetrum.AltosLib.*; public class AltosFlightStatusTableModel extends AbstractTableModel { - private String[] columnNames = {"Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" }; + private String[] columnNames = { + String.format("Height (%s)", AltosConvert.show_distance_units()), + "State", + "RSSI (dBm)", + String.format("Speed (%s)", AltosConvert.show_speed_unit()) + }; private Object[] data = { 0, "idle", 0, 0 }; public int getColumnCount() { return columnNames.length; } @@ -51,12 +56,12 @@ public class AltosFlightStatusTableModel extends AbstractTableModel { } public void set(AltosState state) { - setValueAt(String.format("%1.0f", state.height), 0); + setValueAt(String.format("%1.0f", AltosConvert.distance(state.height), 0); setValueAt(state.data.state(), 1); setValueAt(state.data.rssi, 2); double speed = state.baro_speed; if (state.ascent) speed = state.speed; - setValueAt(String.format("%1.0f", speed), 3); + setValueAt(String.format("%1.0f", AltosConvert.speed(speed)), 3); } } -- cgit v1.2.3 From c2ebebc4967043b16380b8ec8800862993005358 Mon Sep 17 00:00:00 2001 From: Tom Marble Date: Mon, 10 Sep 2012 14:50:37 -0500 Subject: Test commit (comment) to confirm push works --- altosui/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 19db6698..eb6ea2a3 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -112,6 +112,8 @@ LIBALTOS= \ libaltos.dylib \ altos.dll +# tmarble: test comment for change of package name +# from altosui to AltosUI JAR=altosui.jar FATJAR=altosui-fat.jar -- cgit v1.2.3 From 708e7937cba52982b91244cf89bfbff46d346135 Mon Sep 17 00:00:00 2001 From: Tom Marble Date: Mon, 10 Sep 2012 16:54:27 -0500 Subject: Changed package name from altosui to AltosUI --- altosui/Altos.java | 2 +- altosui/AltosAscent.java | 2 +- altosui/AltosBTDevice.java | 2 +- altosui/AltosBTDeviceIterator.java | 2 +- altosui/AltosBTKnown.java | 2 +- altosui/AltosBTManage.java | 2 +- altosui/AltosCSV.java | 2 +- altosui/AltosCSVUI.java | 2 +- altosui/AltosChannelMenu.java | 2 +- altosui/AltosCompanionInfo.java | 2 +- altosui/AltosConfig.java | 2 +- altosui/AltosConfigFreqUI.java | 2 +- altosui/AltosConfigTD.java | 2 +- altosui/AltosConfigTDUI.java | 2 +- altosui/AltosConfigUI.java | 2 +- altosui/AltosConfigureUI.java | 2 +- altosui/AltosDataChooser.java | 2 +- altosui/AltosDataPoint.java | 2 +- altosui/AltosDataPointReader.java | 2 +- altosui/AltosDebug.java | 2 +- altosui/AltosDescent.java | 2 +- altosui/AltosDevice.java | 2 +- altosui/AltosDeviceDialog.java | 2 +- altosui/AltosDialog.java | 2 +- altosui/AltosDisplayThread.java | 2 +- altosui/AltosEepromDelete.java | 2 +- altosui/AltosEepromDownload.java | 2 +- altosui/AltosEepromList.java | 2 +- altosui/AltosEepromManage.java | 2 +- altosui/AltosEepromMonitor.java | 2 +- altosui/AltosEepromSelect.java | 2 +- altosui/AltosFlash.java | 2 +- altosui/AltosFlashUI.java | 2 +- altosui/AltosFlightDisplay.java | 2 +- altosui/AltosFlightInfoTableModel.java | 2 +- altosui/AltosFlightStats.java | 2 +- altosui/AltosFlightStatsTable.java | 2 +- altosui/AltosFlightStatus.java | 2 +- altosui/AltosFlightStatusTableModel.java | 2 +- altosui/AltosFlightStatusUpdate.java | 2 +- altosui/AltosFlightUI.java | 2 +- altosui/AltosFontListener.java | 2 +- altosui/AltosFrame.java | 2 +- altosui/AltosFreqList.java | 2 +- altosui/AltosGraph.java | 2 +- altosui/AltosGraphTime.java | 2 +- altosui/AltosGraphUI.java | 2 +- altosui/AltosHexfile.java | 2 +- altosui/AltosIdleMonitorUI.java | 2 +- altosui/AltosIgniteUI.java | 2 +- altosui/AltosInfoTable.java | 2 +- altosui/AltosKML.java | 2 +- altosui/AltosLanded.java | 2 +- altosui/AltosLaunch.java | 2 +- altosui/AltosLaunchUI.java | 2 +- altosui/AltosLed.java | 2 +- altosui/AltosLights.java | 2 +- altosui/AltosPad.java | 2 +- altosui/AltosRomconfig.java | 2 +- altosui/AltosRomconfigUI.java | 2 +- altosui/AltosScanUI.java | 2 +- altosui/AltosSerial.java | 2 +- altosui/AltosSerialInUseException.java | 2 +- altosui/AltosSiteMap.java | 2 +- altosui/AltosSiteMapCache.java | 2 +- altosui/AltosSiteMapPreload.java | 2 +- altosui/AltosSiteMapTile.java | 2 +- altosui/AltosUI.java | 2 +- altosui/AltosUIListener.java | 2 +- altosui/AltosUIPreferences.java | 2 +- altosui/AltosUSBDevice.java | 2 +- altosui/AltosVersion.java.in | 2 +- altosui/AltosVoice.java | 2 +- altosui/AltosWriter.java | 2 +- altosui/GrabNDrag.java | 2 +- altosui/Makefile.am | 28 +++++++++++++--------------- 76 files changed, 88 insertions(+), 90 deletions(-) (limited to 'altosui') diff --git a/altosui/Altos.java b/altosui/Altos.java index cd17a93e..d3aad6b2 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.util.*; diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index a158eb21..de6c90a1 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index 5e353fdd..a6eee085 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosBTDeviceIterator.java b/altosui/AltosBTDeviceIterator.java index 58ed86d5..8d9e6fe6 100644 --- a/altosui/AltosBTDeviceIterator.java +++ b/altosui/AltosBTDeviceIterator.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java index 6a8e53cb..ad0672c6 100644 --- a/altosui/AltosBTKnown.java +++ b/altosui/AltosBTKnown.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index aeb964bb..a411c83e 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index c876d9ca..c672b78f 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.io.*; diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java index 2702668b..a28c4ca6 100644 --- a/altosui/AltosCSVUI.java +++ b/altosui/AltosCSVUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosChannelMenu.java b/altosui/AltosChannelMenu.java index 0249a0bd..d7e7f58f 100644 --- a/altosui/AltosChannelMenu.java +++ b/altosui/AltosChannelMenu.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosCompanionInfo.java b/altosui/AltosCompanionInfo.java index 4ba8fe98..16c972b3 100644 --- a/altosui/AltosCompanionInfo.java +++ b/altosui/AltosCompanionInfo.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index cae41858..0b386ac9 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java index 7958a21c..4f8bd0f2 100644 --- a/altosui/AltosConfigFreqUI.java +++ b/altosui/AltosConfigFreqUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java index 324a5988..f5d30250 100644 --- a/altosui/AltosConfigTD.java +++ b/altosui/AltosConfigTD.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigTDUI.java b/altosui/AltosConfigTDUI.java index f2058f69..f653d941 100644 --- a/altosui/AltosConfigTDUI.java +++ b/altosui/AltosConfigTDUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index 62394fa6..b0624ef2 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index da82e8e0..b46c1fae 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index 4bd51c39..b003a606 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosDataPoint.java b/altosui/AltosDataPoint.java index 5e077320..80f62c2c 100644 --- a/altosui/AltosDataPoint.java +++ b/altosui/AltosDataPoint.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package altosui; +package AltosUI; interface AltosDataPoint { int version(); diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index 821b0771..371c48cb 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package altosui; +package AltosUI; import java.io.IOException; import java.text.ParseException; diff --git a/altosui/AltosDebug.java b/altosui/AltosDebug.java index 23e38bc0..4e394011 100644 --- a/altosui/AltosDebug.java +++ b/altosui/AltosDebug.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.io.*; diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 62258814..2e3f26bd 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosDevice.java b/altosui/AltosDevice.java index 1b5c1a91..dc045d7b 100644 --- a/altosui/AltosDevice.java +++ b/altosui/AltosDevice.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index fa9d0013..7ab08b30 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.util.*; diff --git a/altosui/AltosDialog.java b/altosui/AltosDialog.java index ff38c3e4..1de11317 100644 --- a/altosui/AltosDialog.java +++ b/altosui/AltosDialog.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java index cf69c414..0cf942e7 100644 --- a/altosui/AltosDisplayThread.java +++ b/altosui/AltosDisplayThread.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index 73f3a00f..21f09d0e 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index b04890cd..a4d6b26e 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index 6a656215..2a88134c 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index 563c90b3..27b03bed 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java index 75643442..daf8d0ba 100644 --- a/altosui/AltosEepromMonitor.java +++ b/altosui/AltosEepromMonitor.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index 4ad78896..cb242183 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.util.*; diff --git a/altosui/AltosFlash.java b/altosui/AltosFlash.java index bd0c8a50..996456fd 100644 --- a/altosui/AltosFlash.java +++ b/altosui/AltosFlash.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 66991d10..01421de9 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightDisplay.java b/altosui/AltosFlightDisplay.java index 826f9522..e677fd6f 100644 --- a/altosui/AltosFlightDisplay.java +++ b/altosui/AltosFlightDisplay.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import org.altusmetrum.AltosLib.*; diff --git a/altosui/AltosFlightInfoTableModel.java b/altosui/AltosFlightInfoTableModel.java index 77969a89..cb798bcb 100644 --- a/altosui/AltosFlightInfoTableModel.java +++ b/altosui/AltosFlightInfoTableModel.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index ab094c80..d37f90b8 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index 87ba6aa8..bcfdd84e 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStatus.java b/altosui/AltosFlightStatus.java index 6a351004..ee03698b 100644 --- a/altosui/AltosFlightStatus.java +++ b/altosui/AltosFlightStatus.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStatusTableModel.java b/altosui/AltosFlightStatusTableModel.java index c2cf8cd1..919c7704 100644 --- a/altosui/AltosFlightStatusTableModel.java +++ b/altosui/AltosFlightStatusTableModel.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStatusUpdate.java b/altosui/AltosFlightStatusUpdate.java index d70fc7f8..a0b4e304 100644 --- a/altosui/AltosFlightStatusUpdate.java +++ b/altosui/AltosFlightStatusUpdate.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index ddc54cbd..08e8550f 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFontListener.java b/altosui/AltosFontListener.java index 0dda0f29..a0cb8a56 100644 --- a/altosui/AltosFontListener.java +++ b/altosui/AltosFontListener.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; public interface AltosFontListener { void font_size_changed(int font_size); diff --git a/altosui/AltosFrame.java b/altosui/AltosFrame.java index 70598634..cdbfe7d3 100644 --- a/altosui/AltosFrame.java +++ b/altosui/AltosFrame.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFreqList.java b/altosui/AltosFreqList.java index 1bbc97c6..a17afce6 100644 --- a/altosui/AltosFreqList.java +++ b/altosui/AltosFreqList.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosGraph.java b/altosui/AltosGraph.java index 54d2bb0b..a61a0976 100644 --- a/altosui/AltosGraph.java +++ b/altosui/AltosGraph.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package altosui; +package AltosUI; import java.io.*; diff --git a/altosui/AltosGraphTime.java b/altosui/AltosGraphTime.java index 0955f6e6..f00170ec 100644 --- a/altosui/AltosGraphTime.java +++ b/altosui/AltosGraphTime.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package altosui; +package AltosUI; import java.lang.*; import java.io.*; diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 527a7d28..b571fc7d 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package altosui; +package AltosUI; import java.io.*; import java.util.ArrayList; diff --git a/altosui/AltosHexfile.java b/altosui/AltosHexfile.java index d52b46c3..435f13ee 100644 --- a/altosui/AltosHexfile.java +++ b/altosui/AltosHexfile.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.io.*; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 46ca3e5d..f67644fc 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 78eba8e6..8c4c939f 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java index c1400976..8caf5a80 100644 --- a/altosui/AltosInfoTable.java +++ b/altosui/AltosInfoTable.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosKML.java b/altosui/AltosKML.java index ff0734b8..7e3b0e08 100644 --- a/altosui/AltosKML.java +++ b/altosui/AltosKML.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.io.*; diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index a47e1cbd..5c3111a2 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosLaunch.java b/altosui/AltosLaunch.java index 0e493b91..67512cef 100644 --- a/altosui/AltosLaunch.java +++ b/altosui/AltosLaunch.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.io.*; import java.util.concurrent.*; diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index 44481544..a4f12997 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosLed.java b/altosui/AltosLed.java index 1358cd48..4bf43a53 100644 --- a/altosui/AltosLed.java +++ b/altosui/AltosLed.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosLights.java b/altosui/AltosLights.java index 8bd9e7de..92d11212 100644 --- a/altosui/AltosLights.java +++ b/altosui/AltosLights.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index 0a3f3d65..8006190d 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosRomconfig.java b/altosui/AltosRomconfig.java index 0a283e51..1e3d7294 100644 --- a/altosui/AltosRomconfig.java +++ b/altosui/AltosRomconfig.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.io.*; import org.altusmetrum.AltosLib.*; diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java index 306b8623..25d8d087 100644 --- a/altosui/AltosRomconfigUI.java +++ b/altosui/AltosRomconfigUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 9da1290f..534451cb 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 6cee1609..61865bbd 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -19,7 +19,7 @@ * Deal with TeleDongle on a serial port */ -package altosui; +package AltosUI; import java.lang.*; import java.io.*; diff --git a/altosui/AltosSerialInUseException.java b/altosui/AltosSerialInUseException.java index 7380f331..ae97b3d2 100644 --- a/altosui/AltosSerialInUseException.java +++ b/altosui/AltosSerialInUseException.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; public class AltosSerialInUseException extends Exception { public AltosDevice device; diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index b57edcab..4195fc3f 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.image.*; diff --git a/altosui/AltosSiteMapCache.java b/altosui/AltosSiteMapCache.java index f729a298..6e7e423b 100644 --- a/altosui/AltosSiteMapCache.java +++ b/altosui/AltosSiteMapCache.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.image.*; diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 676b0790..8c0850fa 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.image.*; diff --git a/altosui/AltosSiteMapTile.java b/altosui/AltosSiteMapTile.java index 34550219..1e1cca5a 100644 --- a/altosui/AltosSiteMapTile.java +++ b/altosui/AltosSiteMapTile.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.image.*; diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 926d66f0..a1678299 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosUIListener.java b/altosui/AltosUIListener.java index 7ee62afc..e50b30b2 100644 --- a/altosui/AltosUIListener.java +++ b/altosui/AltosUIListener.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; public interface AltosUIListener { public void ui_changed(String look_and_feel); diff --git a/altosui/AltosUIPreferences.java b/altosui/AltosUIPreferences.java index 10ab26c3..010d8e6a 100644 --- a/altosui/AltosUIPreferences.java +++ b/altosui/AltosUIPreferences.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.io.*; import java.util.*; diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java index ed5f8307..0c953cbf 100644 --- a/altosui/AltosUSBDevice.java +++ b/altosui/AltosUSBDevice.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosVersion.java.in b/altosui/AltosVersion.java.in index b0b3c0cf..d72e0936 100644 --- a/altosui/AltosVersion.java.in +++ b/altosui/AltosVersion.java.in @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; public class AltosVersion { public final static String version = "@VERSION@"; diff --git a/altosui/AltosVoice.java b/altosui/AltosVoice.java index ab74e0b3..ff83ac29 100644 --- a/altosui/AltosVoice.java +++ b/altosui/AltosVoice.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import com.sun.speech.freetts.Voice; import com.sun.speech.freetts.VoiceManager; diff --git a/altosui/AltosWriter.java b/altosui/AltosWriter.java index b7375204..9031c268 100644 --- a/altosui/AltosWriter.java +++ b/altosui/AltosWriter.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.lang.*; import java.io.*; diff --git a/altosui/GrabNDrag.java b/altosui/GrabNDrag.java index c350efec..a984c43e 100644 --- a/altosui/GrabNDrag.java +++ b/altosui/GrabNDrag.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package altosui; +package AltosUI; import java.awt.*; import java.awt.image.*; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index eb6ea2a3..9ca4f86e 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -112,11 +112,9 @@ LIBALTOS= \ libaltos.dylib \ altos.dll -# tmarble: test comment for change of package name -# from altosui to AltosUI -JAR=altosui.jar +JAR=AltosUI.jar -FATJAR=altosui-fat.jar +FATJAR=AltosUI-fat.jar # Icons ICONDIR=$(top_srcdir)/icon @@ -172,7 +170,7 @@ MACOSX_EXTRA=$(FIRMWARE) WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON) -all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb +all-local: classes/AltosUI $(JAR) altosui altosui-test altosui-jdb clean-local: -rm -rf classes $(JAR) $(FATJAR) \ @@ -209,43 +207,43 @@ endif altosuidir=$(datadir)/java -install-altosuiJAVA: altosui.jar +install-altosuiJAVA: AltosUI.jar @$(NORMAL_INSTALL) test -z "$(altosuidir)" || $(MKDIR_P) "$(DESTDIR)$(altosuidir)" - echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/altosui.jar'"; \ + echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/AltosUI.jar'"; \ $(INSTALL_DATA) "$<" "$(DESTDIR)$(altosuidir)" -classes/altosui: - mkdir -p classes/altosui +classes/AltosUI: + mkdir -p classes/AltosUI $(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICON) $(ALTOSLIB_CLASS) jar cfm $@ Manifest.txt \ $(ICONJAR) \ - -C classes altosui \ + -C classes AltosUI \ -C libaltos libaltosJNI $(FATJAR): classaltosui.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICON) jar cfm $@ Manifest-fat.txt \ $(ICONJAR) \ - -C classes altosui \ + -C classes AltosUI \ -C libaltos libaltosJNI Manifest.txt: Makefile - echo 'Main-Class: altosui.AltosUI' > $@ + echo 'Main-Class: AltosUI.AltosUI' > $@ echo "Class-Path: AltosLib.jar $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@ Manifest-fat.txt: - echo 'Main-Class: altosui.AltosUI' > $@ + echo 'Main-Class: AltosUI.AltosUI' > $@ echo "Class-Path: AltosLib.jar freetts.jar jfreechart.jar jcommon.jar" >> $@ altosui: Makefile echo "#!/bin/sh" > $@ - echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/altosui.jar" "$$@"' >> $@ + echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/AltosUI.jar" "$$@"' >> $@ chmod +x $@ altosui-test: Makefile echo "#!/bin/sh" > $@ - echo 'exec java -cp "./*:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@ + echo 'exec java -cp "./*:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar AltosUI.jar "$$@"' >> $@ chmod +x $@ altosui-jdb: Makefile -- cgit v1.2.3 From 0bc3ed53aa8972c7080d6335f609cd9d0df1c79d Mon Sep 17 00:00:00 2001 From: Tom Marble Date: Tue, 11 Sep 2012 11:37:14 -0500 Subject: Use explicit build deps for altosui (avoids * wildcarding) --- altosui/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 9ca4f86e..aca2e8fc 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -6,7 +6,9 @@ man_MANS=altosui.1 altoslibdir=$(libdir)/altos -CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:libaltos:$(FREETTS)/*:/usr/share/java/*" +# tmarble: attempt to use specific build deps +# CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:libaltos:$(FREETTS)/*:/usr/share/java/*" +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:libaltos:/usr/share/java/jcommon.jar:/usr/share/java/jfreechart.jar:/usr/share/java/freetts.jar" bin_SCRIPTS=altosui -- cgit v1.2.3 From 13c64f6fb5764c6a0f3520cf4e48a75d78e163db Mon Sep 17 00:00:00 2001 From: Tom Marble Date: Tue, 11 Sep 2012 12:44:24 -0500 Subject: Add appropriate Java build deps as given from autoconf --- altosui/Makefile.am | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'altosui') diff --git a/altosui/Makefile.am b/altosui/Makefile.am index aca2e8fc..ca5d2b35 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -6,9 +6,7 @@ man_MANS=altosui.1 altoslibdir=$(libdir)/altos -# tmarble: attempt to use specific build deps -# CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:libaltos:$(FREETTS)/*:/usr/share/java/*" -CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:libaltos:/usr/share/java/jcommon.jar:/usr/share/java/jfreechart.jar:/usr/share/java/freetts.jar" +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:libaltos::$(JFREECHART)/jfreechart.jar:$(FREETTS)/freetts.jar" bin_SCRIPTS=altosui -- cgit v1.2.3 From 95268d681c9a6652d84db383f55a4fe8a4ac5173 Mon Sep 17 00:00:00 2001 From: Tom Marble Date: Tue, 11 Sep 2012 12:54:31 -0500 Subject: Reverted package name to 'altosui' from 'AltosUI' Also added emacs backup regex (*~) to .gitignore --- .gitignore | 2 +- altosui/Altos.java | 2 +- altosui/AltosAscent.java | 2 +- altosui/AltosBTDevice.java | 2 +- altosui/AltosBTDeviceIterator.java | 2 +- altosui/AltosBTKnown.java | 2 +- altosui/AltosBTManage.java | 2 +- altosui/AltosCSV.java | 2 +- altosui/AltosCSVUI.java | 2 +- altosui/AltosChannelMenu.java | 2 +- altosui/AltosCompanionInfo.java | 2 +- altosui/AltosConfig.java | 2 +- altosui/AltosConfigFreqUI.java | 2 +- altosui/AltosConfigTD.java | 2 +- altosui/AltosConfigTDUI.java | 2 +- altosui/AltosConfigUI.java | 2 +- altosui/AltosConfigureUI.java | 2 +- altosui/AltosDataChooser.java | 2 +- altosui/AltosDataPoint.java | 2 +- altosui/AltosDataPointReader.java | 2 +- altosui/AltosDebug.java | 2 +- altosui/AltosDescent.java | 2 +- altosui/AltosDevice.java | 2 +- altosui/AltosDeviceDialog.java | 2 +- altosui/AltosDialog.java | 2 +- altosui/AltosDisplayThread.java | 2 +- altosui/AltosEepromDelete.java | 2 +- altosui/AltosEepromDownload.java | 2 +- altosui/AltosEepromList.java | 2 +- altosui/AltosEepromManage.java | 2 +- altosui/AltosEepromMonitor.java | 2 +- altosui/AltosEepromSelect.java | 2 +- altosui/AltosFlash.java | 2 +- altosui/AltosFlashUI.java | 2 +- altosui/AltosFlightDisplay.java | 2 +- altosui/AltosFlightInfoTableModel.java | 2 +- altosui/AltosFlightStats.java | 2 +- altosui/AltosFlightStatsTable.java | 2 +- altosui/AltosFlightStatus.java | 2 +- altosui/AltosFlightStatusTableModel.java | 2 +- altosui/AltosFlightStatusUpdate.java | 2 +- altosui/AltosFlightUI.java | 2 +- altosui/AltosFontListener.java | 2 +- altosui/AltosFrame.java | 2 +- altosui/AltosFreqList.java | 2 +- altosui/AltosGraph.java | 2 +- altosui/AltosGraphTime.java | 2 +- altosui/AltosGraphUI.java | 2 +- altosui/AltosHexfile.java | 2 +- altosui/AltosIdleMonitorUI.java | 2 +- altosui/AltosIgniteUI.java | 2 +- altosui/AltosInfoTable.java | 2 +- altosui/AltosKML.java | 2 +- altosui/AltosLanded.java | 2 +- altosui/AltosLaunch.java | 2 +- altosui/AltosLaunchUI.java | 2 +- altosui/AltosLed.java | 2 +- altosui/AltosLights.java | 2 +- altosui/AltosPad.java | 2 +- altosui/AltosRomconfig.java | 2 +- altosui/AltosRomconfigUI.java | 2 +- altosui/AltosScanUI.java | 2 +- altosui/AltosSerial.java | 2 +- altosui/AltosSerialInUseException.java | 2 +- altosui/AltosSiteMap.java | 2 +- altosui/AltosSiteMapCache.java | 2 +- altosui/AltosSiteMapPreload.java | 2 +- altosui/AltosSiteMapTile.java | 2 +- altosui/AltosUI.java | 2 +- altosui/AltosUIListener.java | 2 +- altosui/AltosUIPreferences.java | 2 +- altosui/AltosUSBDevice.java | 2 +- altosui/AltosVersion.java.in | 2 +- altosui/AltosVoice.java | 2 +- altosui/AltosWriter.java | 2 +- altosui/GrabNDrag.java | 2 +- altosui/Makefile.am | 26 +++++++++++++------------- 77 files changed, 89 insertions(+), 89 deletions(-) (limited to 'altosui') diff --git a/.gitignore b/.gitignore index 782be7f6..9f33ea3c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*~ *.a *.adb *.asm @@ -41,7 +42,6 @@ autom4te.cache config.* config.h config.h.in -config.h.in~ config.log config.status build-stamp diff --git a/altosui/Altos.java b/altosui/Altos.java index d3aad6b2..cd17a93e 100644 --- a/altosui/Altos.java +++ b/altosui/Altos.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.util.*; diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index de6c90a1..a158eb21 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java index a6eee085..5e353fdd 100644 --- a/altosui/AltosBTDevice.java +++ b/altosui/AltosBTDevice.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosBTDeviceIterator.java b/altosui/AltosBTDeviceIterator.java index 8d9e6fe6..58ed86d5 100644 --- a/altosui/AltosBTDeviceIterator.java +++ b/altosui/AltosBTDeviceIterator.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java index ad0672c6..6a8e53cb 100644 --- a/altosui/AltosBTKnown.java +++ b/altosui/AltosBTKnown.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java index a411c83e..aeb964bb 100644 --- a/altosui/AltosBTManage.java +++ b/altosui/AltosBTManage.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index c672b78f..c876d9ca 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.io.*; diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java index a28c4ca6..2702668b 100644 --- a/altosui/AltosCSVUI.java +++ b/altosui/AltosCSVUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosChannelMenu.java b/altosui/AltosChannelMenu.java index d7e7f58f..0249a0bd 100644 --- a/altosui/AltosChannelMenu.java +++ b/altosui/AltosChannelMenu.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosCompanionInfo.java b/altosui/AltosCompanionInfo.java index 16c972b3..4ba8fe98 100644 --- a/altosui/AltosCompanionInfo.java +++ b/altosui/AltosCompanionInfo.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 0b386ac9..cae41858 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java index 4f8bd0f2..7958a21c 100644 --- a/altosui/AltosConfigFreqUI.java +++ b/altosui/AltosConfigFreqUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigTD.java b/altosui/AltosConfigTD.java index f5d30250..324a5988 100644 --- a/altosui/AltosConfigTD.java +++ b/altosui/AltosConfigTD.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigTDUI.java b/altosui/AltosConfigTDUI.java index f653d941..f2058f69 100644 --- a/altosui/AltosConfigTDUI.java +++ b/altosui/AltosConfigTDUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index b0624ef2..62394fa6 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosConfigureUI.java b/altosui/AltosConfigureUI.java index b46c1fae..da82e8e0 100644 --- a/altosui/AltosConfigureUI.java +++ b/altosui/AltosConfigureUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index b003a606..4bd51c39 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosDataPoint.java b/altosui/AltosDataPoint.java index 80f62c2c..5e077320 100644 --- a/altosui/AltosDataPoint.java +++ b/altosui/AltosDataPoint.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package AltosUI; +package altosui; interface AltosDataPoint { int version(); diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index 371c48cb..821b0771 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package AltosUI; +package altosui; import java.io.IOException; import java.text.ParseException; diff --git a/altosui/AltosDebug.java b/altosui/AltosDebug.java index 4e394011..23e38bc0 100644 --- a/altosui/AltosDebug.java +++ b/altosui/AltosDebug.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.io.*; diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index 2e3f26bd..62258814 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosDevice.java b/altosui/AltosDevice.java index dc045d7b..1b5c1a91 100644 --- a/altosui/AltosDevice.java +++ b/altosui/AltosDevice.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosDeviceDialog.java b/altosui/AltosDeviceDialog.java index 7ab08b30..fa9d0013 100644 --- a/altosui/AltosDeviceDialog.java +++ b/altosui/AltosDeviceDialog.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.util.*; diff --git a/altosui/AltosDialog.java b/altosui/AltosDialog.java index 1de11317..ff38c3e4 100644 --- a/altosui/AltosDialog.java +++ b/altosui/AltosDialog.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java index 0cf942e7..cf69c414 100644 --- a/altosui/AltosDisplayThread.java +++ b/altosui/AltosDisplayThread.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java index 21f09d0e..73f3a00f 100644 --- a/altosui/AltosEepromDelete.java +++ b/altosui/AltosEepromDelete.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index a4d6b26e..b04890cd 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index 2a88134c..6a656215 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java index 27b03bed..563c90b3 100644 --- a/altosui/AltosEepromManage.java +++ b/altosui/AltosEepromManage.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java index daf8d0ba..75643442 100644 --- a/altosui/AltosEepromMonitor.java +++ b/altosui/AltosEepromMonitor.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java index cb242183..4ad78896 100644 --- a/altosui/AltosEepromSelect.java +++ b/altosui/AltosEepromSelect.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.util.*; diff --git a/altosui/AltosFlash.java b/altosui/AltosFlash.java index 996456fd..bd0c8a50 100644 --- a/altosui/AltosFlash.java +++ b/altosui/AltosFlash.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index 01421de9..66991d10 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightDisplay.java b/altosui/AltosFlightDisplay.java index e677fd6f..826f9522 100644 --- a/altosui/AltosFlightDisplay.java +++ b/altosui/AltosFlightDisplay.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import org.altusmetrum.AltosLib.*; diff --git a/altosui/AltosFlightInfoTableModel.java b/altosui/AltosFlightInfoTableModel.java index cb798bcb..77969a89 100644 --- a/altosui/AltosFlightInfoTableModel.java +++ b/altosui/AltosFlightInfoTableModel.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index d37f90b8..ab094c80 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java index bcfdd84e..87ba6aa8 100644 --- a/altosui/AltosFlightStatsTable.java +++ b/altosui/AltosFlightStatsTable.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStatus.java b/altosui/AltosFlightStatus.java index ee03698b..6a351004 100644 --- a/altosui/AltosFlightStatus.java +++ b/altosui/AltosFlightStatus.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStatusTableModel.java b/altosui/AltosFlightStatusTableModel.java index 919c7704..c2cf8cd1 100644 --- a/altosui/AltosFlightStatusTableModel.java +++ b/altosui/AltosFlightStatusTableModel.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightStatusUpdate.java b/altosui/AltosFlightStatusUpdate.java index a0b4e304..d70fc7f8 100644 --- a/altosui/AltosFlightStatusUpdate.java +++ b/altosui/AltosFlightStatusUpdate.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index 08e8550f..ddc54cbd 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFontListener.java b/altosui/AltosFontListener.java index a0cb8a56..0dda0f29 100644 --- a/altosui/AltosFontListener.java +++ b/altosui/AltosFontListener.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; public interface AltosFontListener { void font_size_changed(int font_size); diff --git a/altosui/AltosFrame.java b/altosui/AltosFrame.java index cdbfe7d3..70598634 100644 --- a/altosui/AltosFrame.java +++ b/altosui/AltosFrame.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosFreqList.java b/altosui/AltosFreqList.java index a17afce6..1bbc97c6 100644 --- a/altosui/AltosFreqList.java +++ b/altosui/AltosFreqList.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosGraph.java b/altosui/AltosGraph.java index a61a0976..54d2bb0b 100644 --- a/altosui/AltosGraph.java +++ b/altosui/AltosGraph.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package AltosUI; +package altosui; import java.io.*; diff --git a/altosui/AltosGraphTime.java b/altosui/AltosGraphTime.java index f00170ec..0955f6e6 100644 --- a/altosui/AltosGraphTime.java +++ b/altosui/AltosGraphTime.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package AltosUI; +package altosui; import java.lang.*; import java.io.*; diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index b571fc7d..527a7d28 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -2,7 +2,7 @@ // Copyright (c) 2010 Anthony Towns // GPL v2 or later -package AltosUI; +package altosui; import java.io.*; import java.util.ArrayList; diff --git a/altosui/AltosHexfile.java b/altosui/AltosHexfile.java index 435f13ee..d52b46c3 100644 --- a/altosui/AltosHexfile.java +++ b/altosui/AltosHexfile.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.io.*; diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index f67644fc..46ca3e5d 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 8c4c939f..78eba8e6 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java index 8caf5a80..c1400976 100644 --- a/altosui/AltosInfoTable.java +++ b/altosui/AltosInfoTable.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosKML.java b/altosui/AltosKML.java index 7e3b0e08..ff0734b8 100644 --- a/altosui/AltosKML.java +++ b/altosui/AltosKML.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.io.*; diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 5c3111a2..a47e1cbd 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosLaunch.java b/altosui/AltosLaunch.java index 67512cef..0e493b91 100644 --- a/altosui/AltosLaunch.java +++ b/altosui/AltosLaunch.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.io.*; import java.util.concurrent.*; diff --git a/altosui/AltosLaunchUI.java b/altosui/AltosLaunchUI.java index a4f12997..44481544 100644 --- a/altosui/AltosLaunchUI.java +++ b/altosui/AltosLaunchUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosLed.java b/altosui/AltosLed.java index 4bf43a53..1358cd48 100644 --- a/altosui/AltosLed.java +++ b/altosui/AltosLed.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosLights.java b/altosui/AltosLights.java index 92d11212..8bd9e7de 100644 --- a/altosui/AltosLights.java +++ b/altosui/AltosLights.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosPad.java b/altosui/AltosPad.java index 8006190d..0a3f3d65 100644 --- a/altosui/AltosPad.java +++ b/altosui/AltosPad.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosRomconfig.java b/altosui/AltosRomconfig.java index 1e3d7294..0a283e51 100644 --- a/altosui/AltosRomconfig.java +++ b/altosui/AltosRomconfig.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.io.*; import org.altusmetrum.AltosLib.*; diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java index 25d8d087..306b8623 100644 --- a/altosui/AltosRomconfigUI.java +++ b/altosui/AltosRomconfigUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java index 534451cb..9da1290f 100644 --- a/altosui/AltosScanUI.java +++ b/altosui/AltosScanUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java index 61865bbd..6cee1609 100644 --- a/altosui/AltosSerial.java +++ b/altosui/AltosSerial.java @@ -19,7 +19,7 @@ * Deal with TeleDongle on a serial port */ -package AltosUI; +package altosui; import java.lang.*; import java.io.*; diff --git a/altosui/AltosSerialInUseException.java b/altosui/AltosSerialInUseException.java index ae97b3d2..7380f331 100644 --- a/altosui/AltosSerialInUseException.java +++ b/altosui/AltosSerialInUseException.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; public class AltosSerialInUseException extends Exception { public AltosDevice device; diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java index 4195fc3f..b57edcab 100644 --- a/altosui/AltosSiteMap.java +++ b/altosui/AltosSiteMap.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.image.*; diff --git a/altosui/AltosSiteMapCache.java b/altosui/AltosSiteMapCache.java index 6e7e423b..f729a298 100644 --- a/altosui/AltosSiteMapCache.java +++ b/altosui/AltosSiteMapCache.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.image.*; diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java index 8c0850fa..676b0790 100644 --- a/altosui/AltosSiteMapPreload.java +++ b/altosui/AltosSiteMapPreload.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.image.*; diff --git a/altosui/AltosSiteMapTile.java b/altosui/AltosSiteMapTile.java index 1e1cca5a..34550219 100644 --- a/altosui/AltosSiteMapTile.java +++ b/altosui/AltosSiteMapTile.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.image.*; diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index a1678299..926d66f0 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.event.*; diff --git a/altosui/AltosUIListener.java b/altosui/AltosUIListener.java index e50b30b2..7ee62afc 100644 --- a/altosui/AltosUIListener.java +++ b/altosui/AltosUIListener.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; public interface AltosUIListener { public void ui_changed(String look_and_feel); diff --git a/altosui/AltosUIPreferences.java b/altosui/AltosUIPreferences.java index 010d8e6a..10ab26c3 100644 --- a/altosui/AltosUIPreferences.java +++ b/altosui/AltosUIPreferences.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.io.*; import java.util.*; diff --git a/altosui/AltosUSBDevice.java b/altosui/AltosUSBDevice.java index 0c953cbf..ed5f8307 100644 --- a/altosui/AltosUSBDevice.java +++ b/altosui/AltosUSBDevice.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.util.*; import libaltosJNI.*; diff --git a/altosui/AltosVersion.java.in b/altosui/AltosVersion.java.in index d72e0936..b0b3c0cf 100644 --- a/altosui/AltosVersion.java.in +++ b/altosui/AltosVersion.java.in @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; public class AltosVersion { public final static String version = "@VERSION@"; diff --git a/altosui/AltosVoice.java b/altosui/AltosVoice.java index ff83ac29..ab74e0b3 100644 --- a/altosui/AltosVoice.java +++ b/altosui/AltosVoice.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import com.sun.speech.freetts.Voice; import com.sun.speech.freetts.VoiceManager; diff --git a/altosui/AltosWriter.java b/altosui/AltosWriter.java index 9031c268..b7375204 100644 --- a/altosui/AltosWriter.java +++ b/altosui/AltosWriter.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.lang.*; import java.io.*; diff --git a/altosui/GrabNDrag.java b/altosui/GrabNDrag.java index a984c43e..c350efec 100644 --- a/altosui/GrabNDrag.java +++ b/altosui/GrabNDrag.java @@ -15,7 +15,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package AltosUI; +package altosui; import java.awt.*; import java.awt.image.*; diff --git a/altosui/Makefile.am b/altosui/Makefile.am index ca5d2b35..9f75d5e3 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -112,9 +112,9 @@ LIBALTOS= \ libaltos.dylib \ altos.dll -JAR=AltosUI.jar +JAR=altosui.jar -FATJAR=AltosUI-fat.jar +FATJAR=altosui-fat.jar # Icons ICONDIR=$(top_srcdir)/icon @@ -170,7 +170,7 @@ MACOSX_EXTRA=$(FIRMWARE) WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON) -all-local: classes/AltosUI $(JAR) altosui altosui-test altosui-jdb +all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb clean-local: -rm -rf classes $(JAR) $(FATJAR) \ @@ -207,43 +207,43 @@ endif altosuidir=$(datadir)/java -install-altosuiJAVA: AltosUI.jar +install-altosuiJAVA: altosui.jar @$(NORMAL_INSTALL) test -z "$(altosuidir)" || $(MKDIR_P) "$(DESTDIR)$(altosuidir)" - echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/AltosUI.jar'"; \ + echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/altosui.jar'"; \ $(INSTALL_DATA) "$<" "$(DESTDIR)$(altosuidir)" -classes/AltosUI: - mkdir -p classes/AltosUI +classes/altosui: + mkdir -p classes/altosui $(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICON) $(ALTOSLIB_CLASS) jar cfm $@ Manifest.txt \ $(ICONJAR) \ - -C classes AltosUI \ + -C classes altosui \ -C libaltos libaltosJNI $(FATJAR): classaltosui.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICON) jar cfm $@ Manifest-fat.txt \ $(ICONJAR) \ - -C classes AltosUI \ + -C classes altosui \ -C libaltos libaltosJNI Manifest.txt: Makefile - echo 'Main-Class: AltosUI.AltosUI' > $@ + echo 'Main-Class: altosui.AltosUI' > $@ echo "Class-Path: AltosLib.jar $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@ Manifest-fat.txt: - echo 'Main-Class: AltosUI.AltosUI' > $@ + echo 'Main-Class: altosui.AltosUI' > $@ echo "Class-Path: AltosLib.jar freetts.jar jfreechart.jar jcommon.jar" >> $@ altosui: Makefile echo "#!/bin/sh" > $@ - echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/AltosUI.jar" "$$@"' >> $@ + echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/altosui.jar" "$$@"' >> $@ chmod +x $@ altosui-test: Makefile echo "#!/bin/sh" > $@ - echo 'exec java -cp "./*:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar AltosUI.jar "$$@"' >> $@ + echo 'exec java -cp "./*:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@ chmod +x $@ altosui-jdb: Makefile -- cgit v1.2.3 From 7ae3e4cea1cd180ff18b5293a67b4520cc8292be Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 11 Sep 2012 01:00:05 -0700 Subject: altosui: Imperial units for graphs too Just to be consistent Signed-off-by: Keith Packard --- altosui/AltosGraphUI.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'altosui') diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 527a7d28..edde1307 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -35,16 +35,16 @@ public class AltosGraphUI extends AltosFrame static private class OverallGraphs { AltosGraphTime.Element height = - new AltosGraphTime.TimeSeries("Height (m)", "Height (AGL)", red) { + new AltosGraphTime.TimeSeries(String.format("Height (%s)", AltosConvert.height.show_units()), "Height (AGL)", red) { public void gotTimeData(double time, AltosDataPoint d) { double height = d.height(); if (height != AltosRecord.MISSING) - series.add(time, d.height()); + series.add(time, AltosConvert.height.value(height)); } }; AltosGraphTime.Element speed = - new AltosGraphTime.TimeSeries("Speed (m/s)", "Vertical Speed", green) { + new AltosGraphTime.TimeSeries(String.format("Speed (%s)", AltosConvert.speed.show_units()), "Vertical Speed", green) { public void gotTimeData(double time, AltosDataPoint d) { double speed; if (d.state() < Altos.ao_flight_drogue && d.has_accel()) { @@ -53,18 +53,19 @@ public class AltosGraphUI extends AltosFrame speed = d.baro_speed(); } if (speed != AltosRecord.MISSING) - series.add(time, speed); + series.add(time, AltosConvert.speed.value(speed)); } }; AltosGraphTime.Element acceleration = - new AltosGraphTime.TimeSeries("Acceleration (m/s\u00B2)", - "Axial Acceleration", blue) + new AltosGraphTime.TimeSeries(String.format("Acceleration (%s)", + AltosConvert.accel.show_units()), + "Axial Acceleration", blue) { public void gotTimeData(double time, AltosDataPoint d) { double acceleration = d.acceleration(); if (acceleration != AltosRecord.MISSING) - series.add(time, acceleration); + series.add(time, AltosConvert.accel.value(acceleration)); } }; -- cgit v1.2.3