+commit b68c0482d4fae8eb54cde1df0e4bcf4c5d272bad
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 22:49:09 2017 -0700
+
+ Version 1.8.1
+
+ Android version 15
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit abe100385cedf2b0734191611d97e794805d0ef4
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 22:48:46 2017 -0700
+
+ doc: Update for 1.8.1
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4775b1d9b50a8732d66a0ad3b73ff74901a8cb7f
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 28 00:15:43 2017 -0700
+
+ altos: Don't compute filtered average of height error when HAS_ACCEL
+
+ We only use this for baro-only devices to avoid firing drogue charges
+ at mach transitions; we trust the combination of accel+baro to do the
+ right thing when available.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dacd4c70700041a018b1f8ba47f22071b9600eaf
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 28 00:10:04 2017 -0700
+
+ altoslib: Fix freq preference loading
+
+ Allocate throw-away freq array to get the class pointer.
+ Add null-ary AltosFrequency constructor for JSON code.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7f5f37ac7fb71d3059f639b39315712f90e9bfd6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 17:37:10 2017 -0700
+
+ altosui: Make --oneline show drogue deploy speed
+
+ Also remove some commented out values.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dd72c9144b207b12150eb6a7ffb012f217f37374
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 17:35:49 2017 -0700
+
+ altoslib: Compute speed at entry to each state
+
+ Useful to have drogue/main deployment speeds
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9537a21b6ddb73b9f086858dad9a7b9d05279741
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 17:34:49 2017 -0700
+
+ altoslib: Fix parsing of old TM log GPS sat data
+
+ Attempting to fetch sat data from wrong byte led to array bounds
+ exception.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 92b689bfd78a96ba56f0e1022ba68b7384a9b9b6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 17:34:07 2017 -0700
+
+ altoslib: Allow for missing product when checking for mma655x inverted
+
+ If there's no product, assume we've got some ancient log file.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6e244a73d8c2a475416480f83328b7d363693402
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 17:33:38 2017 -0700
+
+ altoslib: Remove debug printf for gyro adjust
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f5642db4e03856b1f2ffeae6570fcf35fb7d93fb
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 17:32:27 2017 -0700
+
+ altos/test: Fake baro data for flight 12 serial 2093
+
+ This flight had a baro spike due to an accidental drogue charge firing
+ but is otherwise quite useful when testing for various mach delay
+ effects, so fake out the data during that spike.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bef7c37d1c986cd477367c0c015be61368a788d2
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 17:30:15 2017 -0700
+
+ altos/test: Integrate raw accel to provide speed for comparison
+
+ This can provide a useful visualization of the 'true' vs 'kalman'
+ speed value, as the kalman is necessarily delayed due to the model
+ assuming constant acceleration.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2dce02efd54ad4051f1ddb94048696e8677dd225
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 17:04:27 2017 -0700
+
+ altos/test: telemetrum baro data is inverted before being written to eeprom
+
+ No need for the test code to invert it during replay
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ea6fe21d78744d7e6225a56c369d54f7cd956767
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 26 19:16:47 2017 -0700
+
+ altos: Don't eliminate baro above mach speed, just trust it less
+
+ Instead of completely eliminating the baro sensor above mach speed,
+ just derate it a bit so that the accel will dominate for speed
+ computation and keep the device from false-triggering across mach
+ transitions.
+
+ When we completely ignored the baro sensor above mach, and the flight
+ spent considerable time in that speed range, then the estimated height
+ could be far from the real value. When the estimated speed dropped
+ back down and the baro values were brought back into the computation,
+ then the resulting rapid shift in estimated speed could trigger
+ accidental apogee detection.
+
+ By mixing in a bit of baro data even above mach, we keep the estimated
+ height closer to the baro value and prevent this error, at least in
+ flights measured so far.
+
+ The flight known to have this problem is:
+
+ 2015-09-26-serial-2093-flight-0012.eeprom
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 12ef994a24eb996458092dc35c671d6b824b1576
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 27 16:57:13 2017 -0700
+
+ altos: Eliminate separate height error filter for accelerometer devices
+
+ We don't use the error value in flight for those models anyways; it's
+ only useful on baro-only hardware.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f972000642f9c9835a0b7d14155d4c5695455d94
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 26 19:15:59 2017 -0700
+
+ altosui: Add --oneline mode to briefly summarize flights
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 465bb7242f39f6f8489e5fd52ce88031106c1c76
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 26 19:15:07 2017 -0700
+
+ altosuilib: Add "Huge" font size
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3dde7f4d05414ac4907c91c68c88cc1d06233605
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 26 19:14:10 2017 -0700
+
+ micropeak: Track font changes in raw data display
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cf20e213f39fb24f15e0ac94307c2d138fcadecb
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Aug 24 16:45:54 2017 -0700
+
+ altos: Perform time comparisons using 16-bit arithmetic to handle wrap
+
+ Subtracting two 16-bit unsigned values to perform time comparisons
+ yields mystic results unless we carefully cast that to int16_t.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 43e2275250d9c91560a770942f3c06a8f74ed501
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 12 01:37:07 2017 -0400
+
+ install: Add 'fat-install' target
+
+ This uses the existing --with-fat-dir option and instead of installing
+ everything to that directory, creates a normal ikiwiki hierarchy of
+ files including .mdwn files, whacked release notes html files and all
+ of the appropriate packages.
+
+ One stop shopping for adding the release to the web site.
+
+ Attempted to update Releasing file to match.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fccfa54bb3b746cecfcdc1fd497cf736bbfe3ef3
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sat Aug 12 00:23:27 2017 -0400
+
+ releasing 1.8
+
commit dbcb68f684a96d13efeb9993685f61b27b45e7dc
Author: Bdale Garbee <bdale@gag.com>
Date: Sat Aug 12 00:21:43 2017 -0400
dist-hook: ChangeLog
+if FATINSTALL
+fat-install: fat
+ cd altosui && $(MAKE) fat-install
+ cd telegps && $(MAKE) fat-install
+ cd micropeak && $(MAKE) fat-install
+endif
+
fat:
cd src && $(MAKE) all
cd doc && $(MAKE) all
Add the firmware to altosui/altos-windows.nsi.in
+ Add the firmware to telegps/Makefile.am
+
+ Add the firmware to telegps/telegps-windows.nsi.in
+
+ Add the firmware to Releasing
+
+These are Keith's notes on how to do a release
+
+ - update the version and date in configure.ac if Bdale hasn't already
+
+ - make sure there is a doc/release-notes-<version>.inc
+
+ - make sure doc/release-notes.inc points at that
+
+ - make sure doc/Makefile points at that too
+
+ - make sure that doc/altusmetrum-docinfo.xml has the right copyright
+ year, and add release to the revision history at the front (release
+ notes will be pulled in by release-notes.inc)
+
These are Bdale's notes on how to do a release.
- make sure build environment is up to date
make distclean
./autogen.sh --enable-multi-arch \
- --with-fat-dir=/home/bdale/web/altusmetrum/AltOS/releases
+ --with-fat-dir=/home/bdale/web/altusmetrum/
make && make fat
- this pushes packages for each platform to web site
+ this pushes packages for each platform and application
+ to web site, including auto-generated mdwn files and
+ release notes in html format.
# store a stable copy of ARM binaries for production use
cp src/chaoskey-v1.0/{*.elf,*.ihx} \
- copy the relevant release notes .html file from doc/ to
/home/bdale/web/altusmetrum/AltOS/releases/<rev>
- (cd ~/web/altusmetrum/AltOS/releases/<rev> ; rm *.tar.bz2)
-
- - create /home/bdale/web/altusmetrum/MicroPeak/releases/<rev>,
- and move the MicroPeak installers from AltOS/releases to there
-
- - create /home/bdale/web/altusmetrum/TeleGPS/releases/<rev>,
- and move the TeleGPS installers from AltOS/releases to there
-
- - go edit ~/web/altusmetrum/AltOS/releases/<rev>.mdwn,
- /home/bdale/web/altusmetrum/MicroPeak/releases/<rev>.mdwn, and
- /home/bdale/web/altusmetrum/TeleGPS/releases/<rev>.mdwn
-
- - make sure the Windows stuff is like 1-4-1, not 1.4.1!
+ - Push new release to web site
+ make fat-install
(cd doc ; make publish)
+ (cd ~/web/altusmetrum/ && git add AltOS/releases
+ TeleGPS/releases MicroPeak/releases && git commit -m'Release
+ <rev>' && git push origin master)
+
this pushes fresh documents to the web site
sudo debian/rules clean
v = Math.ceil(v);
else
v = Math.floor(v);
- if (v != 0)
- System.out.printf("Adjusting gyro axis by %g steps\n", v);
+// if (v != 0)
+// System.out.printf("Adjusting gyro axis by %g steps\n", v);
return v * 128.0;
}
public boolean mma655x_inverted() throws AltosUnknownProduct {
- if (product.startsWith("EasyMega-v1"))
- return false;
- if (product.startsWith("TeleMetrum-v2"))
- return true;
- if (product.startsWith("TeleMega-v2"))
- return false;
- if (product.startsWith("TeleMega-v1"))
- return false;
+ if (product != null) {
+ if (product.startsWith("EasyMega-v1"))
+ return false;
+ if (product.startsWith("TeleMetrum-v2"))
+ return true;
+ if (product.startsWith("TeleMega-v2"))
+ return false;
+ if (product.startsWith("TeleMega-v1"))
+ return false;
+ }
throw new AltosUnknownProduct(product);
}
case AltosLib.AO_LOG_GPS_SAT:
gps = cal_data.make_temp_gps(tick(),true);
int svid = data16(0);
- int c_n0 = data16(3);
+ int c_n0 = data16(2);
gps.add_sat(svid, c_n0);
break;
case AltosLib.AO_LOG_GPS_DATE:
public double max_speed;
public double max_acceleration;
public double[] state_speed = new double[AltosLib.ao_flight_invalid + 1];
+ public double[] state_enter_speed = new double[AltosLib.ao_flight_invalid + 1];
public double[] state_accel = new double[AltosLib.ao_flight_invalid + 1];
public double[] state_time = new double[AltosLib.ao_flight_invalid + 1];
public String product;
private void add_times(AltosFlightSeries series, int state, double start_time, double end_time) {
double delta_time = end_time - start_time;
if (0 <= state && state <= AltosLib.ao_flight_invalid && delta_time > 0) {
+ if (state_enter_speed[state] == AltosLib.MISSING)
+ state_enter_speed[state] = series.speed_series.value(start_time);
speeds[state].value += series.speed_series.average(start_time, end_time) * delta_time;
speeds[state].time += delta_time;
accels[state].value += series.accel_series.average(start_time, end_time) * delta_time;
for (int s = 0; s < AltosLib.ao_flight_invalid + 1; s++) {
state_speed[s] = AltosLib.MISSING;
+ state_enter_speed[s] = AltosLib.MISSING;
state_accel[s] = AltosLib.MISSING;
state_time[s] = 0;
speeds[s] = new AltosTimeValue(0, 0);
frequency = f;
description = d;
}
+ public AltosFrequency() {
+ this(0, null);
+ }
}
try {
AltosJson json = AltosJson.fromString(backend.getString(frequenciesPreference,
null));
- frequencies = (AltosFrequency[]) json.make(frequencies.getClass());
+ frequencies = (AltosFrequency[]) json.make((new AltosFrequency[1]).getClass());
} catch (Exception e) {
}
String message = ie.getMessage();
if (message == null)
message = String.format("%s (I/O error)", input.toString());
- System.err.printf("%s\n", message);
+ System.err.printf("%s: %s\n", input.toString(), message);
}
return null;
}
static final int process_graph = 3;
static final int process_replay = 4;
static final int process_summary = 5;
+ static final int process_oneline = 6;
static boolean process_csv(File input) {
AltosRecordSet set = record_set(input);
return true;
}
+ static boolean process_oneline(File file) {
+ AltosRecordSet set = record_set(file);
+ if (set == null)
+ return false;
+ System.out.printf("%s", file.toString());
+ AltosFlightSeries series = make_series(set);
+ AltosFlightStats stats = new AltosFlightStats(series);
+ if (stats.max_height != AltosLib.MISSING)
+ System.out.printf(" height %6.0f m", stats.max_height);
+ if (stats.max_speed != AltosLib.MISSING)
+ System.out.printf(" speed %6.0f m/s", stats.max_speed);
+ if (stats.state_enter_speed[AltosLib.ao_flight_drogue] != AltosLib.MISSING)
+ System.out.printf(" drogue-deploy %6.0f m/s", stats.state_enter_speed[AltosLib.ao_flight_drogue]);
+ if (stats.max_acceleration != AltosLib.MISSING)
+ System.out.printf(" accel %6.0f m/s²", stats.max_acceleration);
+ System.out.printf("\n");
+ return true;
+ }
+
public static void help(int code) {
System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
System.out.printf(" Options:\n");
System.out.printf(" --replay <filename>\t\trelive the glory of past flights \n");
System.out.printf(" --graph <filename>\t\tgraph a flight\n");
System.out.printf(" --summary <filename>\t\tText summary of a flight\n");
+ System.out.printf(" --oneline <filename>\t\tOne line summary of 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");
System.exit(code);
process = process_graph;
else if (args[i].equals("--summary"))
process = process_summary;
+ else if (args[i].equals("--oneline"))
+ process = process_oneline;
else if (args[i].startsWith("--"))
help(1);
else {
if (!process_summary(file))
++errors;
break;
+ case process_oneline:
+ if (!process_oneline(file))
+ ++errors;
+ break;
}
}
}
LINUX_SH=Altos-Linux-$(VERSION).sh
MACOSX_DIST=Altos-Mac-$(VERSION).dmg
WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe
+MDWN=$(VERSION).mdwn
+MDWNTMPL=mdwn.tmpl
FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS)
WINDOWS_FILES=$(FAT_FILES) $(FIRMWARE) altos.dll altos64.dll $(top_srcdir)/altusmetrum.inf $(top_srcdir)/altusmetrum.cat $(WINDOWS_ICONS)
-all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb
+all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb $(MDWN)
clean-local:
-rm -rf classes $(JAR) $(FATJAR) \
Altos-Linux-*.tar.bz2 Altos-Linux-*.sh Altos-Mac-*.dmg Altos-Windows-*.exe \
windows altoslib_*.jar altosuilib_*.jar $(FREETTS_CLASS) \
$(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log altos-windows.nsi \
- altosui altosui-test altosui-jdb macosx linux *.desktop
+ altosui altosui-test altosui-jdb macosx linux *.desktop $(MDWN)
EXTRA_DIST = $(desktop_file).in
if FATINSTALL
-FATTARGET=$(FATDIR)/$(VERSION)
+FATTARGET=$(FATDIR)/AltOS/releases/$(VERSION)
-LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
LINUX_SH_TARGET=$(FATTARGET)/$(LINUX_SH)
MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
+MDWN_TARGET=$(FATDIR)/AltOS/releases/$(MDWN)
+RELNOTES=release-notes-$(VERSION).html
+RELNOTES_SRC=$(top_builddir)/doc/$(RELNOTES)
+RELNOTES_TARGET=$(FATTARGET)/$(RELNOTES)
-fat: $(LINUX_DIST_TARGET) $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
-
-$(LINUX_DIST_TARGET): $(LINUX_DIST)
- mkdir -p $(FATTARGET)
- cp -p $< $@
+fat-install: fat $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET) $(MDWN_TARGET) $(RELNOTES_TARGET)
$(LINUX_SH_TARGET): $(LINUX_SH)
mkdir -p $(FATTARGET)
mkdir -p $(FATTARGET)
cp -p $< $@
-else
-fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
+$(MDWN_TARGET): $(MDWN)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+$(RELNOTES_TARGET): $(RELNOTES_SRC)
+ mkdir -p $(FATTARGET)
+ sh $(top_srcdir)/doc/install-html -d $(FATTARGET) $(RELNOTES_SRC)
+
endif
+$(MDWN): $(MDWNTMPL)
+ sed -e 's/%version%/$(VERSION)/g' -e 's/%version_dash%/$(VERSION_DASH)/g' $(MDWNTMPL) > $@
+
+fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
+
altosuidir=$(datadir)/java
install-altosuiJAVA: altosui.jar
--- /dev/null
+[[!inline pages="./%version%/release-notes-%version%.html" rss="no" raw="yes" ]]
+
+- Available Files:
+ - [Windows Installer](/AltOS/releases/%version%/Altos-Windows-%version_dash%.exe)
+ - [Mac OS X Package](/AltOS/releases/%version%/Altos-Mac-%version%.dmg)
+ - [Linux](/AltOS/releases/%version%/Altos-Linux-%version%.sh)
+ - [Source Snapshot](http://git.gag.com/?p=fw/altos;a=snapshot;h=refs/tags/%version%;sf=tgz)
public int row;
- final static String[] font_size_names = { "Small", "Medium", "Large" };
+ final static String[] font_size_names = { "Small", "Medium", "Large", "Huge" };
public GridBagConstraints constraints (int x, int width, int fill) {
GridBagConstraints c = new GridBagConstraints();
final public static int font_size_small = 1;
final public static int font_size_medium = 2;
final public static int font_size_large = 3;
+ final public static int font_size_huge = 4;
final public static int position_top_left = 0;
final public static int position_top = 1;
status_size = 30;
table_size = 17;
break;
+ case font_size_huge:
+ brief_size = 30;
+ status_size = 36;
+ table_size = 24;
+ break;
}
label_font = new Font("Dialog", Font.PLAIN, brief_size);
value_font = new Font("Monospaced", Font.PLAIN, brief_size);
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
-AC_INIT([altos], 1.8)
-ANDROID_VERSION=14
+AC_INIT([altos], 1.8.1)
+ANDROID_VERSION=15
AC_CONFIG_SRCDIR([src/kernel/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
-RELEASE_DATE=2017-08-11
+RELEASE_DATE=2017-08-27
AC_SUBST(RELEASE_DATE)
VERSION_DASH=`echo $VERSION | sed 's/\./-/g'`
AC_SUBST(ANDROID_SDK)
AC_ARG_WITH(fat-dir, AS_HELP_STRING([--with-fat-dir=PATH],
- [Set the directory to install the 'fat' distribution files to (defaults to not installing)]),
+ [Set the directory to install the 'fat-install' distribution files to (defaults to no such target)]),
[FATDIR=$withval], [FATDIR=none])
AM_CONDITIONAL(FATINSTALL, [test "x$FATDIR" != "xnone"])
#
RELNOTES_INC=\
+ release-notes-1.8.1.inc \
release-notes-1.8.inc \
release-notes-1.7.inc \
release-notes-1.6.8.inc \
</legalnotice>
<revhistory>
<?dbhtml filename="altusmetrum-revhistory.html"?>
+ <revision>
+ <revnumber>1.8.1</revnumber>
+ <date>27 Aug 2017</date>
+ <revremark>
+ Fix Apogee Lockout time value wrapping bug. Change high-speed
+ Kalman filter function.
+ </revremark>
+ </revision>
<revision>
<revnumber>1.8</revnumber>
<date>12 Aug 2017</date>
--- /dev/null
+= Release Notes for Version 1.8.1
+:toc!:
+:doctype: article
+
+ Version 1.8.1 includes an important bug fix for Apogee Lockout
+ operation in all flight computers. Anyone using this option
+ must update firmware.
+
+ This release also contains a change in how flight computers
+ with accelerometers deal with speeds around and above Mach
+ 1. In previous versions, the flight computer would completely
+ disregard the barometric sensor above 330m/s (around Mach
+ 1). Now, the data from the barometric sensor is reduced in
+ effect without ever going away entirely. This prevents early
+ drogue deployment for flights which spend considerable time
+ above Mach 1.
+
+ 1.8.1 also contains a couple of minor fixes for AltosUI when
+ analyzing saved data files.
+
+ == AltOS
+
+ AltOS Bug Fixes
+
+ * Handle time value wrapping in Apogee Lockout
+ correctly. Without this, apogee lockout would sometimes
+ prevent any drogue charge from firing.
+
+ * Change Kalman filter on flight computers with accelerometer
+ to continue using the barometric sensor even at high speeds
+ to avoid unintentional drogue deployment during
+ deceleration.
+
+ == AltosUI and TeleGPS Applications
+
+ AltosUI New Features
+
+ * Add new 'Huge' font size to make text even bigger on high
+ resolution monitors.
+
+ AltosUI Bug Fixes
+
+ * Prevent some crashes when reading older saved flight data
+ for graphing or KML export.
+
+ * Load frequency preference at startup. The loading code was
+ broken, so you'd see only the default frequencies.
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.8.1.raw[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.8.raw[]
desktop_file = altusmetrum-micropeak.desktop
desktop_SCRIPTS = $(desktop_file)
-all-local: micropeak-test micropeak-jdb $(JAR)
+all-local: micropeak-test micropeak-jdb $(JAR) $(MDWN)
clean-local:
-rm -rf classes $(JAR) $(FATJAR) \
altoslib_*.jar altosuilib_*.jar \
$(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt \
micropeak micropeak-test micropeak-jdb macosx linux windows micropeak-windows.log \
- micropeak-windows.nsi *.desktop
+ micropeak-windows.nsi *.desktop $(MDWN)
EXTRA_DIST = $(desktop_file).in
LINUX_SH=MicroPeak-Linux-$(VERSION).sh
MACOSX_DIST=MicroPeak-Mac-$(VERSION).dmg
WINDOWS_DIST=MicroPeak-Windows-$(VERSION_DASH).exe
+MDWN=$(VERSION).mdwn
+MDWNTMPL=mdwn.tmpl
MICROPEAK_DOC=$(top_srcdir)/doc/micropeak.pdf
if FATINSTALL
-FATTARGET=$(FATDIR)/$(VERSION)
+FATTARGET=$(FATDIR)/MicroPeak/releases/$(VERSION)
-LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
LINUX_SH_TARGET=$(FATTARGET)/$(LINUX_SH)
MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
+MDWN_TARGET=$(FATDIR)/MicroPeak/releases/$(MDWN)
+RELNOTES=release-notes-$(VERSION).html
+RELNOTES_SRC=$(top_builddir)/doc/$(RELNOTES)
+RELNOTES_TARGET=$(FATTARGET)/$(RELNOTES)
-fat: $(LINUX_DIST_TARGET) $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
-
-$(LINUX_DIST_TARGET): $(LINUX_DIST)
- mkdir -p $(FATTARGET)
- cp -p $< $@
+fat-install: $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET) $(MDWN_TARGET) $(RELNOTES_TARGET)
$(LINUX_SH_TARGET): $(LINUX_SH)
mkdir -p $(FATTARGET)
mkdir -p $(FATTARGET)
cp -p $< $@
-else
-fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
+$(MDWN_TARGET): $(MDWN)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+$(RELNOTES_TARGET): $(RELNOTES_SRC)
+ mkdir -p $(FATTARGET)
+ sh $(top_srcdir)/doc/install-html -d $(FATTARGET) $(RELNOTES_SRC)
+
endif
+$(MDWN): $(MDWNTMPL)
+ sed -e 's/%version%/$(VERSION)/g' -e 's/%version_dash%/$(VERSION_DASH)/g' $(MDWNTMPL) > $@
+
+fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
+
+
micropeak: Makefile
echo "#!/bin/sh" > $@
echo 'exec java -Djava.library.path="$(altoslibdir)" -jar "$(micropeakdir)/micropeak.jar" "$$@"' >> $@
@Override
public void windowClosing(WindowEvent e) {
statsTable.tell_closing();
+ raw.tell_closing();
Close();
}
});
import org.altusmetrum.altoslib_12.*;
import org.altusmetrum.altosuilib_12.*;
-public class MicroRaw extends JTextArea {
+public class MicroRaw extends JTextArea implements AltosFontListener {
+
+ public void font_size_changed(int font_size) {
+ setFont(AltosUILib.table_value_font);
+ }
public void setData(MicroData data) {
StringWriter sw = new StringWriter();
setCaretPosition(0);
}
+ public void tell_closing() {
+ AltosUIPreferences.unregister_font_listener(this);
+ }
+
public MicroRaw() {
super(1, 30);
setFont(AltosUILib.table_value_font);
setEditable(false);
+ AltosUIPreferences.register_font_listener(this);
}
}
--- /dev/null
+[[!inline pages="./%version%/release-notes-%version%.html" rss="no" raw="yes" ]]
+
+- Available Files:
+ - [Windows Installer](/MicroPeak/releases/%version%/MicroPeak-Windows-%version_dash%.exe)
+ - [Mac OS X Package](/MicroPeak/releases/%version%/MicroPeak-Mac-%version%.dmg)
+ - [Linux](/MicroPeak/releases/%version%/MicroPeak-Linux-%version%.sh)
+ - [Source Snapshot](http://git.gag.com/?p=fw/altos;a=snapshot;h=refs/tags/%version%;sf=tgz)
* number of seconds.
*/
if (ao_config.apogee_lockout) {
- if ((ao_sample_tick - ao_boost_tick) <
+ if ((int16_t) (ao_sample_tick - ao_boost_tick) <
AO_SEC_TO_TICKS(ao_config.apogee_lockout))
break;
}
* the measured altitude reasonably closely; otherwise
* we're probably transsonic.
*/
+#define AO_ERROR_BOUND 100
+
if (ao_speed < 0
#if !HAS_ACCEL
- && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100)
+ && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < AO_ERROR_BOUND)
#endif
)
{
__xdata ao_v_t ao_avg_height;
__pdata ao_v_t ao_error_h;
+#if !HAS_ACCEL
__pdata ao_v_t ao_error_h_sq_avg;
+#endif
#if HAS_ACCEL
__pdata ao_v_t ao_error_a;
ao_kalman_predict(void)
{
#ifdef AO_FLIGHT_TEST
- if (ao_sample_tick - ao_sample_prev_tick > 50) {
+ if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 50) {
ao_k_height += ((ao_k_t) ao_speed * AO_K_STEP_1 +
(ao_k_t) ao_accel * AO_K_STEP_2_2_1) >> 4;
ao_k_speed += (ao_k_t) ao_accel * AO_K_STEP_1;
return;
}
- if (ao_sample_tick - ao_sample_prev_tick > 5) {
+ if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 5) {
ao_k_height += ((ao_k_t) ao_speed * AO_K_STEP_10 +
(ao_k_t) ao_accel * AO_K_STEP_2_2_10) >> 4;
ao_k_speed += (ao_k_t) ao_accel * AO_K_STEP_10;
static void
ao_kalman_err_height(void)
{
+#if !HAS_ACCEL
ao_v_t e;
+#endif
ao_v_t height_distrust;
#if HAS_ACCEL
ao_v_t speed_distrust;
ao_error_h = ao_sample_height - (ao_v_t) (ao_k_height >> 16);
+#if !HAS_ACCEL
e = ao_error_h;
if (e < 0)
e = -e;
if (e > 127)
e = 127;
-#if HAS_ACCEL
- ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2;
- ao_error_h_sq_avg += (e * e) >> 2;
-#else
ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4;
ao_error_h_sq_avg += (e * e) >> 4;
#endif
return;
height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT;
#if HAS_ACCEL
- /* speed is stored * 16, but we need to ramp between 200 and 328, so
+ /* speed is stored * 16, but we need to ramp between 248 and 328, so
* we want to multiply by 2. The result is a shift by 3.
*/
speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1);
- if (speed_distrust <= 0)
- speed_distrust = 0;
- else if (speed_distrust > height_distrust)
+ if (speed_distrust > AO_MAX_SPEED_DISTRUST)
+ speed_distrust = AO_MAX_SPEED_DISTRUST;
+ if (speed_distrust > height_distrust)
height_distrust = speed_distrust;
#endif
if (height_distrust > 0) {
{
ao_kalman_err_height();
#ifdef AO_FLIGHT_TEST
- if (ao_sample_tick - ao_sample_prev_tick > 50) {
+ if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 50) {
ao_k_height += (ao_k_t) AO_BARO_K0_1 * ao_error_h;
ao_k_speed += (ao_k_t) AO_BARO_K1_1 * ao_error_h;
ao_k_accel += (ao_k_t) AO_BARO_K2_1 * ao_error_h;
return;
}
- if (ao_sample_tick - ao_sample_prev_tick > 5) {
+ if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 5) {
ao_k_height += (ao_k_t) AO_BARO_K0_10 * ao_error_h;
ao_k_speed += (ao_k_t) AO_BARO_K1_10 * ao_error_h;
ao_k_accel += (ao_k_t) AO_BARO_K2_10 * ao_error_h;
ao_kalman_err_accel();
#ifdef AO_FLIGHT_TEST
- if (ao_sample_tick - ao_sample_prev_tick > 50) {
+ if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 50) {
if (ao_flight_debug) {
printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
ao_k_speed / (65536.0 * 16.0),
(ao_k_t) AO_BOTH_K21_1 * ao_error_a;
return;
}
- if (ao_sample_tick - ao_sample_prev_tick > 5) {
+ if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 5) {
if (ao_flight_debug) {
printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
ao_k_speed / (65536.0 * 16.0),
{
ao_kalman_err_accel();
- if (ao_sample_tick - ao_sample_prev_tick > 5) {
+ if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 5) {
ao_k_height +=(ao_k_t) AO_ACCEL_K0_10 * ao_error_a;
ao_k_speed += (ao_k_t) AO_ACCEL_K1_10 * ao_error_a;
ao_k_accel += (ao_k_t) AO_ACCEL_K2_10 * ao_error_a;
ao_max_height = ao_height;
ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height;
#ifdef AO_FLIGHT_TEST
- if (ao_sample_tick - ao_sample_prev_tick > 50)
+ if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 50)
ao_avg_height = (ao_avg_height_scaled + 1) >> 1;
- else if (ao_sample_tick - ao_sample_prev_tick > 5)
+ else if ((int16_t) (ao_sample_tick - ao_sample_prev_tick) > 5)
ao_avg_height = (ao_avg_height_scaled + 7) >> 4;
else
#endif
ao_sample_rotate(void)
{
#ifdef AO_FLIGHT_TEST
- float dt = (ao_sample_tick - ao_sample_prev_tick) / TIME_DIV;
+ float dt = (int16_t) (ao_sample_tick - ao_sample_prev_tick) / TIME_DIV;
#else
static const float dt = 1/TIME_DIV;
#endif
/*
* Above this speed, baro measurements are unreliable
*/
-#define AO_MAX_BARO_SPEED 200
+#define AO_MAX_BARO_SPEED 248
+
+/* The maximum amount (in a range of 0-256) to de-rate the
+ * baro sensor data based on speed.
+ */
+#define AO_MAX_SPEED_DISTRUST 160
#define ACCEL_NOSE_UP (ao_accel_2g >> 2)
extern __xdata ao_v_t ao_avg_height; /* running average of height */
extern __pdata ao_v_t ao_error_h;
+#if !HAS_ACCEL
extern __pdata ao_v_t ao_error_h_sq_avg;
+#endif
#if HAS_ACCEL
extern __pdata ao_v_t ao_error_a;
#define AO_ADC_NUM_SENSE 2
#define HAS_MS5607 1
#define HAS_MMA655X 1
-#define AO_MMA655X_INVERT 1
+#define AO_MMA655X_INVERT 0
#define HAS_BEEP 1
#define AO_CONFIG_MAX_SIZE 1024
int tick_offset;
static ao_k_t ao_k_height;
+static double simple_speed;
int16_t
ao_time(void)
void
ao_sleep(void *wchan);
-const char const * const ao_state_names[] = {
+const char * const ao_state_names[] = {
"startup", "idle", "pad", "boost", "fast",
"coast", "drogue", "main", "landed", "invalid"
};
typedef int16_t accel_t;
+uint16_t ao_serial_number;
+uint16_t ao_flight_number;
+
extern uint16_t ao_sample_tick;
extern alt_t ao_sample_height;
double time;
ao_data_ring[ao_data_head] = ao_data_static;
- ao_data_head = ao_data_ring_next(ao_data_head);
if (ao_flight_state != ao_flight_startup) {
#if HAS_ACCEL
double accel = ((ao_flight_ground_accel - ao_data_accel_cook(&ao_data_static)) * GRAVITY * 2.0) /
#else
double accel = 0.0;
#endif
-#if TELEMEGA || TELEMETRUM_V2 || EASYMINI
- double height;
-
- ao_ms5607_convert(&ao_data_static.ms5607_raw, &ao_data_static.ms5607_cooked);
- height = ao_pa_to_altitude(ao_data_static.ms5607_cooked.pres) - ao_ground_height;
-#else
- double height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height;
-#endif
(void) accel;
if (!tick_offset)
tick_offset = -ao_data_static.tick;
if ((prev_tick - ao_data_static.tick) > 0x400)
tick_offset += 65536;
+ simple_speed += accel * (ao_data_static.tick - prev_tick) / 100.0;
prev_tick = ao_data_static.tick;
time = (double) (ao_data_static.tick + tick_offset) / 100;
+#if TELEMEGA || TELEMETRUM_V2 || EASYMINI
+ ao_ms5607_convert(&ao_data_static.ms5607_raw, &ao_data_static.ms5607_cooked);
+ double height = ao_pa_to_altitude(ao_data_static.ms5607_cooked.pres) - ao_ground_height;
+
+ /* Hack to skip baro spike at accidental drogue charge
+ * firing in 2015-09-26-serial-2093-flight-0012.eeprom
+ * so we can test the kalman filter with this data. Just
+ * keep reporting the same baro value across the pressure spike
+ */
+ {
+ static struct ao_ms5607_sample save;
+ if (ao_serial_number == 2093 && ao_flight_number == 12 && 32.5 < time && time < 33.7) {
+ ao_data_ring[ao_data_head].ms5607_raw = save;
+ } else {
+ save = ao_data_static.ms5607_raw;
+ }
+ }
+#else
+ double height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height;
+#endif
+
if (ao_test_max_height < height) {
ao_test_max_height = height;
ao_test_max_height_time = time;
#endif
#if 1
- printf("%7.2f height %8.2f accel %8.3f "
-#if TELEMEGA && 1
- "angle %5d "
+ printf("%7.2f height %8.2f accel %8.3f accel_speed %8.3f "
+ "state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d"
+#if TELEMEGA
+ " angle %5d "
"accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f mag_x %8d mag_y %8d, mag_z %8d mag_angle %4d "
#endif
- "state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n",
+ "\n",
time,
height,
accel,
-#if TELEMEGA && 1
- ao_sample_orient,
+ simple_speed > -100.0 ? simple_speed : -100.0,
+ ao_state_names[ao_flight_state],
+ ao_k_height / 65536.0,
+ ao_k_speed / 65536.0 / 16.0,
+ ao_k_accel / 65536.0 / 16.0,
+ ao_avg_height,
+ drogue_height,
+ main_height,
+ ao_error_h_sq_avg
+#if TELEMEGA
+ , ao_sample_orient,
ao_mpu6000_accel(ao_data_static.mpu6000.accel_x),
ao_mpu6000_accel(ao_data_static.mpu6000.accel_y),
ao_data_static.hmc5883.x,
ao_data_static.hmc5883.y,
ao_data_static.hmc5883.z,
- ao_mag_angle,
+ ao_mag_angle
#endif
- ao_state_names[ao_flight_state],
- ao_k_height / 65536.0,
- ao_k_speed / 65536.0 / 16.0,
- ao_k_accel / 65536.0 / 16.0,
- ao_avg_height,
- drogue_height,
- main_height,
- ao_error_h_sq_avg);
+ );
#endif
-
+
// if (ao_flight_state == ao_flight_landed)
// ao_test_exit();
}
}
+ ao_data_head = ao_data_ring_next(ao_data_head);
}
// printf ("\n");
switch (type) {
case 'F':
+ ao_flight_number = uint16(bytes, 0);
ao_flight_ground_accel = int16(bytes, 2);
ao_flight_started = 1;
ao_ground_pres = int32(bytes, 4);
switch (type) {
case 'F':
ao_flight_started = 1;
+ ao_flight_number = uint16(bytes, 0);
ao_ground_pres = uint32(bytes, 4);
ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
#if 0
// printf ("\n");
switch (type) {
case 'F':
+ ao_flight_number = uint16(bytes, 0);
ao_flight_ground_accel = int16(bytes, 2);
ao_flight_started = 1;
ao_ground_pres = int32(bytes, 4);
#endif
else if (nword == 2 && strcmp(words[0], "log-format") == 0) {
log_format = strtoul(words[1], NULL, 10);
+ } else if (nword == 2 && strcmp(words[0], "serial-number") == 0) {
+ ao_serial_number = strtoul(words[1], NULL, 10);
} else if (nword >= 6 && strcmp(words[0], "Accel") == 0) {
ao_config.accel_plus_g = atoi(words[3]);
ao_config.accel_minus_g = atoi(words[5]);
switch (type) {
case 'F':
ao_flight_ground_accel = a;
+ ao_flight_number = b;
if (ao_config.accel_plus_g == 0) {
ao_config.accel_plus_g = a;
ao_config.accel_minus_g = a + 530;
set y2tics border out nomirror
plot "$1" using 1:3 with lines axes x1y1 title "raw height",\
"$1" using 1:5 with lines axes x1y2 title "raw accel",\
-"$1" using 1:9 with lines axes x1y1 title "height",\
-"$1" using 1:11 with lines axes x1y2 title "speed",\
-"$1" using 1:13 with lines axes x1y2 title "accel",\
-"$1" using 1:17 with lines axes x1y1 title "drogue",\
-"$1" using 1:19 with lines axes x1y1 title "main",\
-"$1" using 1:21 with lines axes x1y1 title "error"
+"$1" using 1:7 with lines axes x1y2 title "accel speed",\
+"$1" using 1:11 with lines axes x1y1 title "height",\
+"$1" using 1:13 with lines axes x1y2 title "speed",\
+"$1" using 1:15 with lines axes x1y2 title "accel",\
+"$1" using 1:19 with lines axes x1y1 title "drogue",\
+"$1" using 1:21 with lines axes x1y1 title "main",\
+"$1" using 1:23 with lines axes x1y1 title "error"
EOF
desktop_file = altusmetrum-telegps.desktop
desktop_SCRIPTS = $(desktop_file)
-all-local: telegps-test telegps-jdb $(JAR)
+all-local: telegps-test telegps-jdb $(JAR) $(MDWN)
clean-local:
-rm -rf classes $(JAR) $(FATJAR) \
altoslib_*.jar altosuilib_*.jar \
$(JFREECHART_CLASS) $(JCOMMON_CLASS) $(FREETTS_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt \
telegps telegps-test telegps-jdb macosx linux windows telegps-windows.log \
- telegps-windows.nsi *.desktop
+ telegps-windows.nsi *.desktop $(MDWN)
EXTRA_DIST = $(desktop_file).in
LINUX_SH=TeleGPS-Linux-$(VERSION).sh
MACOSX_DIST=TeleGPS-Mac-$(VERSION).dmg
WINDOWS_DIST=TeleGPS-Windows-$(VERSION_DASH).exe
+MDWN=$(VERSION).mdwn
+MDWNTMPL=mdwn.tmpl
TELEGPS_DOC=$(top_srcdir)/doc/telegps.pdf
if FATINSTALL
-FATTARGET=$(FATDIR)/$(VERSION)
+FATTARGET=$(FATDIR)/TeleGPS/releases/$(VERSION)
-LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
LINUX_SH_TARGET=$(FATTARGET)/$(LINUX_SH)
MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
+MDWN_TARGET=$(FATDIR)/TeleGPS/releases/$(MDWN)
+RELNOTES=release-notes-$(VERSION).html
+RELNOTES_SRC=$(top_builddir)/doc/$(RELNOTES)
+RELNOTES_TARGET=$(FATTARGET)/$(RELNOTES)
-fat: $(LINUX_DIST_TARGET) $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
-
-$(LINUX_DIST_TARGET): $(LINUX_DIST)
- mkdir -p $(FATTARGET)
- cp -p $< $@
+fat-install: $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET) $(MDWN_TARGET) $(RELNOTES_TARGET)
$(LINUX_SH_TARGET): $(LINUX_SH)
mkdir -p $(FATTARGET)
mkdir -p $(FATTARGET)
cp -p $< $@
-else
-fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
+$(MDWN_TARGET): $(MDWN)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+$(RELNOTES_TARGET): $(RELNOTES_SRC)
+ mkdir -p $(FATTARGET)
+ sh $(top_srcdir)/doc/install-html -d $(FATTARGET) $(RELNOTES_SRC)
+
endif
+$(MDWN): $(MDWNTMPL)
+ sed -e 's/%version%/$(VERSION)/g' -e 's/%version_dash%/$(VERSION_DASH)/g' $(MDWNTMPL) > $@
+
+fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
+
+
telegps: Makefile
echo "#!/bin/sh" > $@
echo 'exec java -Djava.library.path="$(altoslibdir)" -jar "$(telegpsdir)/telegps.jar" "$$@"' >> $@
--- /dev/null
+[[!inline pages="./%version%/release-notes-%version%.html" rss="no" raw="yes" ]]
+
+- Available Files:
+ - [Windows Installer](/TeleGPS/releases/%version%/TeleGPS-Windows-%version_dash%.exe)
+ - [Mac OS X Package](/TeleGPS/releases/%version%/TeleGPS-Mac-%version%.dmg)
+ - [Linux](/TeleGPS/releases/%version%/TeleGPS-Linux-%version%.sh)
+ - [Source Snapshot](http://git.gag.com/?p=fw/altos;a=snapshot;h=refs/tags/%version%;sf=tgz)