summaryrefslogtreecommitdiff
path: root/micropeak
diff options
context:
space:
mode:
Diffstat (limited to 'micropeak')
-rw-r--r--micropeak/.gitignore6
-rw-r--r--micropeak/FTDI.tar.gzbin0 -> 251029 bytes
-rw-r--r--micropeak/Info.plist.in50
-rw-r--r--micropeak/Makefile.am239
-rw-r--r--micropeak/MicroData.java344
-rw-r--r--micropeak/MicroDataPoint.java42
-rw-r--r--micropeak/MicroDeviceDialog.java50
-rw-r--r--micropeak/MicroDownload.java144
-rw-r--r--micropeak/MicroExport.java105
-rw-r--r--micropeak/MicroFile.java45
-rw-r--r--micropeak/MicroFileChooser.java55
-rw-r--r--micropeak/MicroFrame.java37
-rw-r--r--micropeak/MicroGraph.java173
-rwxr-xr-xmicropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStubbin0 -> 61296 bytes
-rw-r--r--micropeak/MicroPeak.app/Contents/PkgInfo1
-rw-r--r--micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icnsbin0 -> 133711 bytes
-rw-r--r--micropeak/MicroPeak.java305
-rw-r--r--micropeak/MicroRaw.java45
-rw-r--r--micropeak/MicroSave.java107
-rw-r--r--micropeak/MicroSerial.java55
-rw-r--r--micropeak/MicroStats.java162
-rw-r--r--micropeak/MicroStatsTable.java138
-rw-r--r--micropeak/MicroUSB.java109
-rw-r--r--micropeak/ReadMe-Mac.rtf19
-rwxr-xr-xmicropeak/micropeak-fat4
-rw-r--r--micropeak/micropeak-windows.nsi123
26 files changed, 2358 insertions, 0 deletions
diff --git a/micropeak/.gitignore b/micropeak/.gitignore
new file mode 100644
index 00000000..fc99b31c
--- /dev/null
+++ b/micropeak/.gitignore
@@ -0,0 +1,6 @@
+*.jar
+Manifest.txt
+classes
+*.stamp
+micropeak
+micropeak-test
diff --git a/micropeak/FTDI.tar.gz b/micropeak/FTDI.tar.gz
new file mode 100644
index 00000000..cd08ecf2
--- /dev/null
+++ b/micropeak/FTDI.tar.gz
Binary files differ
diff --git a/micropeak/Info.plist.in b/micropeak/Info.plist.in
new file mode 100644
index 00000000..40984c5a
--- /dev/null
+++ b/micropeak/Info.plist.in
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleName</key>
+ <string>MicroPeak</string>
+ <key>CFBundleVersion</key>
+ <string>@VERSION@</string>
+ <key>CFBundleAllowMixedLocalizations</key>
+ <string>true</string>
+ <key>CFBundleExecutable</key>
+ <string>JavaApplicationStub</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.altusmetrum.micropeak</string>
+ <key>CFBundleSignature</key>
+ <string>Altu</string>
+ <key>CFBundleGetInfoString</key>
+ <string>MicroPeak UI version @VERSION@</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleIconFile</key>
+ <string>MicroPeak.icns</string>
+ <key>Java</key>
+ <dict>
+ <key>MainClass</key>
+ <string>org.altusmetrum.micropeak.MicroPeak</string>
+ <key>JVMVersion</key>
+ <string>1.5+</string>
+ <key>ClassPath</key>
+ <array>
+ <string>$JAVAROOT/micropeak.jar</string>
+ </array>
+ <key>Properties</key>
+ <dict>
+ <key>apple.laf.useScreenMenuBar</key>
+ <string>true</string>
+ </dict>
+ <key>VMOptions</key>
+ <array>
+ <string>-Xms512M</string>
+ <string>-Xmx512M</string>
+ <string>-Dosgi.clean=true</string>
+ </array>
+ </dict>
+</dict>
+</plist>
diff --git a/micropeak/Makefile.am b/micropeak/Makefile.am
new file mode 100644
index 00000000..b80cabf2
--- /dev/null
+++ b/micropeak/Makefile.am
@@ -0,0 +1,239 @@
+JAVAROOT=classes
+AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+
+CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:../altosuilib/*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar"
+
+bin_SCRIPTS=micropeak
+
+micropeakdir=$(datadir)/java
+
+micropeak_JAVA= \
+ MicroPeak.java \
+ MicroData.java \
+ MicroDataPoint.java \
+ MicroDownload.java \
+ MicroExport.java \
+ MicroFile.java \
+ MicroFrame.java \
+ MicroGraph.java \
+ MicroRaw.java \
+ MicroSave.java \
+ MicroSerial.java \
+ MicroStats.java \
+ MicroStatsTable.java \
+ MicroFileChooser.java \
+ MicroDeviceDialog.java \
+ MicroUSB.java
+
+JFREECHART_CLASS= \
+ jfreechart.jar
+
+JCOMMON_CLASS=\
+ jcommon.jar
+
+JAR=micropeak.jar
+
+FATJAR=micropeak-fat.jar
+
+LIBALTOS= \
+ libaltos.so \
+ libaltos.dylib \
+ altos64.dll \
+ altos.dll
+
+ALTOSLIB_CLASS=\
+ AltosLib.jar
+
+ALTOSUILIB_CLASS=\
+ altosuilib.jar
+
+# Icons
+ICONDIR=$(top_srcdir)/icon
+
+JAVA_ICONS=\
+ $(ICONDIR)/micropeak-16.png \
+ $(ICONDIR)/micropeak-32.png \
+ $(ICONDIR)/micropeak-48.png \
+ $(ICONDIR)/micropeak-64.png \
+ $(ICONDIR)/micropeak-128.png \
+ $(ICONDIR)/micropeak-256.png
+
+# icon base names for jar
+ICONJAR= -C $(ICONDIR) micropeak-16.png \
+ -C $(ICONDIR) micropeak-32.png \
+ -C $(ICONDIR) micropeak-48.png \
+ -C $(ICONDIR) micropeak-64.png \
+ -C $(ICONDIR) micropeak-128.png \
+ -C $(ICONDIR) micropeak-256.png
+
+WINDOWS_ICON=$(ICONDIR)/micro-peak.ico
+
+all-local: micropeak-test micropeak-jdb $(JAR)
+
+clean-local:
+ -rm -rf classes $(JAR) $(FATJAR) \
+ $(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) \
+ $(ALTOSLIB_CLASS) \
+ $(ALTOSUILIB_CLASS) \
+ $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt \
+ micropeak micropeak-test macosx linux windows
+
+LINUX_DIST=MicroPeak-Linux-$(VERSION).tar.bz2
+MACOSX_DIST=MicroPeak-Mac-$(VERSION).dmg
+WINDOWS_DIST=MicroPeak-Windows-$(VERSION_DASH).exe
+
+FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS)
+
+LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC)
+LINUX_EXTRA=micropeak-fat
+
+MACOSX_INFO_PLIST=Info.plist
+MACOSX_DRIVER=FTDI.tar.gz
+MACOSX_README=ReadMe-Mac.rtf
+MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(MACOSX_DRIVER) $(MACOSX_README)
+
+WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON)
+
+if FATINSTALL
+
+FATTARGET=$(FATDIR)/$(VERSION)
+
+LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
+MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
+WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
+
+fat: $(LINUX_DIST_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
+
+$(LINUX_DIST_TARGET): $(LINUX_DIST)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+$(MACOSX_DIST_TARGET): $(MACOSX_DIST)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+$(WINDOWS_DIST_TARGET): $(WINDOWS_DIST)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+else
+fat: $(LINUX_DIST) $(MACOSX_DIST) $(WINDOWS_DIST)
+endif
+
+micropeak: Makefile
+ echo "#!/bin/sh" > $@
+ echo 'exec java -cp "$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="$(altoslibdir)" -jar "$(micropeakdir)/micropeak.jar" "$$@"' >> $@
+ chmod +x $@
+
+micropeak-jdb: Makefile
+ echo "#!/bin/sh" > $@
+ echo 'exec jdb -classpath "classes:./*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="../libaltos/.libs" org.altusmetrum.micropeak.MicroPeak "$$@"' >> $@
+ chmod +x $@
+
+micropeak-test: Makefile
+ echo "#!/bin/sh" > $@
+ echo 'exec java -cp "./*:../libaltos/*:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="../libaltos/.libs" -jar micropeak.jar "$$@"' >> $@
+ chmod +x $@
+
+install-micropeakJAVA: micropeak.jar
+ @$(NORMAL_INSTALL)
+ test -z "$(micropeakdir)" || $(MKDIR_P) "$(DESTDIR)$(micropeakdir)"
+ echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(micropeakdir)/micropeak.jar'"; \
+ $(INSTALL_DATA) "$<" "$(DESTDIR)$(micropeakdir)"
+
+$(JAR): classmicropeak.stamp Manifest.txt $(JAVA_ICONS) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)
+ jar cfm $@ Manifest.txt \
+ $(ICONJAR) \
+ -C classes org \
+ -C ../libaltos libaltosJNI
+
+$(FATJAR): classmicropeak.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(JAVA_ICONS)
+ jar cfm $@ Manifest-fat.txt \
+ $(ICONJAR) \
+ -C classes org \
+ -C ../libaltos libaltosJNI
+
+libaltos.so: build-libaltos
+ -rm -f "$@"
+ $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos.dylib:
+ -rm -f "$@"
+ $(LN_S) ../libaltos/"$@" .
+
+altos.dll: ../libaltos/altos.dll
+ -rm -f "$@"
+ $(LN_S) ../libaltos/"$@" .
+
+altos64.dll: ../libaltos/altos64.dll
+ -rm -f "$@"
+ $(LN_S) ../libaltos/"$@" .
+
+../libaltos/.libs/libaltos.so: build-libaltos
+
+../libaltos/altos.dll: build-altos-dll
+
+../libaltos/altos64.dll: build-altos64-dll
+
+build-libaltos:
+ +cd ../libaltos && make libaltos.la
+build-altos-dll:
+ +cd ../libaltos && make altos.dll
+
+build-altos64-dll:
+ +cd ../libaltos && make altos64.dll
+
+$(ALTOSLIB_CLASS):
+ -rm -f "$@"
+ $(LN_S) ../altoslib/"$@" .
+
+$(ALTOSUILIB_CLASS):
+ -rm -f "$@"
+ $(LN_S) ../altosuilib/"$@" .
+
+$(JFREECHART_CLASS):
+ -rm -f "$@"
+ $(LN_S) "$(JFREECHART)"/"$@" .
+
+$(JCOMMON_CLASS):
+ -rm -f "$@"
+ $(LN_S) "$(JCOMMON)"/"$@" .
+
+$(LINUX_DIST): $(LINUX_FILES) $(LINUX_EXTRA)
+ -rm -f $@
+ -rm -rf linux
+ mkdir -p linux/MicroPeak
+ cp -p $(LINUX_FILES) linux/MicroPeak
+ cp -p micropeak-fat linux/MicroPeak/micropeak
+ chmod +x linux/MicroPeak/micropeak
+ tar cjf $@ -C linux MicroPeak
+
+$(MACOSX_DIST): $(MACOSX_FILES)
+ -rm -f $@
+ -rm -rf macosx
+ mkdir macosx
+ cp -a MicroPeak.app macosx/
+ cp -a $(MACOSX_README) macosx/ReadMe.rtf
+ cp -p Info.plist macosx/MicroPeak.app/Contents
+ tar xzf $(MACOSX_DRIVER) -C macosx
+ mkdir -p macosx/MicroPeak.app/Contents/Resources/Java
+ cp -p $(FATJAR) macosx/MicroPeak.app/Contents/Resources/Java/micropeak.jar
+ cp -p libaltos.dylib macosx/MicroPeak.app/Contents/Resources/Java
+ cp -p $(ALTOSLIB_CLASS) macosx/MicroPeak.app/Contents/Resources/Java
+ cp -p $(ALTOSUILIB_CLASS) macosx/MicroPeak.app/Contents/Resources/Java
+ cp -p $(JFREECHART_CLASS) macosx/MicroPeak.app/Contents/Resources/Java
+ cp -p $(JCOMMON_CLASS) macosx/MicroPeak.app/Contents/Resources/Java
+ genisoimage -D -V MicroPeak-$(VERSION) -no-pad -r -apple -o $@ macosx
+
+$(WINDOWS_DIST): $(WINDOWS_FILES) micropeak-windows.nsi
+ -rm -f $@
+ makensis -Omicropeak-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" micropeak-windows.nsi
+
+Manifest.txt: Makefile
+ echo 'Main-Class: org.altusmetrum.micropeak.MicroPeak' > $@
+ echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(JCOMMON)/jcommon.jar $(JFREECHART)/jfreechart.jar" >> $@
+
+Manifest-fat.txt:
+ echo 'Main-Class: org.altusmetrum.micropeak.MicroPeak' > $@
+ echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) jcommon.jar jfreechart.jar" >> $@
+
diff --git a/micropeak/MicroData.java b/micropeak/MicroData.java
new file mode 100644
index 00000000..f1204e11
--- /dev/null
+++ b/micropeak/MicroData.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.lang.*;
+import java.io.*;
+import java.util.*;
+import org.altusmetrum.AltosLib.*;
+
+class MicroIterator implements Iterator<MicroDataPoint> {
+ int i;
+ MicroData data;
+
+ public boolean hasNext() {
+ return i < data.pressures.length;
+ }
+
+ public MicroDataPoint next() {
+ return new MicroDataPoint(data, i++);
+ }
+
+ public MicroIterator (MicroData data) {
+ this.data = data;
+ i = 0;
+ }
+
+ public void remove() {
+ }
+}
+
+class MicroIterable implements Iterable<MicroDataPoint> {
+
+ MicroData data;
+
+ public Iterator<MicroDataPoint> iterator() {
+ return new MicroIterator(data);
+ }
+
+ public MicroIterable(MicroData data) {
+ this.data = data;
+ }
+}
+
+public class MicroData {
+ public int ground_pressure;
+ public int min_pressure;
+ public int[] pressures;
+ private double time_step;
+ private double ground_altitude;
+ private ArrayList<Integer> bytes;
+ String name;
+
+
+ class FileEndedException extends Exception {
+ }
+
+ class NonHexcharException extends Exception {
+ }
+
+ class InvalidCrcException extends Exception {
+ }
+
+ private int getc(InputStream f) throws IOException, FileEndedException {
+ int c = f.read();
+
+ if (c == -1)
+ throw new FileEndedException();
+ bytes.add(c);
+ return c;
+ }
+
+ private int get_nonwhite(InputStream f) throws IOException, FileEndedException {
+ int c;
+
+ for (;;) {
+ c = getc(f);
+ if (!Character.isWhitespace(c))
+ return c;
+ }
+ }
+
+ private int get_hexc(InputStream f) throws IOException, FileEndedException, NonHexcharException {
+ int c = get_nonwhite(f);
+
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ throw new NonHexcharException();
+ }
+
+ private static final int POLY = 0x8408;
+
+ private int log_crc(int crc, int b) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (((crc & 0x0001) ^ (b & 0x0001)) != 0)
+ crc = (crc >> 1) ^ POLY;
+ else
+ crc = crc >> 1;
+ b >>= 1;
+ }
+ return crc & 0xffff;
+ }
+
+ int file_crc;
+
+ private int get_hex(InputStream f) throws IOException, FileEndedException, NonHexcharException {
+ int a = get_hexc(f);
+ int b = get_hexc(f);
+
+ int h = (a << 4) + b;
+
+ file_crc = log_crc(file_crc, h);
+ return h;
+ }
+
+ private boolean find_header(InputStream f) throws IOException {
+ try {
+ for (;;) {
+ if (get_nonwhite(f) == 'M' && get_nonwhite(f) == 'P')
+ return true;
+ }
+ } catch (FileEndedException fe) {
+ return false;
+ }
+ }
+
+ private int get_32(InputStream f) throws IOException, FileEndedException, NonHexcharException {
+ int v = 0;
+ for (int i = 0; i < 4; i++) {
+ v += get_hex(f) << (i * 8);
+ }
+ return v;
+ }
+
+ private int get_16(InputStream f) throws IOException, FileEndedException, NonHexcharException {
+ int v = 0;
+ for (int i = 0; i < 2; i++) {
+ v += get_hex(f) << (i * 8);
+ }
+ return v;
+ }
+
+ private int swap16(int i) {
+ return ((i << 8) & 0xff00) | ((i >> 8) & 0xff);
+ }
+
+ public boolean crc_valid;
+
+ int mix_in (int high, int low) {
+ return high - (high & 0xffff) + low;
+ }
+
+ boolean closer (int target, int a, int b) {
+ return Math.abs (target - a) < Math.abs(target - b);
+ }
+
+ public double altitude(int i) {
+ return AltosConvert.pressure_to_altitude(pressures[i]);
+ }
+
+ public Iterable<MicroDataPoint> points() {
+ return new MicroIterable(this);
+ }
+
+ int fact(int n) {
+ if (n == 0)
+ return 1;
+ return n * fact(n-1);
+ }
+
+ int choose(int n, int k) {
+ return fact(n) / (fact(k) * fact(n-k));
+ }
+
+
+ public double avg_altitude(int center, int dist) {
+ int start = center - dist;
+ int stop = center + dist;
+
+ if (start < 0)
+ start = 0;
+ if (stop >= pressures.length)
+ stop = pressures.length - 1;
+
+ double sum = 0;
+ double div = 0;
+
+ int n = dist * 2;
+
+ for (int i = start; i <= stop; i++) {
+ int k = i - (center - dist);
+ int c = choose (n, k);
+
+ sum += c * pressures[i];
+ div += c;
+ }
+
+ double pres = sum / div;
+
+ double alt = AltosConvert.pressure_to_altitude(pres);
+ return alt;
+ }
+
+ public double pressure(int i) {
+ return pressures[i];
+ }
+
+ public double height(int i) {
+ return altitude(i) - ground_altitude;
+ }
+
+ static final int speed_avg = 3;
+ static final int accel_avg = 5;
+
+ private double avg_speed(int center, int dist) {
+ if (center == 0)
+ return 0;
+
+ double ai = avg_altitude(center, dist);
+ double aj = avg_altitude(center - 1, dist);
+ double s = (ai - aj) / time_step;
+
+ return s;
+ }
+
+ public double speed(int i) {
+ return avg_speed(i, speed_avg);
+ }
+
+ public double acceleration(int i) {
+ if (i == 0)
+ return 0;
+ return (avg_speed(i, accel_avg) - avg_speed(i-1, accel_avg)) / time_step;
+ }
+
+ public double time(int i) {
+ return i * time_step;
+ }
+
+ public void save (OutputStream f) throws IOException {
+ for (int c : bytes)
+ f.write(c);
+ f.write('\n');
+ }
+
+ public void export (Writer f) throws IOException {
+ PrintWriter pw = new PrintWriter(f);
+ pw.printf(" Time, Press(Pa), Height(m), Height(f), Speed(m/s), Speed(mph), Speed(mach), Accel(m/s²), Accel(ft/s²), Accel(g)\n");
+ for (MicroDataPoint point : points()) {
+ pw.printf("%6.3f,%10.0f,%10.1f,%10.1f,%11.2f,%11.2f,%12.4f,%12.2f,%13.2f,%10.4f\n",
+ point.time,
+ point.pressure,
+ point.height,
+ AltosConvert.meters_to_feet(point.height),
+ point.speed,
+ AltosConvert.meters_to_mph(point.speed),
+ AltosConvert.meters_to_mach(point.speed),
+ point.accel,
+ AltosConvert.meters_to_feet(point.accel),
+ AltosConvert.meters_to_g(point.accel));
+ }
+ }
+
+ public void set_name(String name) {
+ this.name = name;
+ }
+
+ public MicroData (InputStream f, String name) throws IOException, InterruptedException {
+ this.name = name;
+ bytes = new ArrayList<Integer>();
+ if (!find_header(f))
+ throw new IOException("No MicroPeak data header found");
+ try {
+ file_crc = 0xffff;
+ ground_pressure = get_32(f);
+ min_pressure = get_32(f);
+ int nsamples = get_16(f);
+ pressures = new int[nsamples + 1];
+
+ ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure);
+ int cur = ground_pressure;
+ pressures[0] = cur;
+ for (int i = 0; i < nsamples; i++) {
+ int k = get_16(f);
+ int same = mix_in(cur, k);
+ int up = mix_in(cur + 0x10000, k);
+ int down = mix_in(cur - 0x10000, k);
+
+ if (closer (cur, same, up)) {
+ if (closer (cur, same, down))
+ cur = same;
+ else
+ cur = down;
+ } else {
+ if (closer (cur, up, down))
+ cur = up;
+ else
+ cur = down;
+ }
+
+ pressures[i+1] = cur;
+ }
+
+ int current_crc = swap16(~file_crc & 0xffff);
+ int crc = get_16(f);
+
+ crc_valid = crc == current_crc;
+
+ time_step = 0.192;
+ } catch (FileEndedException fe) {
+ throw new IOException("File Ended Unexpectedly");
+ } catch (NonHexcharException ne) {
+ throw new IOException("Non hexadecimal character found");
+ }
+ }
+
+ public MicroData() {
+ ground_pressure = 101000;
+ min_pressure = 101000;
+ pressures = new int[1];
+ pressures[0] = 101000;
+ }
+
+}
diff --git a/micropeak/MicroDataPoint.java b/micropeak/MicroDataPoint.java
new file mode 100644
index 00000000..c58708e6
--- /dev/null
+++ b/micropeak/MicroDataPoint.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+public class MicroDataPoint {
+ public double time;
+ public double pressure;
+ public double height;
+ public double speed;
+ public double accel;
+
+ public MicroDataPoint (double pressure, double height, double speed, double accel, double time) {
+ this.pressure = pressure;
+ this.height = height;
+ this.speed = speed;
+ this.accel = accel;
+ this.time = time;
+ }
+
+ public MicroDataPoint(MicroData data, int i) {
+ this(data.pressure(i),
+ data.height(i),
+ data.speed(i),
+ data.acceleration(i),
+ data.time(i));
+ }
+} \ No newline at end of file
diff --git a/micropeak/MicroDeviceDialog.java b/micropeak/MicroDeviceDialog.java
new file mode 100644
index 00000000..7b8a630c
--- /dev/null
+++ b/micropeak/MicroDeviceDialog.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroDeviceDialog extends AltosDeviceDialog {
+
+ public AltosDevice[] devices() {
+ java.util.List<MicroUSB> list = MicroUSB.list();
+ int num_devices = list.size();
+ AltosDevice[] devices = new AltosDevice[num_devices];
+
+ for (int i = 0; i < num_devices; i++)
+ devices[i] = list.get(i);
+ return devices;
+ }
+
+ public MicroDeviceDialog (Frame in_frame, Component location) {
+ super(in_frame, location, 0);
+ }
+
+ public static AltosDevice show (Component frameComp) {
+ Frame frame = JOptionPane.getFrameForComponent(frameComp);
+ MicroDeviceDialog dialog;
+
+ dialog = new MicroDeviceDialog (frame, frameComp);
+ dialog.setVisible(true);
+ return dialog.getValue();
+ }
+}
diff --git a/micropeak/MicroDownload.java b/micropeak/MicroDownload.java
new file mode 100644
index 00000000..28a7550d
--- /dev/null
+++ b/micropeak/MicroDownload.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.util.concurrent.*;
+import java.util.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroDownload extends AltosUIDialog implements Runnable, ActionListener {
+ MicroPeak owner;
+ Container pane;
+ AltosDevice device;
+ JButton cancel;
+ MicroData data;
+ MicroSerial serial;
+
+ private void done_internal() {
+ setVisible(false);
+ if (data != null) {
+ if (data.crc_valid) {
+ owner = owner.SetData(data);
+ MicroSave save = new MicroSave(owner, data);
+ if (save.runDialog())
+ owner.SetName(data.name);
+ } else {
+ JOptionPane.showMessageDialog(owner,
+ "Flight data corrupted",
+ "Download Failed",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ dispose();
+ }
+
+ public void done() {
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ done_internal();
+ } catch (Exception ex) {
+ }
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+
+ public void run() {
+ try {
+ data = new MicroData(serial, device.toShortString());
+ serial.close();
+ } catch (FileNotFoundException fe) {
+ } catch (IOException ioe) {
+ } catch (InterruptedException ie) {
+ }
+ done();
+ }
+
+ Thread serial_thread;
+
+ public void start() {
+ try {
+ serial = new MicroSerial(device);
+ } catch (FileNotFoundException fe) {
+ return;
+ }
+ serial_thread = new Thread(this);
+ serial_thread.start();
+ }
+
+ public void actionPerformed(ActionEvent ae) {
+ if (serial_thread != null) {
+ serial.close();
+ serial_thread.interrupt();
+ }
+ }
+
+ public MicroDownload(MicroPeak owner, AltosDevice device) {
+ super (owner, "Download MicroPeak Data", false);
+
+ GridBagConstraints c;
+ Insets il = new Insets(4,4,4,4);
+ Insets ir = new Insets(4,4,4,4);
+
+ this.owner = owner;
+ this.device = device;
+
+ pane = getContentPane();
+ pane.setLayout(new GridBagLayout());
+
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ JLabel device_label = new JLabel("Device:");
+ pane.add(device_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 1; c.gridy = 0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ JLabel device_value = new JLabel(device.toString());
+ pane.add(device_value, c);
+
+ cancel = new JButton("Cancel");
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridx = 0; c.gridy = 1;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ Insets ic = new Insets(4,4,4,4);
+ c.insets = ic;
+ pane.add(cancel, c);
+
+ cancel.addActionListener(this);
+
+ pack();
+ setLocationRelativeTo(owner);
+ setVisible(true);
+ this.start();
+ }
+}
diff --git a/micropeak/MicroExport.java b/micropeak/MicroExport.java
new file mode 100644
index 00000000..4b83bb4d
--- /dev/null
+++ b/micropeak/MicroExport.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.io.*;
+import java.util.ArrayList;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroExport extends JFileChooser {
+
+ JFrame frame;
+ MicroData data;
+
+ public static void export(File file, MicroData data) throws FileNotFoundException, IOException {
+ FileWriter fw = new FileWriter(file);
+ data.export(fw);
+ fw.close();
+ }
+
+ public boolean runDialog() {
+ int ret;
+
+ setSelectedFile(new File(AltosLib.replace_extension(data.name, ".csv")));
+ for (;;) {
+ ret = showSaveDialog(frame);
+ if (ret != APPROVE_OPTION)
+ return false;
+ File file;
+ String filename;
+ file = getSelectedFile();
+ if (file == null)
+ continue;
+ if (!file.getName().contains(".")) {
+ String fullname = file.getPath();
+ file = new File(fullname.concat(".csv"));
+ }
+ filename = file.getName();
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("\"%s\" is a directory",
+ filename),
+ "Directory",
+ JOptionPane.ERROR_MESSAGE);
+ continue;
+ }
+ int r = JOptionPane.showConfirmDialog(frame,
+ String.format("\"%s\" already exists. Overwrite?",
+ filename),
+ "Overwrite file?",
+ JOptionPane.YES_NO_OPTION);
+ if (r != JOptionPane.YES_OPTION)
+ continue;
+
+ if (!file.canWrite()) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("\"%s\" is not writable",
+ filename),
+ "File not writable",
+ JOptionPane.ERROR_MESSAGE);
+ continue;
+ }
+ }
+ try {
+ export(file, data);
+ return true;
+ } catch (FileNotFoundException fe) {
+ JOptionPane.showMessageDialog(frame,
+ fe.getMessage(),
+ "Cannot create file",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (IOException ioe) {
+ }
+ }
+ }
+
+ public MicroExport(JFrame frame, MicroData data) {
+ this.frame = frame;
+ this.data = data;
+ setDialogTitle("Export MicroPeak Data File");
+ setFileFilter(new FileNameExtensionFilter("MicroPeak CSV file",
+ "csv"));
+ setCurrentDirectory(AltosUIPreferences.logdir());
+ }
+}
diff --git a/micropeak/MicroFile.java b/micropeak/MicroFile.java
new file mode 100644
index 00000000..13d48380
--- /dev/null
+++ b/micropeak/MicroFile.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.io.*;
+import java.util.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroFile {
+
+ public static File make(File directory, int year, int month, int day) {
+ for (int sequence = 1;; sequence++) {
+ String s = String.format("%04d-%02d-%02d-flight-%03d.mpd",
+ year, month, day, sequence);
+ File file = new File(directory, s);
+ if (!file.exists())
+ return file;
+ }
+ }
+
+ public static File make(File directory) {
+ Calendar cal = Calendar.getInstance();
+ return make(directory, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH));
+ }
+
+ public static File make() {
+ return make(AltosUIPreferences.logdir());
+ }
+} \ No newline at end of file
diff --git a/micropeak/MicroFileChooser.java b/micropeak/MicroFileChooser.java
new file mode 100644
index 00000000..21ddb0f8
--- /dev/null
+++ b/micropeak/MicroFileChooser.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import java.io.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroFileChooser extends JFileChooser {
+ JFrame frame;
+ String filename;
+ File file;
+
+ public String filename() {
+ return filename;
+ }
+
+ public File file() {
+ return file;
+ }
+
+ public File runDialog() {
+ int ret;
+
+ ret = showOpenDialog(frame);
+ if (ret == APPROVE_OPTION)
+ return getSelectedFile();
+ return null;
+ }
+
+ public MicroFileChooser(JFrame in_frame) {
+ frame = in_frame;
+ setDialogTitle("Select MicroPeak Data File");
+ setFileFilter(new FileNameExtensionFilter("MicroPeak data file",
+ "mpd"));
+ setCurrentDirectory(AltosUIPreferences.logdir());
+ }
+}
diff --git a/micropeak/MicroFrame.java b/micropeak/MicroFrame.java
new file mode 100644
index 00000000..03e3af0c
--- /dev/null
+++ b/micropeak/MicroFrame.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.util.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroFrame extends AltosUIFrame {
+ static String[] micro_icon_names = {
+ "/micropeak-16.png",
+ "/micropeak-32.png",
+ "/micropeak-48.png",
+ "/micropeak-64.png",
+ "/micropeak-128.png",
+ "/micropeak-256.png"
+ };
+
+ static { set_icon_names(micro_icon_names); }
+}
diff --git a/micropeak/MicroGraph.java b/micropeak/MicroGraph.java
new file mode 100644
index 00000000..84320be3
--- /dev/null
+++ b/micropeak/MicroGraph.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.io.*;
+import java.util.ArrayList;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.AltosLib.*;
+
+import org.jfree.ui.*;
+import org.jfree.chart.*;
+import org.jfree.chart.plot.*;
+import org.jfree.chart.axis.*;
+import org.jfree.chart.renderer.*;
+import org.jfree.chart.renderer.xy.*;
+import org.jfree.chart.labels.*;
+import org.jfree.data.xy.*;
+import org.jfree.data.*;
+
+class MicroSeries extends XYSeries {
+ NumberAxis axis;
+ String label;
+ String units;
+ Color color;
+ XYItemRenderer renderer;
+
+ void set_units(String units) {
+ this.units = units;
+
+ axis.setLabel(String.format("%s (%s)", label, units));
+
+ StandardXYToolTipGenerator ttg;
+
+ ttg = new StandardXYToolTipGenerator(String.format("{1}s: {2}%s ({0})", units),
+ new java.text.DecimalFormat("0.00"),
+ new java.text.DecimalFormat("0.00"));
+ renderer.setBaseToolTipGenerator(ttg);
+ }
+
+ public MicroSeries (String label, String units, Color color) {
+ super(label);
+ this.label = label;
+ this.units = units;
+ this.color = color;
+
+ axis = new NumberAxis();
+ axis.setLabelPaint(color);
+ axis.setTickLabelPaint(color);
+
+ renderer = new XYLineAndShapeRenderer(true, false);
+ renderer.setSeriesPaint(0, color);
+ set_units(units);
+ }
+}
+
+public class MicroGraph implements AltosUnitsListener {
+
+ XYPlot plot;
+ JFreeChart chart;
+ ChartPanel panel;
+ NumberAxis xAxis;
+ MicroSeries heightSeries;
+ MicroSeries speedSeries;
+ MicroSeries accelSeries;
+
+ static final private Color height_color = new Color(194,31,31);
+ static final private Color speed_color = new Color(31,194,31);
+ static final private Color accel_color = new Color(31,31,194);
+ static final private Color gridline_color = new Color(0, 0, 0);
+ static final private Color border_color = new Color(255, 255, 255);
+ static final private Color background_color = new Color(255, 255, 255);
+
+ MicroData data;
+
+ public JPanel panel() {
+ return panel;
+ }
+
+ private MicroSeries addSeries(int index, String label, String units, Color color) {
+ MicroSeries series = new MicroSeries(label, units, color);
+ XYSeriesCollection dataset = new XYSeriesCollection(series);
+
+ series.renderer.setPlot(plot);
+ plot.setRangeAxis(index, series.axis);
+ plot.setDataset(index, dataset);
+ plot.setRenderer(index, series.renderer);
+ plot.mapDatasetToRangeAxis(index, index);
+ return series;
+ }
+
+ public void resetData() {
+ heightSeries.clear();
+ speedSeries.clear();
+ accelSeries.clear();
+ if (data != null) {
+ for (MicroDataPoint point : data.points()) {
+ heightSeries.add(point.time, AltosConvert.height.value(point.height));
+ speedSeries.add(point.time, AltosConvert.speed.value(point.speed));
+ accelSeries.add(point.time, AltosConvert.accel.value(point.accel));
+ }
+ }
+ }
+
+ public void setName (String name) {
+ chart.setTitle(name);
+ }
+
+ public void setData (MicroData data) {
+ this.data = data;
+ if (data != null)
+ setName(data.name);
+ resetData();
+ }
+
+ public void units_changed(boolean imperial_units) {
+ heightSeries.set_units(AltosConvert.height.show_units());
+ speedSeries.set_units(AltosConvert.speed.show_units());
+ accelSeries.set_units(AltosConvert.accel.show_units());
+ resetData();
+ }
+
+ public MicroGraph() {
+
+ xAxis = new NumberAxis("Time (s)");
+
+ xAxis.setAutoRangeIncludesZero(true);
+
+ plot = new XYPlot();
+ plot.setDomainAxis(xAxis);
+ plot.setOrientation(PlotOrientation.VERTICAL);
+ plot.setDomainPannable(true);
+ plot.setRangePannable(true);
+
+ chart = new JFreeChart("Flight", JFreeChart.DEFAULT_TITLE_FONT,
+ plot, true);
+
+ ChartUtilities.applyCurrentTheme(chart);
+
+ heightSeries = addSeries(0, "Height", AltosConvert.height.show_units(), height_color);
+ speedSeries = addSeries(1, "Speed", AltosConvert.speed.show_units(), speed_color);
+ accelSeries = addSeries(2, "Acceleration", AltosConvert.accel.show_units(), accel_color);
+
+ plot.setDomainGridlinePaint(gridline_color);
+ plot.setRangeGridlinePaint(gridline_color);
+ plot.setBackgroundPaint(background_color);
+ plot.setBackgroundAlpha((float) 1);
+
+ chart.setBackgroundPaint(background_color);
+ chart.setBorderPaint(border_color);
+ panel = new ChartPanel(chart);
+ panel.setMouseWheelEnabled(true);
+ panel.setPreferredSize(new java.awt.Dimension(800, 500));
+
+ AltosPreferences.register_units_listener(this);
+ }
+} \ No newline at end of file
diff --git a/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub b/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub
new file mode 100755
index 00000000..c661d3e1
--- /dev/null
+++ b/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub
Binary files differ
diff --git a/micropeak/MicroPeak.app/Contents/PkgInfo b/micropeak/MicroPeak.app/Contents/PkgInfo
new file mode 100644
index 00000000..8a43480f
--- /dev/null
+++ b/micropeak/MicroPeak.app/Contents/PkgInfo
@@ -0,0 +1 @@
+APPLAM.O
diff --git a/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns b/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns
new file mode 100644
index 00000000..9ba83bf5
--- /dev/null
+++ b/micropeak/MicroPeak.app/Contents/Resources/MicroPeak.icns
Binary files differ
diff --git a/micropeak/MicroPeak.java b/micropeak/MicroPeak.java
new file mode 100644
index 00000000..5d128dfd
--- /dev/null
+++ b/micropeak/MicroPeak.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.util.concurrent.*;
+import java.util.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroPeak extends MicroFrame implements ActionListener, ItemListener {
+
+ File filename;
+ MicroGraph graph;
+ MicroStatsTable stats;
+ MicroRaw raw;
+ MicroData data;
+ Container container;
+ JTabbedPane pane;
+ static int number_of_windows;
+
+ MicroPeak SetData(MicroData data) {
+ MicroPeak mp = this;
+ if (this.data != null) {
+ mp = new MicroPeak();
+ return mp.SetData(data);
+ }
+ this.data = data;
+ graph.setData(data);
+ stats.setData(data);
+ raw.setData(data);
+ setTitle(data.name);
+ return this;
+ }
+
+ void SetName(String name) {
+ graph.setName(name);
+ setTitle(name);
+ }
+
+ private static MicroData ReadFile(File filename) throws IOException, FileNotFoundException {
+ MicroData data = null;
+ FileInputStream fis = new FileInputStream(filename);
+ try {
+ data = new MicroData((InputStream) fis, filename.getName());
+ } catch (InterruptedException ie) {
+ data = null;
+ } finally {
+ fis.close();
+ }
+ return data;
+ }
+
+ private void OpenFile(File filename) {
+ try {
+ SetData(ReadFile(filename));
+ } catch (FileNotFoundException fne) {
+ JOptionPane.showMessageDialog(this,
+ fne.getMessage(),
+ "Cannot open file",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (IOException ioe) {
+ JOptionPane.showMessageDialog(this,
+ ioe.getMessage(),
+ "File Read Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ private void SelectFile() {
+ MicroFileChooser chooser = new MicroFileChooser(this);
+ File file = chooser.runDialog();
+
+ if (file != null)
+ OpenFile(file);
+ }
+
+ private void Preferences() {
+ new AltosUIConfigure(this);
+ }
+
+ private void DownloadData() {
+ AltosDevice device = MicroDeviceDialog.show(this);
+
+ if (device != null)
+ new MicroDownload(this, device);
+ }
+
+ private void no_data() {
+ JOptionPane.showMessageDialog(this,
+ "No data available",
+ "No data",
+ JOptionPane.INFORMATION_MESSAGE);
+ }
+
+ private void Save() {
+ if (data == null) {
+ no_data();
+ return;
+ }
+ MicroSave save = new MicroSave (this, data);
+ if (save.runDialog())
+ SetName(data.name);
+ }
+
+ private void Export() {
+ if (data == null) {
+ no_data();
+ return;
+ }
+ MicroExport export = new MicroExport (this, data);
+ export.runDialog();
+ }
+
+ private static void CommandGraph(File file) {
+ MicroPeak m = new MicroPeak();
+ m.OpenFile(file);
+ }
+
+ private static void CommandExport(File file) {
+ try {
+ MicroData d = ReadFile(file);
+ if (d != null) {
+ File csv = new File(AltosLib.replace_extension(file.getPath(), ".csv"));
+ try {
+ System.out.printf ("Export \"%s\" to \"%s\"\n", file.getPath(), csv.getPath());
+ MicroExport.export(csv, d);
+ } catch (FileNotFoundException fe) {
+ System.err.printf("Cannot create file \"%s\" (%s)\n", csv.getName(), fe.getMessage());
+ } catch (IOException ie) {
+ System.err.printf("Cannot write file \"%s\" (%s)\n", csv.getName(), ie.getMessage());
+ }
+ }
+ } catch (IOException ie) {
+ System.err.printf("Cannot read file \"%s\" (%s)\n", file.getName(), ie.getMessage());
+ }
+ }
+
+ private void Close() {
+ setVisible(false);
+ dispose();
+ --number_of_windows;
+ if (number_of_windows == 0)
+ System.exit(0);
+ }
+
+ public void actionPerformed(ActionEvent ev) {
+ if ("Exit".equals(ev.getActionCommand()))
+ System.exit(0);
+ else if ("Close".equals(ev.getActionCommand()))
+ Close();
+ else if ("Open".equals(ev.getActionCommand()))
+ SelectFile();
+ else if ("Download".equals(ev.getActionCommand()))
+ DownloadData();
+ else if ("Export".equals(ev.getActionCommand()))
+ Export();
+ else if ("Preferences".equals(ev.getActionCommand()))
+ Preferences();
+ else if ("Save a Copy".equals(ev.getActionCommand()))
+ Save();
+ }
+
+ public void itemStateChanged(ItemEvent e) {
+ }
+
+ public MicroPeak() {
+
+ ++number_of_windows;
+
+ AltosUIPreferences.set_component(this);
+
+ container = getContentPane();
+ pane = new JTabbedPane();
+
+ setTitle("MicroPeak");
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ JMenu fileMenu = new JMenu("File");
+ menuBar.add(fileMenu);
+
+ JMenuItem openAction = new JMenuItem("Open");
+ fileMenu.add(openAction);
+ openAction.addActionListener(this);
+
+ JMenuItem downloadAction = new JMenuItem("Download");
+ fileMenu.add(downloadAction);
+ downloadAction.addActionListener(this);
+
+ JMenuItem saveAction = new JMenuItem("Save a Copy");
+ fileMenu.add(saveAction);
+ saveAction.addActionListener(this);
+
+ JMenuItem exportAction = new JMenuItem("Export");
+ fileMenu.add(exportAction);
+ exportAction.addActionListener(this);
+
+ JMenuItem preferencesAction = new JMenuItem("Preferences");
+ fileMenu.add(preferencesAction);
+ preferencesAction.addActionListener(this);
+
+ JMenuItem closeAction = new JMenuItem("Close");
+ fileMenu.add(closeAction);
+ closeAction.addActionListener(this);
+
+ JMenuItem exitAction = new JMenuItem("Exit");
+ fileMenu.add(exitAction);
+ exitAction.addActionListener(this);
+
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ Close();
+ }
+ });
+
+ graph = new MicroGraph();
+ stats = new MicroStatsTable();
+ raw = new MicroRaw();
+ pane.add(graph.panel, "Graph");
+ pane.add(stats, "Statistics");
+ JScrollPane scroll = new JScrollPane(raw);
+ pane.add(scroll, "Raw Data");
+ pane.doLayout();
+ pane.validate();
+ container.add(pane);
+ container.doLayout();
+ container.validate();
+ doLayout();
+ validate();
+ Insets i = getInsets();
+ Dimension ps = pane.getPreferredSize();
+ ps.width += i.left + i.right;
+ ps.height += i.top + i.bottom;
+// setPreferredSize(ps);
+ setSize(ps);
+ setLocationByPlatform(true);
+ setVisible(true);
+ }
+
+ public static void help(int code) {
+ System.out.printf("Usage: micropeak [OPTION] ... [FILE]...\n");
+ System.out.printf(" Options:\n");
+ System.out.printf(" --csv\tgenerate comma separated output for spreadsheets, etc\n");
+ System.out.printf(" --graph\tgraph a flight\n");
+ System.exit(code);
+ }
+
+ public static void main(final String[] args) {
+ boolean opened = false;
+ boolean graphing = true;
+
+ try {
+ UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel());
+ } catch (Exception e) {
+ }
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("--help"))
+ help(0);
+ else if (args[i].equals("--export"))
+ graphing = false;
+ else if (args[i].equals("--graph"))
+ graphing = true;
+ else if (args[i].startsWith("--"))
+ help(1);
+ else {
+ File file = new File(args[i]);
+ try {
+ if (graphing)
+ CommandGraph(file);
+ else
+ CommandExport(file);
+ opened = true;
+ } catch (Exception e) {
+ System.err.printf("Error processing \"%s\": %s\n",
+ file.getName(), e.getMessage());
+ }
+ }
+ }
+ if (!opened)
+ new MicroPeak();
+ }
+}
diff --git a/micropeak/MicroRaw.java b/micropeak/MicroRaw.java
new file mode 100644
index 00000000..8546cffb
--- /dev/null
+++ b/micropeak/MicroRaw.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.awt.*;
+import java.io.*;
+import javax.swing.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroRaw extends JTextArea {
+
+ public void setData(MicroData data) {
+ StringWriter sw = new StringWriter();
+ try {
+ data.export(sw);
+ setRows(data.pressures.length + 1);
+ setText(sw.toString());
+ } catch (IOException ie) {
+ setText(String.format("Error writing data: %s", ie.getMessage()));
+ }
+ setCaretPosition(0);
+ }
+
+ public MicroRaw() {
+ super(1, 30);
+ setFont(AltosUILib.table_value_font);
+ setEditable(false);
+ }
+}
diff --git a/micropeak/MicroSave.java b/micropeak/MicroSave.java
new file mode 100644
index 00000000..7879ff90
--- /dev/null
+++ b/micropeak/MicroSave.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import java.io.*;
+import java.util.concurrent.*;
+import java.util.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroSave extends JFileChooser {
+
+ JFrame frame;
+ MicroData data;
+
+ public static void save(File file, MicroData data) throws FileNotFoundException, IOException {
+ FileOutputStream fos = new FileOutputStream(file);
+ data.save(fos);
+ fos.close();
+ }
+
+ public boolean runDialog() {
+ int ret;
+
+ for (;;) {
+ ret = showSaveDialog(frame);
+ if (ret != APPROVE_OPTION)
+ return false;
+ File file;
+ String filename;
+ file = getSelectedFile();
+ if (file == null)
+ continue;
+ if (!file.getName().contains(".")) {
+ String fullname = file.getPath();
+ file = new File(fullname.concat(".mpd"));
+ }
+ filename = file.getName();
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("\"%s\" is a directory",
+ filename),
+ "Directory",
+ JOptionPane.ERROR_MESSAGE);
+ continue;
+ }
+ int r = JOptionPane.showConfirmDialog(frame,
+ String.format("\"%s\" already exists. Overwrite?",
+ filename),
+ "Overwrite file?",
+ JOptionPane.YES_NO_OPTION);
+ if (r != JOptionPane.YES_OPTION)
+ continue;
+
+ if (!file.canWrite()) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("\"%s\" is not writable",
+ filename),
+ "File not writable",
+ JOptionPane.ERROR_MESSAGE);
+ continue;
+ }
+ }
+ try {
+ save(file, data);
+ data.set_name(filename);
+ return true;
+ } catch (FileNotFoundException fe) {
+ JOptionPane.showMessageDialog(frame,
+ fe.getMessage(),
+ "Cannot create file",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (IOException ioe) {
+ }
+ }
+ }
+
+ public MicroSave(JFrame frame, MicroData data) {
+ this.frame = frame;
+ this.data = data;
+ setDialogTitle("Save MicroPeak Data File");
+ setFileFilter(new FileNameExtensionFilter("MicroPeak data file",
+ "mpd"));
+ setCurrentDirectory(AltosUIPreferences.logdir());
+ setSelectedFile(MicroFile.make());
+ }
+}
diff --git a/micropeak/MicroSerial.java b/micropeak/MicroSerial.java
new file mode 100644
index 00000000..15ef8582
--- /dev/null
+++ b/micropeak/MicroSerial.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.util.*;
+import java.io.*;
+import libaltosJNI.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroSerial extends InputStream {
+ SWIGTYPE_p_altos_file file;
+
+ public int read() {
+ int c = libaltos.altos_getchar(file, 0);
+ if (Thread.interrupted())
+ return -1;
+ if (c == -1)
+ return -1;
+ if (AltosUIPreferences.serial_debug)
+ System.out.printf("%c", c);
+ return c;
+ }
+
+ public void close() {
+ if (file != null) {
+ libaltos.altos_close(file);
+ file = null;
+ }
+ }
+
+ public MicroSerial(AltosDevice device) throws FileNotFoundException {
+ file = device.open();
+ if (file == null) {
+ final String message = device.getErrorString();
+ throw new FileNotFoundException(String.format("%s (%s)",
+ device.toShortString(),
+ message));
+ }
+ }
+}
diff --git a/micropeak/MicroStats.java b/micropeak/MicroStats.java
new file mode 100644
index 00000000..056fac7d
--- /dev/null
+++ b/micropeak/MicroStats.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.io.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroStats {
+ double coast_height;
+ double coast_time;
+
+ double apogee_height;
+ double apogee_time;
+
+ double landed_height;
+ double landed_time;
+
+ double max_speed;
+ double max_accel;
+
+ MicroData data;
+
+ void find_landing() {
+ landed_height = 0;
+
+ for (MicroDataPoint point : data.points()) {
+ landed_height = point.height;
+ landed_time = point.time;
+ }
+
+ boolean above = false;
+ for (MicroDataPoint point : data.points()) {
+ if (point.height > landed_height + 10) {
+ above = true;
+ } else {
+ if (above && point.height < landed_height + 2) {
+ above = false;
+ landed_time = point.time;
+ }
+ }
+ }
+ }
+
+ void find_apogee() {
+ apogee_height = 0;
+ apogee_time = 0;
+
+ for (MicroDataPoint point : data.points()) {
+ if (point.height > apogee_height) {
+ apogee_height = point.height;
+ apogee_time = point.time;
+ }
+ }
+ }
+
+ void find_coast() {
+ coast_height = 0;
+ coast_time = 0;
+
+ for (MicroDataPoint point : data.points()) {
+ if (point.accel < -9.8)
+ break;
+ coast_time = point.time;
+ coast_height = point.height;
+ }
+ }
+
+ void find_max_speed() {
+ max_speed = 0;
+ for (MicroDataPoint point : data.points()) {
+ if (point.time > apogee_time)
+ break;
+ if (point.speed > max_speed)
+ max_speed = point.speed;
+ }
+ }
+
+ void find_max_accel() {
+ max_accel = 0;
+ for (MicroDataPoint point : data.points()) {
+ if (point.time > apogee_time)
+ break;
+ if (point.accel > max_accel)
+ max_accel = point.accel;
+ }
+ }
+
+ double boost_duration() {
+ return coast_time;
+ }
+
+ double boost_height() {
+ return coast_height;
+ }
+
+ double boost_speed() {
+ return coast_height / coast_time;
+ }
+
+ double boost_accel() {
+ return boost_speed() / boost_duration();
+ }
+
+ double coast_duration() {
+ return apogee_time - coast_time;
+ }
+
+ double coast_height() {
+ return apogee_height - coast_height;
+ }
+
+ double coast_speed() {
+ return coast_height() / coast_duration();
+ }
+
+ double coast_accel() {
+ return coast_speed() / coast_duration();
+ }
+
+ double descent_duration() {
+ return landed_time - apogee_time;
+ }
+
+ double descent_height() {
+ return apogee_height - landed_height;
+ }
+
+ double descent_speed() {
+ return descent_height() / descent_duration();
+ }
+
+ public MicroStats(MicroData data) {
+
+ this.data = data;
+
+ find_coast();
+ find_apogee();
+ find_landing();
+ find_max_speed();
+ find_max_accel();
+ }
+
+ public MicroStats() {
+ this(new MicroData());
+ }
+}
diff --git a/micropeak/MicroStatsTable.java b/micropeak/MicroStatsTable.java
new file mode 100644
index 00000000..f373e25d
--- /dev/null
+++ b/micropeak/MicroStatsTable.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroStatsTable extends JComponent {
+ GridBagLayout layout;
+
+ class MicroStat {
+ JLabel label;
+ JTextField[] texts;
+
+ public void set_values(String ... values) {
+ for (int j = 0; j < values.length; j++) {
+ texts[j].setText(values[j]);
+ }
+ }
+
+ public MicroStat(GridBagLayout layout, int y, String label_text, String ... values) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad);
+ c.weighty = 1;
+
+ label = new JLabel(label_text);
+ label.setFont(AltosUILib.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = 0; c.gridy = y;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ texts = new JTextField[values.length];
+ for (int j = 0; j < values.length; j++) {
+ JTextField value = new JTextField(values[j]);
+ value.setFont(AltosUILib.value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ texts[j] = value;
+ c.gridx = j+1; c.gridy = y;
+ c.anchor = GridBagConstraints.EAST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ layout.setConstraints(value, c);
+ add(value);
+ }
+ }
+ }
+
+ MicroStat max_height, max_speed;
+ MicroStat max_accel, avg_accel;
+ MicroStat boost_duration;
+ MicroStat coast_duration;
+ MicroStat descent_speed;
+ MicroStat descent_duration;
+ MicroStat flight_time;
+
+ public void setStats(MicroStats stats) {
+ max_height.set_values(String.format("%5.0f m", stats.apogee_height),
+ String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.apogee_height)));
+ max_speed.set_values(String.format("%5.0f m/s", stats.max_speed),
+ String.format("%5.0f mph", AltosConvert.meters_to_mph(stats.max_speed)),
+ String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
+ max_accel.set_values(String.format("%5.0f m/s²", stats.max_accel),
+ String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_accel)),
+ String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_accel)));
+ avg_accel.set_values(String.format("%5.0f m/s²", stats.boost_accel(),
+ String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.boost_accel())),
+ String.format("%5.0f G", AltosConvert.meters_to_g(stats.boost_accel()))));
+ boost_duration.set_values(String.format("%6.1f s", stats.boost_duration()));
+ coast_duration.set_values(String.format("%6.1f s", stats.coast_duration()));
+ descent_speed.set_values(String.format("%5.0f m/s", stats.descent_speed()),
+ String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.descent_speed())));
+ descent_duration.set_values(String.format("%6.1f s", stats.descent_duration()));
+ flight_time.set_values(String.format("%6.1f s", stats.landed_time));
+ }
+
+ public void setData(MicroData data) {
+ setStats(new MicroStats(data));
+ }
+
+ public MicroStatsTable(MicroStats stats) {
+ layout = new GridBagLayout();
+
+ setLayout(layout);
+ int y = 0;
+ max_height = new MicroStat(layout, y++, "Maximum height",
+ String.format("%5.0f m", stats.apogee_height),
+ String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.apogee_height)));
+ max_speed = new MicroStat(layout, y++, "Maximum speed",
+ String.format("%5.0f m/s", stats.max_speed),
+ String.format("%5.0f mph", AltosConvert.meters_to_mph(stats.max_speed)),
+ String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
+ max_accel = new MicroStat(layout, y++, "Maximum boost acceleration",
+ String.format("%5.0f m/s²", stats.max_accel),
+ String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_accel)),
+ String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_accel)));
+ avg_accel = new MicroStat(layout, y++, "Average boost acceleration",
+ String.format("%5.0f m/s²", stats.boost_accel(),
+ String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.boost_accel())),
+ String.format("%5.0f G", AltosConvert.meters_to_g(stats.boost_accel()))));
+ boost_duration = new MicroStat(layout, y++, "Boost duration",
+ String.format("%6.0f s", stats.boost_duration()));
+ coast_duration = new MicroStat(layout, y++, "Coast duration",
+ String.format("%6.1f s", stats.coast_duration()));
+ descent_speed = new MicroStat(layout, y++, "Descent rate",
+ String.format("%5.0f m/s", stats.descent_speed()),
+ String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.descent_speed())));
+ descent_duration = new MicroStat(layout, y++, "Descent duration",
+ String.format("%6.1f s", stats.descent_duration()));
+ flight_time = new MicroStat(layout, y++, "Flight Time",
+ String.format("%6.0f s", stats.landed_time));
+ }
+
+ public MicroStatsTable() {
+ this(new MicroStats());
+ }
+
+} \ No newline at end of file
diff --git a/micropeak/MicroUSB.java b/micropeak/MicroUSB.java
new file mode 100644
index 00000000..f56d81d4
--- /dev/null
+++ b/micropeak/MicroUSB.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.util.*;
+import libaltosJNI.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroUSB extends altos_device implements AltosDevice {
+
+ static boolean initialized = false;
+ static boolean loaded_library = false;
+
+ public static boolean load_library() {
+ if (!initialized) {
+ try {
+ System.loadLibrary("altos");
+ libaltos.altos_init();
+ loaded_library = true;
+ } catch (UnsatisfiedLinkError e) {
+ try {
+ System.loadLibrary("altos64");
+ libaltos.altos_init();
+ loaded_library = true;
+ } catch (UnsatisfiedLinkError e2) {
+ loaded_library = false;
+ }
+ }
+ initialized = true;
+ }
+ return loaded_library;
+ }
+
+ public String toString() {
+ String name = getName();
+ if (name == null)
+ name = "Altus Metrum";
+ return String.format("%-24.24s %s",
+ name, getPath());
+ }
+
+ public String toShortString() {
+ String name = getName();
+ if (name == null)
+ name = "Altus Metrum";
+ return String.format("%s %s",
+ name, getPath());
+
+ }
+
+ public String getErrorString() {
+ altos_error error = new altos_error();
+
+ libaltos.altos_get_last_error(error);
+ return String.format("%s (%d)", error.getString(), error.getCode());
+ }
+
+ public SWIGTYPE_p_altos_file open() {
+ return libaltos.altos_open(this);
+ }
+
+ private boolean isMicro() {
+ if (getVendor() != 0x0403)
+ return false;
+ if (getProduct() != 0x6015)
+ return false;
+ return true;
+ }
+
+ public boolean matchProduct(int product) {
+ return isMicro();
+ }
+
+ static java.util.List<MicroUSB> list() {
+ if (!load_library())
+ return null;
+
+ SWIGTYPE_p_altos_list list = libaltos.altos_ftdi_list_start();
+
+ ArrayList<MicroUSB> device_list = new ArrayList<MicroUSB>();
+ if (list != null) {
+ for (;;) {
+ MicroUSB device = new MicroUSB();
+ if (libaltos.altos_list_next(list, device) == 0)
+ break;
+ if (device.isMicro())
+ device_list.add(device);
+ }
+ libaltos.altos_list_finish(list);
+ }
+
+ return device_list;
+ }
+} \ No newline at end of file
diff --git a/micropeak/ReadMe-Mac.rtf b/micropeak/ReadMe-Mac.rtf
new file mode 100644
index 00000000..64bbdeb6
--- /dev/null
+++ b/micropeak/ReadMe-Mac.rtf
@@ -0,0 +1,19 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\vieww10800\viewh8400\viewkind0
+\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural
+
+\f0\fs24 \cf0 Installing MicroPeak software for Mac OS X computers\
+\
+There are two files included in the Mac OS X distribution:\
+\
+ 1) The MicroPeak application\
+\
+ 2) The FTDI device drivers\
+\
+As with most Mac OS X applications, install MicroPeak by dragging it from the distribution disk image to a suitable place on your computer.\
+\
+To communicate with the MicroPeak serial adapter, you need to installed the FTDI device drivers, which is done by double-clicking on the FTDIUSBSerialDriver package file. That will guide you through the installation process.\
+\
+Thanks for choosing AltusMetrum products!} \ No newline at end of file
diff --git a/micropeak/micropeak-fat b/micropeak/micropeak-fat
new file mode 100755
index 00000000..ace7548d
--- /dev/null
+++ b/micropeak/micropeak-fat
@@ -0,0 +1,4 @@
+#!/bin/sh
+me=`which "$0"`
+dir=`dirname "$me"`
+exec java -cp "$dir/*" -Djava.library.path="$dir" -jar "$dir"/micropeak-fat.jar "$@"
diff --git a/micropeak/micropeak-windows.nsi b/micropeak/micropeak-windows.nsi
new file mode 100644
index 00000000..425048bd
--- /dev/null
+++ b/micropeak/micropeak-windows.nsi
@@ -0,0 +1,123 @@
+!addplugindir Instdrv/NSIS/Plugins
+; Definitions for Java 1.6 Detection
+!define JRE_VERSION "1.6"
+!define JRE_ALTERNATE "1.7"
+!define JRE_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=52247&/jre-6u27-windows-i586-p.exe"
+!define PRODUCT_NAME "Altus Metrum Windows Software"
+
+Name "Altus Metrum MicroPeak Installer"
+
+; Default install directory
+InstallDir "$PROGRAMFILES\AltusMetrum"
+
+; Tell the installer where to re-install a new version
+InstallDirRegKey HKLM "Software\AltusMetrum" "Install_Dir"
+
+LicenseText "GNU General Public License Version 2"
+LicenseData "../COPYING"
+
+; Need admin privs for Vista or Win7
+RequestExecutionLevel admin
+
+ShowInstDetails Show
+
+ComponentText "Altus Metrum MicroPeak Software Installer"
+
+Function GetJRE
+ MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION} 32-bit, it will now \
+ be downloaded and installed"
+
+ StrCpy $2 "$TEMP\Java Runtime Environment.exe"
+ nsisdl::download /TIMEOUT=30000 ${JRE_URL} $2
+ Pop $R0 ;Get the return value
+ StrCmp $R0 "success" +3
+ MessageBox MB_OK "Download failed: $R0"
+ Quit
+ ExecWait $2
+ Delete $2
+FunctionEnd
+
+
+Function DetectJRE
+ ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" \
+ "CurrentVersion"
+ StrCmp $2 ${JRE_VERSION} done
+
+ StrCmp $2 ${JRE_ALTERNATE} done
+
+ Call GetJRE
+
+ done:
+FunctionEnd
+
+; Pages to present
+
+Page license
+Page components
+Page directory
+Page instfiles
+
+UninstPage uninstConfirm
+UninstPage instfiles
+
+; And the stuff to install
+
+Section "MicroPeak Application"
+ Call DetectJRE
+
+ SetOutPath $INSTDIR
+
+ File "micropeak-fat.jar"
+ File "AltosLib.jar"
+ File "AltosUILib.jar"
+ File "jfreechart.jar"
+ File "jcommon.jar"
+
+ File "*.dll"
+
+ File "../icon/*.ico"
+
+ CreateShortCut "$SMPROGRAMS\MicroPeak.lnk" "$SYSDIR\javaw.exe" "-jar micropeak-fat.jar" "$INSTDIR\micro-peak.ico"
+SectionEnd
+
+Section "MicroPeak Desktop Shortcut"
+ CreateShortCut "$DESKTOP\MicroPeak.lnk" "$INSTDIR\micropeak-fat.jar" "" "$INSTDIR\micro-peak.ico"
+SectionEnd
+
+Section "Documentation"
+
+ SetOutPath $INSTDIR
+
+ File "../doc/micropeak.pdf"
+SectionEnd
+
+Section "Uninstaller"
+
+ ; Deal with the uninstaller
+
+ SetOutPath $INSTDIR
+
+ ; Write the install path to the registry
+ WriteRegStr HKLM SOFTWARE\AltusMetrum "Install_Dir" "$INSTDIR"
+
+ ; Write the uninstall keys for windows
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "DisplayName" "Altus Metrum"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "UninstallString" '"$INSTDIR\uninstall.exe"'
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoModify" "1"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoRepair" "1"
+
+ WriteUninstaller "uninstall.exe"
+SectionEnd
+
+Section "Uninstall"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum"
+ DeleteRegKey HKLM "Software\AltusMetrum"
+
+ Delete "$INSTDIR\*.*"
+ RMDir "$INSTDIR"
+
+ ; Remove shortcuts, if any
+ Delete "$SMPROGRAMS\MicroPeak.lnk"
+ Delete "$DESKTOP\MicroPeak.lnk"
+
+SectionEnd