Merge branch 'master' of git://git.gag.com/fw/altos
authorAnthony Towns <aj@erisian.com.au>
Sun, 5 Sep 2010 10:49:34 +0000 (20:49 +1000)
committerAnthony Towns <aj@erisian.com.au>
Sun, 5 Sep 2010 10:49:34 +0000 (20:49 +1000)
104 files changed:
.gitattributes [new file with mode: 0644]
.gitignore
ChangeLog
Makefile.am
ao-tools/altosui/.gitignore
ao-tools/altosui/Altos.java
ao-tools/altosui/AltosCRCException.java [new file with mode: 0644]
ao-tools/altosui/AltosCSV.java
ao-tools/altosui/AltosCSVUI.java [new file with mode: 0644]
ao-tools/altosui/AltosConfig.java
ao-tools/altosui/AltosConfigUI.java
ao-tools/altosui/AltosDebug.java [new file with mode: 0644]
ao-tools/altosui/AltosDevice.java
ao-tools/altosui/AltosEepromDownload.java
ao-tools/altosui/AltosEepromReader.java
ao-tools/altosui/AltosEepromRecord.java
ao-tools/altosui/AltosFlash.java [new file with mode: 0644]
ao-tools/altosui/AltosFlashUI.java [new file with mode: 0644]
ao-tools/altosui/AltosGPS.java
ao-tools/altosui/AltosGreatCircle.java
ao-tools/altosui/AltosHexfile.java [new file with mode: 0644]
ao-tools/altosui/AltosLine.java [new file with mode: 0644]
ao-tools/altosui/AltosLog.java
ao-tools/altosui/AltosLogfileChooser.java [new file with mode: 0644]
ao-tools/altosui/AltosParse.java
ao-tools/altosui/AltosReader.java
ao-tools/altosui/AltosRomconfig.java [new file with mode: 0644]
ao-tools/altosui/AltosRomconfigUI.java [new file with mode: 0644]
ao-tools/altosui/AltosSerial.java
ao-tools/altosui/AltosState.java
ao-tools/altosui/AltosTelemetry.java
ao-tools/altosui/AltosTelemetryReader.java
ao-tools/altosui/AltosUI.java
ao-tools/altosui/AltosVoice.java
ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/Example.nsi [new file with mode: 0644]
ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe [new file with mode: 0644]
ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.c [new file with mode: 0644]
ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsp [new file with mode: 0644]
ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsw [new file with mode: 0644]
ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/Readme.txt [new file with mode: 0644]
ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.inf [new file with mode: 0644]
ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys [new file with mode: 0644]
ao-tools/altosui/Instdrv/NSIS/Plugins/InstDrv.dll [new file with mode: 0644]
ao-tools/altosui/Makefile [deleted file]
ao-tools/altosui/Makefile-standalone [new file with mode: 0644]
ao-tools/altosui/Makefile.am [new file with mode: 0644]
ao-tools/altosui/Manifest.txt [deleted file]
ao-tools/altosui/altos-windows.nsi [new file with mode: 0644]
ao-tools/altosui/altosui-fat [new file with mode: 0755]
ao-tools/altosui/altosui.1 [new file with mode: 0644]
ao-tools/ao-dumplog/ao-dumplog.c
ao-tools/libaltos/.gitignore [new file with mode: 0644]
ao-tools/libaltos/Makefile [deleted file]
ao-tools/libaltos/Makefile-standalone [new file with mode: 0644]
ao-tools/libaltos/Makefile.am [new file with mode: 0644]
ao-tools/libaltos/altos.dll [new file with mode: 0755]
ao-tools/libaltos/cjnitest.c
ao-tools/libaltos/libaltos.c
ao-tools/libaltos/libaltos.dylib [new file with mode: 0755]
ao-tools/libaltos/libaltos.h
configure.ac
debian/altos.desktop
debian/changelog
debian/control
debian/dirs
doc/Makefile
icon/altus-metrum-16x16.jpg [new file with mode: 0644]
icon/altus-metrum.ico [new file with mode: 0644]
src/Makefile
src/Makefile.proto
src/Version.in [new file with mode: 0644]
src/ao.h
src/ao_adc.c
src/ao_cmd.c
src/ao_config.c
src/ao_dma.c
src/ao_gps_report.c
src/ao_gps_skytraq.c
src/ao_gps_test.c
src/ao_gps_test_skytraq.c
src/ao_log.c
src/ao_packet_master.c
src/ao_product.c
src/ao_radio.c
src/ao_romconfig.c [new file with mode: 0644]
src/ao_serial.c
src/ao_timer.c
src/ao_usb.c
src/cc1111.h
src/teledongle-v0.1/.gitignore
src/teledongle-v0.1/Makefile.defs
src/teledongle-v0.2/.gitignore
src/teledongle-v0.2/Makefile.defs
src/telemetrum-v0.1-sirf/.gitignore
src/telemetrum-v0.1-sirf/Makefile.defs
src/telemetrum-v0.1-sky/.gitignore
src/telemetrum-v0.1-sky/.sdcdbrc [new file with mode: 0644]
src/telemetrum-v0.1-sky/Makefile.defs
src/telemetrum-v1.0/.gitignore
src/telemetrum-v1.0/.sdcdbrc [new file with mode: 0644]
src/telemetrum-v1.0/Makefile.defs
src/tidongle/.gitignore
src/tidongle/Makefile.defs
telemetrum.inf

diff --git a/.gitattributes b/.gitattributes
new file mode 100644 (file)
index 0000000..f929a86
--- /dev/null
@@ -0,0 +1,2 @@
+ao-tools/libaltos/altos.dll            export-ignore
+ao-tools/libaltos/libaltos.dylib       export-ignore
index 16ff1f7bfee0eed0bdd43fcc570982dc21eb0b1c..13c9b43dd107d1bbd875fd91c8daf40a1542bf5d 100644 (file)
@@ -14,6 +14,9 @@
 .deps
 TAGS
 aclocal.m4
+libtool
+ltmain.sh
+src/Version
 src/ao_flight_test
 src/ao_gps_test
 src/ao_gps_test_skytraq
index 3398688420717534ff0b0fcae868547d742a1a86..709114346e3447628fb4ca34ed52220112cf7920 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+commit 59798c6fd11502a9c8b66090c23ba50eb250692e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 3 12:43:45 2010 -0700
+
+    altosui: Catch I/O errors on telemetry device, report to user
+    
+    This catches the USB device being unplugged and makes sure the
+    user sees an error dialog in this case.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 16d8d6a8853d09f683b13f9cda3c3174a0aab130
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 3 12:31:05 2010 -0700
+
+    altosui: Must flush serial line after configuring for telemetry
+    
+    Without flushing the configuration commands to the serial device, it
+    never sees them as the telemetry input thread doesn't flush.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d4f64e95e31e2335470efc15df2ab357b7d197f3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 3 11:48:55 2010 -0700
+
+    Revert "altosui: Deal with altos bug setting radio channel while monitoring"
+    
+    This reverts commit ba65e4aeb952a1cf49a77f1e24e235508fcea71f.
+    
+    Testing the old code
+
+commit 71191ecef3ba0e00d0f8a7cd1a24982bfa44ec72
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 3 01:30:33 2010 -0700
+
+    altosui: Allow 'connect to device' when already connected
+    
+    Opening another serial device involves shutting down the display
+    thread (to reset its state) and spawning another one. Shutting down
+    the display thread normally closes the serial device as a part of the
+    process, and if this isn't done before the new serial device is
+    opened, then the new serial device ends up getting closed too.
+    
+    Interrupting the display thread and waiting for it to stop before
+    opening the new serial device solves the problem.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ba65e4aeb952a1cf49a77f1e24e235508fcea71f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 3 01:21:57 2010 -0700
+
+    altosui: Deal with altos bug setting radio channel while monitoring
+    
+    If the monitoring thread is active, then setting the radio channel can
+    sometimes cause the monitoring thread to get stuck. I'm not entirely
+    sure why though. For now, work around the issue by making sure
+    monitoring is off, and the monitoring thread has stopped, before
+    changing the radio channel.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e5ef42c2b22c6639d90631dbbb588f9fd2494385
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 3 01:12:24 2010 -0700
+
+    altosui: Report telemetry CRC errors in UI
+    
+    Telemetry CRC errors can signal problems with TeleMetrum or TeleDongle
+    units, so report them in the UI.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b3aa448f3a0f44137f7530b04b58967ba5f22f5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 2 21:11:29 2010 -0700
+
+    altosui: build Mac OS .zip file to include paths
+    
+    Without the paths, the OS X zip file doesn't create a usable
+    application structure.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cff0d1ef6b338b3d5ad9450d4d5f95df934cb5e4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Sep 1 22:56:34 2010 -0700
+
+    altosui: Post error dialog on invalid ROM config values.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8d8980f56a4f2c7d6f2ce667130706e0f04f8ded
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Sep 1 22:56:12 2010 -0700
+
+    altosui: Remove some debug printfs from AltosRomconfig class
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5ee6cd41ed189c3166f76558ecada80917f40652
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Sep 1 22:47:15 2010 -0700
+
+    altosui: Hide internal rom config UI helper function
+    
+    This was getting mis-used by the flash UI causing the rom dialog
+    'cancel' button to work just like 'ok'.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9a690c9795e8257d2a3225f905117681668a472f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Sep 1 22:46:04 2010 -0700
+
+    altosui: allow flashing to be canceled from the rom config dialog
+    
+    Was using the rom config class wrong, causing cancel actions to work
+    just like 'ok' actions. Oops.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2f07ad14a16dbf1b75c71784ceae303825c90ade
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Sep 1 22:43:22 2010 -0700
+
+    altosui: Abort flashing if debug port isn't working
+    
+    Check each command going over the debug port and make sure it works as
+    expected. This commit adds checks for initializing the clock,
+    selecting the desired program counter and running the flash
+    program.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cf30343aadd5039627a85319872685f743e64b16
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:55:41 2010 -0400
+
+    update changelogs for Debian build
+
+commit 59a40f6d5a2159b9009a3fa0737bb679efd5b32c
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:55:01 2010 -0400
+
+    another distclean fix
+
+commit 59ff9180f11063c257746b895a167179b3a4ff7c
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:53:16 2010 -0400
+
+    and a few more distclean fixes
+
+commit 3aafd70257b70b7c11ba9c55749157979bc61ea2
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:52:04 2010 -0400
+
+    more makefile distclean target work
+
+commit d5a6ad87c7a9ac03b2e694bed0a54b6cc4322a6f
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:50:16 2010 -0400
+
+    update changelogs for Debian build
+
+commit 14fa24ed93b3b1cec08a170004c6fb7f4d74f7e5
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:48:31 2010 -0400
+
+    update changelogs for Debian build
+
+commit 83552dfa0d38db9cdf3efc89e64e6c7896467856
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:47:54 2010 -0400
+
+    add distclean targets to libaltos and altosui to all Debian package to build
+
+commit 6f24d2a476759104a10b26b54faff2b18b0e208b
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:46:21 2010 -0400
+
+    update changelogs for Debian build
+
+commit d079bfe86ed40ff450ece445cf5f5e3970e44cec
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Sep 2 00:44:30 2010 -0400
+
+    update changelogs for Debian build
+
+commit a470315e5d822a69ef5304512cf73c604c88e481
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Sep 1 20:14:51 2010 -0700
+
+    altosui: Remove Manifest.txt from git repo as it's built now
+    
+    This file is built with appropriate contents for each different .jar file.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1177e0a684328422be5adc68093d0091a218a824
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Sep 1 19:53:24 2010 -0700
+
+    altos: Bounds check Skytraq GPS tracking data array
+    
+    Missing GPS serial data could cause the tracking array reset to
+    get skipped, causing the array to be overrun, smashing critical data
+    beyond the array.
+    
+    This was detected using the 'altosui' flash command to program a
+    device from TM. Hitting the USB that hard caused TM to crash with a
+    mutex error (3 beeps) after the ao_gps_task structure was overwritten
+    with zeros.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 775acb89660cdee2f3c54c38297baefe39f2414c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 22:24:09 2010 -0700
+
+    altosui: missed AltosReader.class in the Makefile
+    
+    This caused clean builds to fail to make this file
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bd2b9d958c2b7f846031b076ed51c4fbaaf2d68f
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Aug 31 00:20:06 2010 -0400
+
+    update changelogs for Debian build
+
+commit d006c5e1255433181aca4c8e6a277b2d1bc0841b
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Aug 31 00:19:37 2010 -0400
+
+    add runtime dependencies for altos binary package
+
+commit c1c7d731e3774883fa0bb5538be225a59334d124
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 30 19:52:51 2010 -0600
+
+    update changelogs for Debian build
+
+commit c35632efb1919764e4b8581ed6fcf2bedd4bd517
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 30 19:37:50 2010 -0600
+
+    update changelogs for Debian build
+
+commit 2a004d17a13b4ff52d892bfdecff8ad3d0823f7c
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 30 19:37:17 2010 -0600
+
+    don't build all the "fat" jar deliverables by default
+
+commit 507e429db6638f82c32449e9c5ca06b46da30134
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 30 19:09:00 2010 -0600
+
+    update changelogs for Debian build
+
+commit 25764fcd1b65c3a5a817afdb5901ac30e8a5f0c0
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 30 19:08:29 2010 -0600
+
+    update changelogs for Debian build
+
+commit 4790f78aead8a816e5b247c022b2998ce3a94053
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 30 18:48:50 2010 -0600
+
+    add a .gitattributes file, configuring the Mac and Windows binary library
+    files with the export-ignore attribute, in hopes that this will prevent
+    them showing up in source packages
+
+commit 81318e5b7179b0311ab099043ecb04a25d763750
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 30 18:15:40 2010 -0600
+
+    make invocation of 'install' pathless to work on more Unix variants
+
+commit cbc72399a0f4d7429df0189bcdae683dd491cb9e
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 30 17:56:56 2010 -0600
+
+    continue even if rm's don't have anything to do
+
+commit a9a8d23c877e6f6c76857b7c85e3d43b4da1db27
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 05:49:11 2010 -0700
+
+    altosui: Devices with USB id 0x000a always get listed
+    
+    List 'unknown' AltusMetrum devices anytime the UI needs a device
+    name.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a94900b8862b99b4e317ea0ee3edd2a560f270c7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 05:48:23 2010 -0700
+
+    altosui: build debian-style altosui too
+    
+    This adds the dependencies to make sure altosui and altosui.jar get built.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 38ac388baf8125c0644b868a7aaf8eba1bdf990d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 05:28:37 2010 -0700
+
+    altosui: Build linux, mac and windows archives on Linux
+    
+    This adds 'fat' archives for each target OS.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 35d9a8214252dbe79aeb69ae47d2e5c58a654702
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 05:27:45 2010 -0700
+
+    libaltos: Use overlapped I/O on windows
+    
+    Otherwise, reads block writes and vice-versa. Crazy stuff.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c7ba92317ac55272acbde12416448ebd17b983a6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 04:52:00 2010 -0700
+
+    altos: Windows sends USB Out packets of 0 length. Ack them.
+    
+    This was an untested case as no other operating system sents 0-length
+    out packets (they're not necessary). The correct response is to ACK
+    them by clearing the OUTPKT_RDY bit so that another packet can be sent.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 20a472cfe3369200150ea4ff067ceb28968dbcac
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 02:58:23 2010 -0700
+
+    libaltos: Add pre-built Windows .dll
+    
+    This lets us create the windows distribution on Linux.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0300fe581c949232bc52b05fe9c1f6032cad6b60
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 02:56:25 2010 -0700
+
+    libaltos: Add pre-built Mac OS X libaltos.dylib
+    
+    This allows the mac bits to be built on Linux.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5d48c494325524bbeed10e0dc7300ed44e7e208e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 02:53:26 2010 -0700
+
+    Update telemetrum.inf to include all current USB ids.
+    
+    Windows 7 has 'encouraged' us to split out each product into a
+    separate USB ID. telemetrum.inf now has all of them listed.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit df34bbe7d1c43b12ab6d610fe810b6e1683e4c21
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 02:49:49 2010 -0700
+
+    libaltos: Improve Makefile
+    
+    Builds Windows .dll correctly now and sample app.
+    Moves linux install target to end so it is not default
+    Adds .NOTPARALLEL to disable parallel gnumake.
+    Removes -g debugging flags to shrink file size.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dd5374b8e660012ae4f8b058454fd101e0749ca7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 30 02:00:30 2010 -0700
+
+    libaltos: Fix windows build.
+    
+    Need stdlib.h to get calloc/free defined, remove debug printfs, fix
+    serial timeouts.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 63c832394a829f41b8f77d075786530536360349
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 23:22:27 2010 -0700
+
+    altos: shut down packet mode cleanly
+    
+    Instead of constantly bashing the packet master thread, let it shut
+    itself down in an orderly fashion. It will shut down fairly quickly as
+    all of the activities in that thread are bounded. Otherwise, the
+    master packet thread might leave mutexes locked and all sorts of other
+    horrors.
+    
+    Tested on Linux and Mac OS X and shown to be reliable.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 43619c13f749b79c096d1e8fdab3d5cfb5fd85f1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 22:42:23 2010 -0700
+
+    altos: Abort radio harder when terminating packet mode.
+    
+    Make sure the master radio tasks don't get stuck waiting for an
+    incoming packet again by aborting the radio each time we poke the
+    tasks.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c4a8569f61eddf690d00337543462235ecbfbe54
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 22:41:18 2010 -0700
+
+    altos: flush pending output when terminating packet mode
+    
+    Just in case the last command sent hasn't been transmitted, hang
+    around for up to a second waiting for the data to get across the link.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1acd3c7ec167b1b18e4ea493e5978c938a91cc89
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 21:45:19 2010 -0700
+
+    libaltos: cjnitest needs altos_flush now
+
+commit 6527357d1f0e94faf9e7dacac10a39875131be7c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 21:43:46 2010 -0700
+
+    libaltos: Missing OS_LDFLAGS on cjnitest build
+
+commit b7fa1ea3338f63b8edcf8aacccb5e519ca0b213f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 21:41:40 2010 -0700
+
+    libaltos: Mac OS X cannot use 'poll(2)' on serial lines.
+    
+    Who ships this stuff, anyway? Instead of blocking, we'll poll every 100ms now,
+    otherwise, we won't be able to abort the read when the device is closed. Yay!
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e60c59123232915e808cee23ef89eb1a38ced34b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 21:40:21 2010 -0700
+
+    altosui: discard invalid lines while reading Eeprom flight data
+    
+    This shouldn't happen, but it's easy enough to get back in sync by just
+    skipping lines with weird contents.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ae02b1590439d5c8dfb472cf1f83a14fdcfbaf11
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 21:36:47 2010 -0700
+
+    altosui: provide separate flush_input/flush_output for serial. deal with monitor automatically
+    
+    (yes, this should be two patches, but the diffs in AltosSerial were merged together).
+    
+    First, this replaces the existing flush/flush_reply mess with two simple functions,
+    one to flush output to the serial device, making sure that all data written will be seen
+    while we wait for input. The other sucks any pending input off of the serial line and
+    discards it.
+    
+    Second, AltosSerial now tracks whether the serial line is being used for telemetry
+    monitoring. If so, it enables monitoring, otherwise it disables it. Eliminates a
+    bunch of manual state tracking elsewhere.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit edcfb1bdf64772d3b83405ccf99385b8fea5d8e4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 29 17:33:59 2010 -0700
+
+    libaltos: AltusMetrum devices use more than one USB ID.
+    
+    List all usb devices, picking those with AltusMetrum IDs.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 236685807b63860ad033aa0254ce8f6d8d36d4ef
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 22:26:09 2010 -0600
+
+    update changelogs for Debian build
+
+commit 1cda15fdef2d9d3e54354bd5c43a0bcc7e3240cb
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 22:24:51 2010 -0600
+
+    fix up for an 0.7 release
+
+commit 4c5c7c7f198775c398c1ad2edafb3488384cc297
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 22:13:38 2010 -0600
+
+    update changelogs for Debian build
+
+commit 42055af5c6f17d14a2f1c6a2b5e1ce6d3b45a615
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 13:13:19 2010 -0600
+
+    update changelogs for Debian build
+
+commit 0bd4cc03b3bf23aa32b5ce1921078021d1d8a9c6
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 13:12:46 2010 -0600
+
+    fix path to installed shared library
+
+commit 99c1d9b4ef10ec4ebbee058ce0bb38c954a0a3a6
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 12:41:26 2010 -0600
+
+    update changelogs for Debian build
+
+commit cf65c6b8056c4af7c26b52ec6f9fbd3400cef638
+Merge: 5f2f6a8 ae5eff7
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 12:38:25 2010 -0600
+
+    Merge branch 'bdale'
+    
+    Conflicts:
+       debian/control
+
+commit ae5eff7bc0b63047737223423009707bedcb00f5
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 12:37:36 2010 -0600
+
+    Revert "lose the prebuild hook for now while I'm fumbling"
+    
+    This reverts commit a21b6bb60ac1c07ebd161534a4ea63bfde50dcdf.
+
+commit de2e71c4923a0282df74dbe37d087c34b4ddd279
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 12:25:20 2010 -0600
+
+    fix man page delivery path
+
+commit a8dbe082960dc9bdd44c6e4b1198423c4e566029
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 12:18:28 2010 -0600
+
+    install altosui man page
+
+commit 5cc933039e4763b8675611c63b6147b42878a2bb
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 12:16:19 2010 -0600
+
+    fix permissions on installed jar file, switch from ao-view to altosui in
+    the desktop file
+
+commit 138009e9fad01f79df4c3820fbc206f78688bdce
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 12:06:01 2010 -0600
+
+    update Debian standards version
+
+commit c280071b7db4e9a7af31dc5740eb8d27f137950e
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 12:04:13 2010 -0600
+
+    fix up the wrapper's path to the jar file
+
+commit 5f2f6a8f9ba56be867888758848bc7f152ccbd47
+Merge: 63bd34c 9d1b27f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Aug 27 11:00:31 2010 -0700
+
+    Merge remote branch 'origin/master' into new-packet-format
+
+commit 63bd34cd1b5a411489e8c3ab377f0fe0eec11f67
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Aug 27 10:58:55 2010 -0700
+
+    altosui: add elevation and range information
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 72a18502e40f55cbba6418dc94315517881cd411
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 11:51:24 2010 -0600
+
+    add an install target for altosui
+
+commit 72c33a72ee105ec692dad62d6d9c1ad40b89bfe8
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 11:45:19 2010 -0600
+
+    add install target for libaltos
+
+commit a21b6bb60ac1c07ebd161534a4ea63bfde50dcdf
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 11:26:29 2010 -0600
+
+    lose the prebuild hook for now while I'm fumbling
+
+commit 9ea94411c9730f7a271366d309ab4827beeeb839
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 11:17:54 2010 -0600
+
+    add a dummy install target
+
+commit c443f43f8dee6e0fcbcecf9d09e948fd928b7af4
+Merge: 2950431 2923cf5
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Aug 27 03:08:53 2010 -0600
+
+    Merge branch 'new-packet-format' of ssh://git.gag.com/scm/git/fw/altos into new-package-format
+
+commit 2923cf5057f9cef110dd547d8677ea5b60e00796
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Aug 27 00:10:29 2010 -0700
+
+    altos: prepare for sdcc 2.9.1
+    
+    A few minor language changes -- non-standard keywords are now prefixed
+    with __, such as 'at', 'interrupt', 'naked'.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 68967157cee620ebedcc8c2ffd6fc7656532087b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:55:44 2010 -0700
+
+    altosui: command line args are converted to csv format
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7e0506dc2014b7178f52b950e8c1cb820b35f9c6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:54:53 2010 -0700
+
+    altosui: Remove debug printf from AltosState.java
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 49364608b59de7421ab00d87d2685bc3b5f58411
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:53:06 2010 -0700
+
+    altosui: When parsing saved telem files, errors shouldn't abort file
+    
+    Make syntax errors in telem files just skip the current line and move
+    on to the next one instead of abandoning the whole file.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a16db143fc7ca72dc91e7989420049192114642d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:50:51 2010 -0700
+
+    altosui: Serial line is in UTF-8 encoding. Deal with it.
+    
+    We read bytes from the serial line and need to convert each line into
+    a string. So, save the bytes and at EOL, pass the whole mess to the
+    string constructor with the appropriate encoding info.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0942912163255523d923140c01afbdb5da1c19b5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:49:37 2010 -0700
+
+    altosui: Add support for old (version < 3) telemetry files
+    
+    This lets the code read telemetry files from pre-released versions of
+    the software. Not strictly necessary for production, but useful for
+    analysing old files.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e383595cd281687de903fb6176564bbef270cb83
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:47:38 2010 -0700
+
+    altosui: AltosEepromReader was mis-setting boost tick
+    
+    It was supposed to use record.tick instead of the (unset) state.tick
+    value.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 651f6102ac79459fc8d5679d852c963dcb5bb3fc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:44:25 2010 -0700
+
+    altosui: add rssi and distance/dir from pad to CSV files
+    
+    Just adds a couple more fields to the CSV files that might be interesting.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3dc67c1401976d6e9e2e942d5a4707a4810a0404
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:43:00 2010 -0700
+
+    altosui: Add AltosGreatCircle constructors
+    
+    This adds constructurs from AltosGPS pairs and also one from empty
+    args (which defines both distance and bearing as 0).
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f0fd423d0bf83bc5c3f9d39e9c09397fbe8caed2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:41:26 2010 -0700
+
+    altosui: Move number parsing code to Altos general class
+    
+    This moves these shared functions to the global shared class.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 68b2b66d7574dfd0bd5e3571b8ffad32ca5d2b73
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 23:37:29 2010 -0700
+
+    altos: mark gps date written only after it gets into eeprom
+    
+    Data logging doesn't start until boost detect occurs. As the GPS date
+    is only logged once, if that happens before logging is written to the
+    flash, then the GPS date will never get saved.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit aa6c27df5db6bdae59d00affccb891854a6caa18
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 15:59:09 2010 -0700
+
+    altos: print GPS state flags in GPS 'g' command
+    
+    Having the GPS state information can help with GPS debugging.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 34055129b4008f6a9833887b12dee39ffa408002
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 26 15:57:09 2010 -0700
+
+    altos: always rebuild ao_product.c to track git version
+    
+    The git version is built into ao_product.c and saved in eeprom log
+    files, providing useful diagnostics about the firmware revision used
+    for each flight. However, if ao_product.c isn't recompiled, then the
+    updated version won't be included. Force recompilation of this file
+    each time make is run to ensure that the final output contains an
+    updated version number.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 99400fdc0f19ef538fc362dde5c3ab5b7cdac409
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 24 16:43:38 2010 -0700
+
+    altosui: flush replies from serial link when entering debug mode
+    
+    We use replies in debug mode a lot and depend on them matching the
+    expected parameters. The case which caused trouble was using
+    TeleMetrum to reprogram TeleDongle -- sending the 'm 0' command (to
+    disable telemetry monitoring on TeleDongle) to the TeleMetrum caused
+    it to reply 'Syntax Error' which confused the subsequent flashing
+    operation. Flushing that reply gets things back in sync.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ba086cc77273efe5397f60dcaccd1e3771441481
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 24 04:02:27 2010 -0700
+
+    altosui: write USB serial number string while flashing
+    
+    USB serial number is encoded in UCS2 as a part of the string
+    descriptors. Place those right after the other rom config bits so that
+    altosui can find it. altosui is changed to write the serial number there.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 220f3afdaa432c65f8ad45be7cdbe5c8a3616db3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 24 04:01:47 2010 -0700
+
+    altosui: always display romconfig ui while flashing
+
+commit f62b2aa08ebfd912b3c732397d43ff9f6162ec88
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 24 04:01:14 2010 -0700
+
+    altosui: fetch existing romconfig for flashing
+
+commit d93787284c8e514a929edb9f944c98ae0206a33f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 24 03:59:09 2010 -0700
+
+    altosui: Delay mapping Flash UI until flashing actually starts
+    
+    The flash operation may be abandoned before it even starts; this makes
+    sure the UI doesn't flash up on the screen.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7d44cbd621d2b113ac2b802ef17e3d8a660ce7f2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 24 03:58:00 2010 -0700
+
+    altosui: disable radio monitoring while using serial line for debugging
+
+commit 7bd220dfd9b3fb0e42eb90c3b37eb7b4169eb21b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 24 00:29:11 2010 -0700
+
+    altosui: Add ability to create CSV file from telem or eeprom files
+    
+    This creates a comma separated value file to export data for
+    external programs.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 634a550149e7c344a22a637ba484f115592b1018
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 23:15:05 2010 -0700
+
+    altosui: refactor logfile chooser dialog to share more code
+    
+    Move file opening logic into logfile chooser as it can be shared that way.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a55b132668a819cc26478a609cb79bd9190deb9d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 23:01:36 2010 -0700
+
+    altosui: Separate out log file choosing dialog to share with CSV generator
+    
+    This dialog will be shared with the CSV file generating code, so split
+    it out instead of duplicating it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 295043112ccde35092945c286596f9045ee6fa05
+Merge: 2007288 ef8376c
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Aug 23 23:11:22 2010 -0600
+
+    Merge branch 'new-packet-format' of ssh://git.gag.com/scm/git/fw/altos into new-package-format
+
+commit ef8376c4dd8262a34e02b6bb9e19e907ac2f4330
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 22:08:30 2010 -0700
+
+    altosui: make default Manifest look for built-in freetts
+
+commit 56b906f535ac2f86bcab71addbbcd376d74f6a73
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 22:03:36 2010 -0700
+
+    altos: Place rom config variables in fixed location
+    
+    The device serial number and radio calibration values are stored in
+    flash, mostly so that TeleDongle gets them saved.
+    
+    Placing them in well-known locations (starting at 0xa0) makes it
+    possible to find the previous configuration and to re-write it
+    easily, without requiring the .map file.
+    
+    altosui doesn't have the .map file parsing code, so it relies upon
+    this new technique. As a benefit, it reads the old values from the
+    device before reprogramming it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4c0c099716197ef7539be0cf55bbb164f6804958
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 22:02:21 2010 -0700
+
+    altosui: Finish device programming code
+    
+    Altosui can now reprogram Altusmetrum devices.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bd2b44ddd61fadd8bf8ee6bf783ce019b1be7cc0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 22:01:38 2010 -0700
+
+    altosui: Remove debug printf from AltosRomconfig
+
+commit c3f57ffdb6c74de90d982eacd604e658ce9b00a5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 22:01:11 2010 -0700
+
+    altosui: flush serial output before waiting for reply
+
+commit 8857ac5e43eac6db8d5594b8864df497a712242b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 22:00:16 2010 -0700
+
+    altosui: remove debug printf from AltosHexfile
+
+commit b1758be01397fd49c441f40852f3558fe9343a2d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 21:58:50 2010 -0700
+
+    altosui: Add lots more cc1111 debug interface functions
+    
+    These are sufficient to program the flash.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f9e80f39bc39e5882bfe75f959b6501cb3277cd2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 21:55:49 2010 -0700
+
+    libaltos: use pipe to wake up getchar on close. use mutexes
+
+commit 86f7b9314b042f2e512fdf35067817e68532867b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 21:54:47 2010 -0700
+
+    altosui: pad TM config dialog values to avoid clipping descenders
+
+commit b8519b8669ff54741dd738ac343fbd2424451247
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 21:53:37 2010 -0700
+
+    ao-dumplog: Fix --remote and --channel options to actually work
+
+commit ebeb13688a9a5442c838641ede6ba0dc92c9a1a4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 14:32:58 2010 -0700
+
+    altosui: Add debug dongle API, split flash UI out
+    
+    Create an API to talk through the debug port on another AltOS
+    device. Split the flash UI out from the flash implementation so that a
+    command line flash utility can be written.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7f8d7978606abe544b1b9b6065c5480ed813b8ec
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 23 11:53:19 2010 -0700
+
+    altosui: Add .ihx file reading code and stub out flashing UI
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2007288da8a83e3aa925e11cc196f1c65aab2e5c
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Aug 5 15:00:15 2010 -0400
+
+    working on java packaging details
+
+commit 44b26dd550eef789e70082ccaa46d7d430c67bce
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Aug 5 15:15:04 2010 -0400
+
+    add freetts as a build dep
+
+commit 0e17853c08f77debef3e8cf82e9cdb6a5079fc9b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 22 23:06:15 2010 -0700
+
+    altosui: Set callsign when fetching eeprom data over the air
+    
+    The updated firmware places the callsign in each packet to comply with
+    regulations, this ensures that TeleDongle has the current callsign
+    configured.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 953bc3438b10b21f3d65d292356c4ab2de23cddd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 22 23:05:20 2010 -0700
+
+    altosui: Add TeleMetrum configuration
+    
+    This presents a dialog with all of the user-settable options in the
+    TeleMetrum set for editing. Combo boxes are used for everything except
+    the callsign.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e1463d8e265dfd42c824d90088cd2a51b4cf8131
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 21 17:57:31 2010 -0700
+
+    altosui: Make teledongle callsign configurable
+    
+    Teledongle uses the callsign in packet mode; this provides a way to
+    set that.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 09252ec22d58e946494e4ca2cf367bf3bbe1cc50
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 21 17:09:41 2010 -0700
+
+    altos: Define USB product ID in per-product Makefile.defs file
+    
+    This allows Win7 to tell which kind of device is connected purely by
+    USB id as it doesn't expose the USB product ID string to user space.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 22800dc094797e1e0ad99124198809d0360f7556
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 17 18:22:28 2010 -0700
+
+    altosui: Select devices by USB vendor/product ID.
+    
+    Because Win7 doesn't expose the product name, we're swtiching to using
+    the USB idProduct/idVendor values. This patch adds support for
+    selecting devices by those new IDs.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d14c96663a1027164fa30ed89b53f5a9d3fdb82b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 17 18:19:43 2010 -0700
+
+    libaltos: integrate Windows support.
+    
+    This adds Windows support for discovery and I/O.
+    
+    The API to the library is mostly unchanged, except that it now exports
+    product and vendor USB IDs as Win7 doesn't expose the product name
+    anywhere that we've been able to find, so we'll be updating the
+    firmware to use unique idProduct values for each product.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9d1b27fa147fc8b765d5be165ebef7ee0f85bd37
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Aug 11 22:11:50 2010 -0400
+
+    update changelogs for Debian build
+
 commit b6da90b4627dde1fe88240c38c51559d8f781dd0
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Wed Aug 11 17:15:39 2010 -0400
@@ -16,6 +1074,55 @@ Date:   Wed Aug 11 08:36:59 2010 -0400
 
     update changelogs for Debian build
 
+commit 294d9c7db21eaf1e71504dbcca5040371abcce55
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 7 22:30:55 2010 -0400
+
+    ao-dumplog: add --channel option (for use with -R option)
+    
+    Sets the channel when downloading data with the -R option.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f317f1324b69b4241f4bb192e164b33d712d5a43
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 7 00:42:25 2010 -0400
+
+    altosui: Start adding code to write csv files from eeprom/telem files
+    
+    This is a start to code which can write out a csv file full of flight
+    data from either an eeprom or telem input file. It's not hooked up,
+    but the restructuring necessary is finished and the output is started.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4738cb2fc639adb1d9237e6c903479f0690dd81a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 7 00:40:59 2010 -0400
+
+    altos: add callsign to packet mode, increase payload to 64 bytes
+    
+    Untested, but it 'should' work. Need to add callsign setting to packet
+    mode users.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b7699a5907e64bc7547fcc27e73f4a35bbaabfff
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Aug 6 13:09:21 2010 -0400
+
+    altosui: Add comments to Eeprom reader
+
+commit 0e917f3ff822616adb147517ac961422e5fedbfd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 5 22:49:53 2010 -0400
+
+    altosui: Compute flight state from eeprom data
+    
+    This lets eeprom files be used to replay flights.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
 commit a0a9b445a4d379730b67720f8d7b682d5206a582
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Aug 5 15:16:48 2010 -0400
@@ -52,12 +1159,88 @@ Date:   Thu Aug 5 15:00:15 2010 -0400
 
     working on java packaging details
 
+commit d8bf05f7ad55964c9bce0551e58f4ef6c9f721ad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 5 13:50:18 2010 -0400
+
+    altosui: Split flight record out of telemetry class
+    
+    This will permit either telemetry or eeprom data to be used to
+    construct the sequence of flight events for reply or data generation.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 85a670b5a904d6750d0f179ae307baeb8fc7cbd2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 5 13:40:17 2010 -0400
+
+    altosui: Explicitly initialize Altos class
+    
+    Because the Altos class is never instantiated, the static initializers
+    are never called, leaving the string to state mapping empty. Hand-code
+    the call to the initialer instead.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
 commit 02f17f2cd26189e2676a9dc0d86bd959ed0bc3f4
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Thu Aug 5 00:54:05 2010 -0400
 
     move to science menu
 
+commit 9e8f7f75442303f9bfa99a0435984f5d36863ae6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jul 31 10:34:21 2010 -0700
+
+    altosui: Split status and info panels into separate files
+    
+    This moves some code out of AltosUI.java into separate files
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9c9b35254c693b3ade42b24d1e29eaf31e6ba2aa
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jul 31 10:24:56 2010 -0700
+
+    altosui: Clear displayed data rows as needed.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 88e0137a60d7a13ddb7781befa76650e13ad44ae
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jul 31 10:07:38 2010 -0700
+
+    altosui: Merge gps date and time classes into gps class
+    
+    No reason to split out the date and time information from the other gps info.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1c3b2fe357d6acf28f48aeddd91693f10381be51
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jul 31 10:05:15 2010 -0700
+
+    altosui: Capture config and version info in .eeprom files
+    
+    Instead of only writing the serial number to the .eeprom file, write
+    all of the config values and all of the version reply to the .eeprom
+    file. The config values, in particular, contain the accelerometer
+    calibration data which is needed to correctly compute acceleration
+    from the captured accelerometer data.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e286eb61ad2a90746c1c31f95d26d5edb48738d3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jul 31 09:57:49 2010 -0700
+
+    altosui: rename AltosEeprom -> AltosEepromDownload, split out Altos constants
+    
+    Renames the eeprom downloading code and adds a new file to share the
+    flight data constants across the various UI modules.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
 commit e3a9e3815db3f290e28b40ae02aa654f515cfc37
 Author: Bdale Garbee <bdale@gag.com>
 Date:   Sat Jul 31 10:55:27 2010 -0600
index 39e7c2446130cce0c7ba0874c3c00fd8c49b6951..66d7cb553574c8028a876669dc6d051d41520c79 100644 (file)
@@ -11,3 +11,6 @@ ChangeLog:
        (touch ChangeLog; echo 'git directory not found: installing possibly empty changelog.' >&2)
 
 dist-hook: ChangeLog
+
+fat:
+       cd ao-tools/altosui && $(MAKE) fat
index 59913193ea4a7a7c041165572bef4a09bd0c0684..89be1d53dbb17c3e6e732fa9cc4699029878ef32 100644 (file)
@@ -1,2 +1,19 @@
-*.class
+windows/
+linux/
+macosx/
+fat/
+Manifest.txt
+Manifest-fat.txt
+libaltosJNI
+classes
 altosui
+altosui-test
+classaltosui.stamp
+Altos-Linux-*.tar.bz2
+Altos-Mac-*.zip
+Altos-Windows-*.exe
+*.dll
+*.dylib
+*.so
+*.jar
+*.class
index 53359e23715dd0c0e584cac77ccd1b16bdbe4a45..07bd01ae2fb5bb5e4d342ac171514be0d7885d25 100644 (file)
@@ -114,4 +114,90 @@ public class Altos {
        static final int AO_GPS_DATE_VALID = (1 << 6);
        static final int AO_GPS_NUM_SAT_SHIFT = 0;
        static final int AO_GPS_NUM_SAT_MASK = 0xf;
+
+       static boolean isspace(int c) {
+               switch (c) {
+               case ' ':
+               case '\t':
+                       return true;
+               }
+               return false;
+       }
+
+       static boolean ishex(int c) {
+               if ('0' <= c && c <= '9')
+                       return true;
+               if ('a' <= c && c <= 'f')
+                       return true;
+               if ('A' <= c && c <= 'F')
+                       return true;
+               return false;
+       }
+
+       static boolean ishex(String s) {
+               for (int i = 0; i < s.length(); i++)
+                       if (!ishex(s.charAt(i)))
+                               return false;
+               return true;
+       }
+
+       static int fromhex(int c) {
+               if ('0' <= c && c <= '9')
+                       return c - '0';
+               if ('a' <= c && c <= 'f')
+                       return c - 'a' + 10;
+               if ('A' <= c && c <= 'F')
+                       return c - 'A' + 10;
+               return -1;
+       }
+
+       static int fromhex(String s) throws NumberFormatException {
+               int c, v = 0;
+               for (int i = 0; i < s.length(); i++) {
+                       c = s.charAt(i);
+                       if (!ishex(c)) {
+                               if (i == 0)
+                                       throw new NumberFormatException(String.format("invalid hex \"%s\"", s));
+                               return v;
+                       }
+                       v = v * 16 + fromhex(c);
+               }
+               return v;
+       }
+
+       static boolean isdec(int c) {
+               if ('0' <= c && c <= '9')
+                       return true;
+               return false;
+       }
+
+       static boolean isdec(String s) {
+               for (int i = 0; i < s.length(); i++)
+                       if (!isdec(s.charAt(i)))
+                               return false;
+               return true;
+       }
+
+       static int fromdec(int c) {
+               if ('0' <= c && c <= '9')
+                       return c - '0';
+               return -1;
+       }
+
+       static int fromdec(String s) throws NumberFormatException {
+               int c, v = 0;
+               int sign = 1;
+               for (int i = 0; i < s.length(); i++) {
+                       c = s.charAt(i);
+                       if (i == 0 && c == '-') {
+                               sign = -1;
+                       } else if (!isdec(c)) {
+                               if (i == 0)
+                                       throw new NumberFormatException(String.format("invalid number \"%s\"", s));
+                               return v;
+                       } else
+                               v = v * 10 + fromdec(c);
+               }
+               return v * sign;
+       }
 }
diff --git a/ao-tools/altosui/AltosCRCException.java b/ao-tools/altosui/AltosCRCException.java
new file mode 100644 (file)
index 0000000..4a529bc
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+public class AltosCRCException extends Exception {
+       public int rssi;
+
+       public AltosCRCException (int in_rssi) {
+               rssi = in_rssi;
+       }
+}
index 2493675849624d359db390ddb442253ed5df065e..4ce8e30e77dece9e86edbc1cc37f3fca1bf9f3de 100644 (file)
@@ -19,12 +19,20 @@ package altosui;
 
 import java.lang.*;
 import java.io.*;
+import java.text.*;
+import java.util.*;
+
 import altosui.AltosRecord;
+import altosui.AltosReader;
 
 public class AltosCSV {
-       File            name;
-       PrintStream     out;
-       boolean         header_written;
+       File                    name;
+       PrintStream             out;
+       boolean                 header_written;
+       boolean                 seen_boost;
+       int                     boost_tick;
+       LinkedList<AltosRecord> pad_records;
+       AltosState              state;
 
        static final int ALTOS_CSV_VERSION = 1;
 
@@ -36,6 +44,7 @@ public class AltosCSV {
         *      flight number
         *      callsign
         *      time (seconds since boost)
+        *      rssi
         *
         * Flight status
         *      state
@@ -45,6 +54,7 @@ public class AltosCSV {
         *      acceleration (m/s²)
         *      pressure (mBar)
         *      altitude (m)
+        *      height (m)
         *      accelerometer speed (m/s)
         *      barometer speed (m/s)
         *      temp (°C)
@@ -65,6 +75,10 @@ public class AltosCSV {
         *      hour (0-23)
         *      minute (0-59)
         *      second (0-59)
+        *      from_pad_dist (m)
+        *      from_pad_azimuth (deg true)
+        *      from_pad_range (m)
+        *      from_pad_elevation (deg from horizon)
         *
         * GPS Sat data
         *      hdop
@@ -72,12 +86,14 @@ public class AltosCSV {
         */
 
        void write_general_header() {
-               out.printf("version serial flight call time");
+               out.printf("version serial flight call time rssi");
        }
 
        void write_general(AltosRecord record) {
-               out.printf("%s,%d,%d,%s,%d",
-                          record.version, record.serial, record.flight, record.callsign, record.tick);
+               out.printf("%s,%d,%d,%s,%8.2f,%4d",
+                          record.version, record.serial, record.flight, record.callsign,
+                          (double) record.time,
+                          record.rssi);
        }
 
        void write_flight_header() {
@@ -85,31 +101,137 @@ public class AltosCSV {
        }
 
        void write_flight(AltosRecord record) {
-               out.printf("%d,%s", record.state, record.state());
+               out.printf("%d,%8s", record.state, record.state());
+       }
+
+       void write_basic_header() {
+               out.printf("acceleration pressure altitude height accel_speed baro_speed temperature battery_voltage drogue_voltage main_voltage");
+       }
+
+       void write_basic(AltosRecord record) {
+               out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f",
+                          record.acceleration(),
+                          record.pressure(),
+                          record.altitude(),
+                          record.height(),
+                          record.accel_speed(),
+                          state.baro_speed,
+                          record.temperature(),
+                          record.battery_voltage(),
+                          record.drogue_voltage(),
+                          record.main_voltage());
+       }
+
+       void write_gps_header() {
+               out.printf("connected locked nsat latitude longitude altitude year month day hour minute second pad_dist pad_range pad_az pad_el");
+       }
+
+       void write_gps(AltosRecord record) {
+               AltosGPS        gps = record.gps;
+               if (gps == null)
+                       gps = new AltosGPS();
+
+               AltosGreatCircle from_pad = state.from_pad;
+               if (from_pad == null)
+                       from_pad = new AltosGreatCircle();
+
+               out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%6d,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f",
+                          gps.connected?1:0,
+                          gps.locked?1:0,
+                          gps.nsat,
+                          gps.lat,
+                          gps.lon,
+                          gps.alt,
+                          gps.year,
+                          gps.month,
+                          gps.day,
+                          gps.hour,
+                          gps.minute,
+                          gps.second,
+                          from_pad.distance,
+                          state.range,
+                          from_pad.bearing,
+                          state.elevation);
        }
 
        void write_header() {
                out.printf("# "); write_general_header();
                out.printf(" "); write_flight_header();
+               out.printf(" "); write_basic_header();
+               out.printf(" "); write_gps_header();
+               out.printf ("\n");
+       }
+
+       void write_one(AltosRecord record) {
+               state = new AltosState(record, state);
+               write_general(record); out.printf(",");
+               write_flight(record); out.printf(",");
+               write_basic(record); out.printf(",");
+               write_gps(record);
                out.printf ("\n");
        }
 
+       void flush_pad() {
+               while (!pad_records.isEmpty()) {
+                       write_one (pad_records.remove());
+               }
+       }
+
        public void write(AltosRecord record) {
                if (!header_written) {
                        write_header();
                        header_written = true;
                }
-               write_general(record); out.printf(",");
-               write_flight(record);
-               out.printf ("\n");
+               if (!seen_boost) {
+                       if (record.state >= Altos.ao_flight_boost) {
+                               seen_boost = true;
+                               boost_tick = record.tick;
+                               flush_pad();
+                       }
+               }
+               if (seen_boost)
+                       write_one(record);
+               else
+                       pad_records.add(record);
        }
 
        public PrintStream out() {
                return out;
        }
 
+       public void close() {
+               if (!pad_records.isEmpty()) {
+                       boost_tick = pad_records.element().tick;
+                       flush_pad();
+               }
+               out.close();
+       }
+
+       public void write(AltosReader reader) {
+               AltosRecord     record;
+
+               reader.write_comments(out());
+               try {
+                       for (;;) {
+                               record = reader.read();
+                               if (record == null)
+                                       break;
+                               write(record);
+                       }
+               } catch (IOException ie) {
+                       System.out.printf("IOException\n");
+               } catch (ParseException pe) {
+                       System.out.printf("ParseException %s\n", pe.getMessage());
+               }
+       }
+
        public AltosCSV(File in_name) throws FileNotFoundException {
                name = in_name;
                out = new PrintStream(name);
+               pad_records = new LinkedList<AltosRecord>();
+       }
+
+       public AltosCSV(String in_string) throws FileNotFoundException {
+               this(new File(in_string));
        }
 }
diff --git a/ao-tools/altosui/AltosCSVUI.java b/ao-tools/altosui/AltosCSVUI.java
new file mode 100644 (file)
index 0000000..2d81236
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import altosui.AltosLogfileChooser;
+import altosui.AltosCSV;
+
+public class AltosCSVUI
+       extends JDialog
+       implements Runnable, ActionListener
+{
+       JFrame          frame;
+       Thread          thread;
+       AltosReader     reader;
+       AltosCSV        writer;
+
+       public void run() {
+               AltosLogfileChooser     chooser;
+
+               chooser = new AltosLogfileChooser(frame);
+               reader = chooser.runDialog();
+               if (reader == null)
+                       return;
+               JFileChooser    csv_chooser;
+
+               File file = chooser.file();
+               String path = file.getPath();
+               int dot = path.lastIndexOf(".");
+               if (dot >= 0)
+                       path = path.substring(0,dot);
+               path = path.concat(".csv");
+               csv_chooser = new JFileChooser(path);
+               int ret = csv_chooser.showSaveDialog(frame);
+               if (ret == JFileChooser.APPROVE_OPTION) {
+                       try {
+                               writer = new AltosCSV(csv_chooser.getSelectedFile());
+                       } catch (FileNotFoundException ee) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             file.getName(),
+                                                             "Cannot open file",
+                                                             JOptionPane.ERROR_MESSAGE);
+                       }
+                       writer.write(reader);
+                       reader.close();
+                       writer.close();
+               }
+       }
+
+       public void actionPerformed(ActionEvent e) {
+       }
+
+       public AltosCSVUI(JFrame in_frame) {
+               frame = in_frame;
+               thread = new Thread(this);
+               thread.start();
+       }
+}
index ac73e7c5ea88894daf6a5817e466f860a4f6b9d3..3d970748102abcd2b700cf9a80dc22b6f23142e5 100644 (file)
@@ -122,17 +122,17 @@ public class AltosConfig implements Runnable, ActionListener {
 
        void start_serial() throws InterruptedException {
                if (remote) {
-                       serial_line.printf("m 0\n");
                        serial_line.set_channel(AltosPreferences.channel());
                        serial_line.set_callsign(AltosPreferences.callsign());
                        serial_line.printf("p\n");
+                       serial_line.flush_input();
                }
        }
 
        void stop_serial() throws InterruptedException {
                if (remote) {
-                       serial_line.printf("~\n");
-                       serial_line.flush();
+                       serial_line.printf("~");
+                       serial_line.flush_output();
                }
        }
 
index 1d8c579a8c66ccefbb030db35f6e5576d6fd628b..605ccc8be65e9722306d75d2213f4ddd8f1fb8ae 100644 (file)
@@ -44,7 +44,10 @@ import altosui.AltosFlightInfoTableModel;
 
 import libaltosJNI.*;
 
-public class AltosConfigUI extends JDialog implements ActionListener, ItemListener, DocumentListener {
+public class AltosConfigUI
+       extends JDialog
+       implements ActionListener, ItemListener, DocumentListener
+{
 
        Container       pane;
        Box             box;
@@ -144,6 +147,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen
                c.fill = GridBagConstraints.NONE;
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
+               c.ipady = 5;
                version_label = new JLabel("Software version:");
                pane.add(version_label, c);
 
@@ -154,6 +158,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen
                c.weightx = 1;
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
+               c.ipady = 5;
                version_value = new JLabel("");
                pane.add(version_value, c);
 
@@ -164,6 +169,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen
                c.fill = GridBagConstraints.NONE;
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
+               c.ipady = 5;
                serial_label = new JLabel("Serial:");
                pane.add(serial_label, c);
 
@@ -174,6 +180,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen
                c.weightx = 1;
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
+               c.ipady = 5;
                serial_value = new JLabel("");
                pane.add(serial_value, c);
 
@@ -184,7 +191,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen
                c.fill = GridBagConstraints.NONE;
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
-               c.ipady = 3;
+               c.ipady = 5;
                main_deploy_label = new JLabel("Main Deploy Altitude(m):");
                pane.add(main_deploy_label, c);
 
@@ -275,7 +282,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen
                /* Buttons */
                c = new GridBagConstraints();
                c.gridx = 0; c.gridy = 7;
-               c.gridwidth = 2;
+               c.gridwidth = 6;
                c.fill = GridBagConstraints.NONE;
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
@@ -285,8 +292,8 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen
                save.setActionCommand("save");
 
                c = new GridBagConstraints();
-               c.gridx = 2; c.gridy = 7;
-               c.gridwidth = 2;
+               c.gridx = 0; c.gridy = 7;
+               c.gridwidth = 6;
                c.fill = GridBagConstraints.NONE;
                c.anchor = GridBagConstraints.CENTER;
                c.insets = il;
@@ -296,8 +303,8 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen
                reset.setActionCommand("reset");
 
                c = new GridBagConstraints();
-               c.gridx = 4; c.gridy = 7;
-               c.gridwidth = 2;
+               c.gridx = 0; c.gridy = 7;
+               c.gridwidth = 6;
                c.fill = GridBagConstraints.NONE;
                c.anchor = GridBagConstraints.LINE_END;
                c.insets = il;
diff --git a/ao-tools/altosui/AltosDebug.java b/ao-tools/altosui/AltosDebug.java
new file mode 100644 (file)
index 0000000..3f469d4
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.lang.*;
+import java.io.*;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.LinkedList;
+import java.util.Iterator;
+import altosui.AltosSerial;
+import altosui.AltosRomconfig;
+
+public class AltosDebug extends AltosSerial {
+
+       public static final byte WR_CONFIG =            0x1d;
+       public static final byte RD_CONFIG =            0x24;
+       public static final byte CONFIG_TIMERS_OFF =            (1 << 3);
+       public static final byte CONFIG_DMA_PAUSE =             (1 << 2);
+       public static final byte CONFIG_TIMER_SUSPEND =         (1 << 1);
+       public static final byte SET_FLASH_INFO_PAGE =          (1 << 0);
+
+       public static final byte GET_PC =               0x28;
+       public static final byte READ_STATUS =          0x34;
+       public static final byte STATUS_CHIP_ERASE_DONE =       (byte) (1 << 7);
+       public static final byte STATUS_PCON_IDLE =             (1 << 6);
+       public static final byte STATUS_CPU_HALTED =            (1 << 5);
+       public static final byte STATUS_POWER_MODE_0 =          (1 << 4);
+       public static final byte STATUS_HALT_STATUS =           (1 << 3);
+       public static final byte STATUS_DEBUG_LOCKED =          (1 << 2);
+       public static final byte STATUS_OSCILLATOR_STABLE =     (1 << 1);
+       public static final byte STATUS_STACK_OVERFLOW =        (1 << 0);
+
+       public static final byte SET_HW_BRKPNT =        0x3b;
+       public static byte       HW_BRKPNT_N(byte n)    { return (byte) ((n) << 3); }
+       public static final byte HW_BRKPNT_N_MASK =             (0x3 << 3);
+       public static final byte HW_BRKPNT_ENABLE =             (1 << 2);
+
+       public static final byte HALT =                 0x44;
+       public static final byte RESUME =               0x4c;
+       public static       byte DEBUG_INSTR(byte n)    { return (byte) (0x54|(n)); }
+       public static final byte STEP_INSTR =           0x5c;
+       public static        byte STEP_REPLACE(byte n)  { return  (byte) (0x64|(n)); }
+       public static final byte GET_CHIP_ID =          0x68;
+
+
+       boolean debug_mode;
+
+       void ensure_debug_mode() {
+               if (!debug_mode) {
+                       printf("D\n");
+                       flush_input();
+                       debug_mode = true;
+               }
+       }
+
+       void dump_memory(String header, int address, byte[] bytes, int start, int len) {
+               System.out.printf("%s\n", header);
+               for (int j = 0; j < len; j++) {
+                       if ((j & 15) == 0) {
+                               if (j != 0)
+                                       System.out.printf("\n");
+                               System.out.printf ("%04x:", address + j);
+                       }
+                       System.out.printf(" %02x", bytes[start + j]);
+               }
+               System.out.printf("\n");
+       }
+
+       /*
+        * Write target memory
+        */
+       public void write_memory(int address, byte[] bytes, int start, int len) {
+               ensure_debug_mode();
+//             dump_memory("write_memory", address, bytes, start, len);
+               printf("O %x %x\n", len, address);
+               for (int i = 0; i < len; i++)
+                       printf("%02x", bytes[start + i]);
+       }
+
+       public void write_memory(int address, byte[] bytes) {
+               write_memory(address, bytes, 0, bytes.length);
+       }
+
+       /*
+        * Read target memory
+        */
+       public byte[] read_memory(int address, int length)
+               throws IOException, InterruptedException {
+               byte[]  data = new byte[length];
+
+               flush_input();
+               ensure_debug_mode();
+               printf("I %x %x\n", length, address);
+               int i = 0;
+               int start = 0;
+               while (i < length) {
+                       String  line = get_reply().trim();
+                       if (!Altos.ishex(line) || line.length() % 2 != 0)
+                               throw new IOException(
+                                       String.format
+                                       ("Invalid reply \"%s\"", line));
+                       int this_time = line.length() / 2;
+                       for (int j = 0; j < this_time; j++)
+                               data[start + j] = (byte) ((Altos.fromhex(line.charAt(j*2)) << 4) +
+                                                 Altos.fromhex(line.charAt(j*2+1)));
+                       start += this_time;
+                       i += this_time;
+               }
+//             dump_memory("read_memory", address, data, 0, length);
+
+               return data;
+       }
+
+       /*
+        * Write raw bytes to the debug link using the 'P' command
+        */
+       public void write_bytes(byte[] bytes) throws IOException {
+               int i = 0;
+               ensure_debug_mode();
+               while (i < bytes.length) {
+                       int this_time = bytes.length - i;
+                       if (this_time > 8)
+                               this_time = 0;
+                       printf("P");
+                       for (int j = 0; j < this_time; j++)
+                               printf(" %02x", bytes[i+j]);
+                       printf("\n");
+                       i += this_time;
+               }
+       }
+
+       public void write_byte(byte b) throws IOException {
+               byte[] bytes = { b };
+               write_bytes(bytes);
+       }
+
+       /*
+        * Read raw bytes from the debug link using the 'G' command
+        */
+       public byte[] read_bytes(int length)
+               throws IOException, InterruptedException {
+
+               flush_input();
+               ensure_debug_mode();
+               printf("G %x\n", length);
+               int i = 0;
+               byte[] data = new byte[length];
+               while (i < length) {
+                       String line = get_reply().trim();
+                       String tokens[] = line.split("\\s+");
+                       for (int j = 0; j < tokens.length; j++) {
+                               if (!Altos.ishex(tokens[j]) ||
+                                   tokens[j].length() != 2)
+                                       throw new IOException(
+                                               String.format
+                                               ("Invalid read_bytes reply \"%s\"", line));
+                               try {
+                                       data[i + j] = (byte) Integer.parseInt(tokens[j], 16);
+                               } catch (NumberFormatException ne) {
+                                       throw new IOException(
+                                               String.format
+                                               ("Invalid read_bytes reply \"%s\"", line));
+                               }
+                       }
+                       i += tokens.length;
+               }
+               return data;
+       }
+
+       public byte read_byte() throws IOException, InterruptedException {
+               return read_bytes(1)[0];
+       }
+
+       public byte debug_instr(byte[] instruction) throws IOException, InterruptedException {
+               byte[] command = new byte[1 + instruction.length];
+               command[0] = DEBUG_INSTR((byte) instruction.length);
+               for (int i = 0; i < instruction.length; i++)
+                       command[i+1] = instruction[i];
+               write_bytes(command);
+               return read_byte();
+       }
+
+       public byte resume() throws IOException, InterruptedException {
+               write_byte(RESUME);
+               return read_byte();
+       }
+
+       public int read_uint16() throws IOException, InterruptedException {
+               byte[] d = read_bytes(2);
+               return ((int) (d[0] & 0xff) << 8) | (d[1] & 0xff);
+       }
+
+       public int read_uint8()  throws IOException, InterruptedException {
+               byte[] d = read_bytes(1);
+               return (int) (d[0] & 0xff);
+       }
+
+       public int get_chip_id() throws IOException, InterruptedException {
+               write_byte(GET_CHIP_ID);
+               return read_uint16();
+       }
+
+       public int get_pc() throws IOException, InterruptedException {
+               write_byte(GET_PC);
+               return read_uint16();
+       }
+
+       public byte read_status() throws IOException, InterruptedException {
+               write_byte(READ_STATUS);
+               return read_byte();
+       }
+
+       static final byte LJMP                  = 0x02;
+
+       public void set_pc(int pc) throws IOException, InterruptedException {
+               byte high = (byte) (pc >> 8);
+               byte low = (byte) pc;
+               byte[] jump_mem = { LJMP, high, low };
+               debug_instr(jump_mem);
+       }
+
+       public boolean check_connection() throws IOException, InterruptedException {
+               byte reply = read_status();
+               if ((reply & STATUS_CHIP_ERASE_DONE) == 0)
+                       return false;
+               if ((reply & STATUS_PCON_IDLE) != 0)
+                       return false;
+               if ((reply & STATUS_POWER_MODE_0) == 0)
+                       return false;
+               return true;
+       }
+
+       public AltosRomconfig romconfig() {
+               try {
+                       byte[] bytes = read_memory(0xa0, 10);
+                       return new AltosRomconfig(bytes, 0);
+               } catch (IOException ie) {
+               } catch (InterruptedException ie) {
+               }
+               return new AltosRomconfig();
+       }
+
+       /*
+        * Reset target
+        */
+       public void reset() {
+               printf ("R\n");
+       }
+}
\ No newline at end of file
index 3daf0742311b254ccfc35360391847c466c3b807..e62a0a7aa31f6b9e610c2c2d06372aae8ce44af3 100644 (file)
@@ -32,6 +32,7 @@ public class AltosDevice extends altos_device {
                        System.err.println("Native library failed to load.\n" + e);
                }
        }
+       public final static int AltusMetrum = libaltosConstants.USB_PRODUCT_ALTUSMETRUM;
        public final static int TeleMetrum = libaltosConstants.USB_PRODUCT_TELEMETRUM;
        public final static int TeleDongle = libaltosConstants.USB_PRODUCT_TELEDONGLE;
        public final static int TeleTerra = libaltosConstants.USB_PRODUCT_TELETERRA;
@@ -58,33 +59,23 @@ public class AltosDevice extends altos_device {
 
        public boolean matchProduct(int want_product) {
 
+               if (!isAltusMetrum())
+                       return false;
+
                if (want_product == Any)
                        return true;
 
                if (want_product == BaseStation)
                        return matchProduct(TeleDongle) || matchProduct(TeleTerra);
 
-               if (!isAltusMetrum())
-                       return false;
-
                int have_product = getProduct();
 
-               if (want_product == have_product)
+               if (have_product == AltusMetrum)        /* old devices match any request */
                        return true;
 
-               if (have_product != libaltosConstants.USB_PRODUCT_ALTUSMETRUM)
-                       return false;
-
-               String name = getName();
+               if (want_product == have_product)
+                       return true;
 
-               if (name == null)
-                       return false;
-               if (want_product == libaltosConstants.USB_PRODUCT_TELEMETRUM)
-                       return name.startsWith("TeleMetrum");
-               if (want_product == libaltosConstants.USB_PRODUCT_TELEDONGLE)
-                       return name.startsWith("TeleDongle");
-               if (want_product == libaltosConstants.USB_PRODUCT_TELETERRA)
-                       return name.startsWith("TeleTerra");
                return false;
        }
 
index 02a71118c331e72c0af2fb4d6d76d6b043defe49..6dbbd3ebb8c3477e8b41250cb39ab529a501272e 100644 (file)
@@ -142,6 +142,7 @@ public class AltosEepromDownload implements Runnable {
 
                                if (values == null) {
                                        System.out.printf("invalid line: %s\n", line);
+                                       continue;
                                } else if (values[0] != addr) {
                                        System.out.printf("data address out of sync at 0x%x\n",
                                                          block * 256 + values[0]);
@@ -223,10 +224,10 @@ public class AltosEepromDownload implements Runnable {
 
        public void run () {
                if (remote) {
-                       serial_line.printf("m 0\n");
                        serial_line.set_channel(AltosPreferences.channel());
                        serial_line.set_callsign(AltosPreferences.callsign());
-                       serial_line.printf("p\n");
+                       serial_line.printf("p\nE 0\n");
+                       serial_line.flush_input();
                }
 
                monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed);
@@ -247,6 +248,7 @@ public class AltosEepromDownload implements Runnable {
                if (remote)
                        serial_line.printf("~");
                monitor.done();
+               serial_line.flush_output();
                serial_line.close();
        }
 
index c29fd90b12391105d6ed76bfb5841d6c7c9e0e1e..cb82f9a9d6ced0f7f37596a178c88e52199d791e 100644 (file)
@@ -42,7 +42,7 @@ import altosui.AltosEepromMonitor;
  */
 class AltosOrderedRecord extends AltosEepromRecord implements Comparable<AltosOrderedRecord> {
 
-       int     index;
+       public int      index;
 
        public AltosOrderedRecord(String line, int in_index, int prev_tick)
                throws ParseException {
@@ -56,6 +56,11 @@ class AltosOrderedRecord extends AltosEepromRecord implements Comparable<AltosOr
                index = in_index;
        }
 
+       public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) {
+               super(in_cmd, in_tick, in_a, in_b);
+               index = in_index;
+       }
+
        public int compareTo(AltosOrderedRecord o) {
                int     tick_diff = tick - o.tick;
                if (tick_diff != 0)
@@ -96,10 +101,12 @@ public class AltosEepromReader extends AltosReader {
 
        int                     gps_tick;
 
-       boolean                 saw_boost;
-
        int                     boost_tick;
 
+       boolean                 saw_gps_date;
+
+       boolean                 missing_gps_time;
+
        public AltosRecord read() throws IOException, ParseException {
                for (;;) {
                        if (record == null) {
@@ -107,7 +114,7 @@ public class AltosEepromReader extends AltosReader {
                                        if (last_reported)
                                                return null;
                                        last_reported = true;
-                                       return state;
+                                       return new AltosRecord(state);
                                }
                                record = record_iterator.next();
 
@@ -121,9 +128,7 @@ public class AltosEepromReader extends AltosReader {
                        state.tick = record.tick;
                        switch (record.cmd) {
                        case Altos.AO_LOG_FLIGHT:
-                               state.ground_accel = record.a;
-                               state.flight = record.b;
-                               seen |= seen_flight;
+                               /* recorded when first read from the file */
                                break;
                        case Altos.AO_LOG_SENSOR:
                                state.accel = record.a;
@@ -133,8 +138,6 @@ public class AltosEepromReader extends AltosReader {
                                        ground_pres += state.pres;
                                        state.ground_pres = (int) (ground_pres / n_pad_samples);
                                        state.flight_pres = state.ground_pres;
-                                       System.out.printf("ground pressure %d altitude %f\n",
-                                                         record.b, state.altitude());
                                        ground_accel += state.accel;
                                        state.ground_accel = (int) (ground_accel / n_pad_samples);
                                        state.flight_accel = state.ground_accel;
@@ -156,12 +159,19 @@ public class AltosEepromReader extends AltosReader {
                                seen |= seen_deploy;
                                break;
                        case Altos.AO_LOG_STATE:
-                               System.out.printf("state %d\n", record.a);
                                state.state = record.a;
                                break;
                        case Altos.AO_LOG_GPS_TIME:
                                gps_tick = state.tick;
+                               AltosGPS old = state.gps;
                                state.gps = new AltosGPS();
+
+                               /* GPS date doesn't get repeated through the file */
+                               if (old != null) {
+                                       state.gps.year = old.year;
+                                       state.gps.month = old.month;
+                                       state.gps.day = old.day;
+                               }
                                state.gps.hour = (record.a & 0xff);
                                state.gps.minute = (record.a >> 8);
                                state.gps.second = (record.b & 0xff);
@@ -191,7 +201,7 @@ public class AltosEepromReader extends AltosReader {
                                }
                                break;
                        case Altos.AO_LOG_GPS_DATE:
-                               state.gps.year = record.a & 0xff;
+                               state.gps.year = (record.a & 0xff) + 2000;
                                state.gps.month = record.a >> 8;
                                state.gps.day = record.b & 0xff;
                                break;
@@ -218,6 +228,7 @@ public class AltosEepromReader extends AltosReader {
                        case Altos.AO_LOG_PRODUCT:
                                break;
                        case Altos.AO_LOG_SERIAL_NUMBER:
+                               state.serial = record.a;
                                break;
                        case Altos.AO_LOG_SOFTWARE_VERSION:
                                break;
@@ -228,6 +239,7 @@ public class AltosEepromReader extends AltosReader {
 
        public void write_comments(PrintStream out) {
                Iterator<AltosOrderedRecord>    iterator = records.iterator();
+               out.printf("# Comments\n");
                while (iterator.hasNext()) {
                        AltosOrderedRecord      record = iterator.next();
                        switch (record.cmd) {
@@ -250,7 +262,7 @@ public class AltosEepromReader extends AltosReader {
                                out.printf ("# Accel cal: %d %d\n", record.a, record.b);
                                break;
                        case Altos.AO_LOG_RADIO_CAL:
-                               out.printf ("# Radio cal: %d %d\n", record.a);
+                               out.printf ("# Radio cal: %d\n", record.a);
                                break;
                        case Altos.AO_LOG_MANUFACTURER:
                                out.printf ("# Manufacturer: %s\n", record.data);
@@ -268,6 +280,34 @@ public class AltosEepromReader extends AltosReader {
                }
        }
 
+       /*
+        * Given an AO_LOG_GPS_TIME record with correct time, and one
+        * missing time, rewrite the missing time values with the good
+        * ones, assuming that the difference between them is 'diff' seconds
+        */
+       void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) {
+
+               int diff = (bad.tick - good.tick + 50) / 100;
+
+               int hour = (good.a & 0xff);
+               int minute = (good.a >> 8);
+               int second = (good.b & 0xff);
+               int flags = (good.b >> 8);
+               int seconds = hour * 3600 + minute * 60 + second;
+
+               int new_seconds = seconds + diff;
+               if (new_seconds < 0)
+                       new_seconds += 24 * 3600;
+               int new_second = (new_seconds % 60);
+               int new_minutes = (new_seconds / 60);
+               int new_minute = (new_minutes % 60);
+               int new_hours = (new_minutes / 60);
+               int new_hour = (new_hours % 24);
+
+               bad.a = new_hour + (new_minute << 8);
+               bad.b = new_second + (flags << 8);
+       }
+
        /*
         * Read the whole file, dumping records into a RB tree so
         * we can enumerate them in time order -- the eeprom data
@@ -283,9 +323,13 @@ public class AltosEepromReader extends AltosReader {
                seen = 0;
                records = new TreeSet<AltosOrderedRecord>();
 
+               AltosOrderedRecord last_gps_time = null;
+
                int index = 0;
                int tick = 0;
 
+               boolean missing_time = false;
+
                try {
                        for (;;) {
                                String line = AltosRecord.gets(input);
@@ -294,12 +338,55 @@ public class AltosEepromReader extends AltosReader {
                                AltosOrderedRecord record = new AltosOrderedRecord(line, index++, tick);
                                if (record == null)
                                        break;
+                               if (record.cmd == Altos.AO_LOG_INVALID)
+                                       continue;
                                tick = record.tick;
-                               if (!saw_boost && record.cmd == Altos.AO_LOG_STATE &&
-                                   record.a == Altos.ao_flight_boost)
-                               {
-                                       saw_boost = true;
-                                       boost_tick = state.tick;
+                               if (record.cmd == Altos.AO_LOG_FLIGHT) {
+                                       state.ground_accel = record.a;
+                                       state.flight = record.b;
+                                       boost_tick = tick;
+                                       seen |= seen_flight;
+                               }
+
+                               /* Two firmware bugs caused the loss of some GPS data.
+                                * The flight date would never be recorded, and often
+                                * the flight time would get overwritten by another
+                                * record. Detect the loss of the GPS date and fix up the
+                                * missing time records
+                                */
+                               if (record.cmd == Altos.AO_LOG_GPS_DATE)
+                                       saw_gps_date = true;
+
+                               /* go back and fix up any missing time values */
+                               if (record.cmd == Altos.AO_LOG_GPS_TIME) {
+                                       last_gps_time = record;
+                                       if (missing_time) {
+                                               Iterator<AltosOrderedRecord> iterator = records.iterator();
+                                               while (iterator.hasNext()) {
+                                                       AltosOrderedRecord old = iterator.next();
+                                                       if (old.cmd == Altos.AO_LOG_GPS_TIME &&
+                                                           old.a == -1 && old.b == -1)
+                                                       {
+                                                               update_time(record, old);
+                                                       }
+                                               }
+                                               missing_time = false;
+                                       }
+                               }
+
+                               if (record.cmd == Altos.AO_LOG_GPS_LAT) {
+                                       if (last_gps_time == null || last_gps_time.tick != record.tick) {
+                                               AltosOrderedRecord add_gps_time = new AltosOrderedRecord(Altos.AO_LOG_GPS_TIME,
+                                                                                                        record.tick,
+                                                                                                        -1, -1, index-1);
+                                               if (last_gps_time != null)
+                                                       update_time(last_gps_time, add_gps_time);
+                                               else
+                                                       missing_time = true;
+
+                                               records.add(add_gps_time);
+                                               record.index = index++;
+                                       }
                                }
                                records.add(record);
                        }
index 86ac1fd26df67aadbeff272de8fa321debdc277e..95cbe0159d60d86c39655a0cd70cc5d8b4ad9e29 100644 (file)
@@ -44,10 +44,10 @@ public class AltosEepromRecord {
        public int      tick;
        public int      a;
        public int      b;
-       String          data;
+       public String   data;
        public boolean  tick_valid;
 
-       public AltosEepromRecord (String line) throws ParseException {
+       public AltosEepromRecord (String line) {
                tick_valid = false;
                tick = 0;
                a = 0;
@@ -55,56 +55,72 @@ public class AltosEepromRecord {
                data = null;
                if (line == null) {
                        cmd = Altos.AO_LOG_INVALID;
+                       data = "";
                } else {
-                       String[] tokens = line.split("\\s+");
+                       try {
+                               String[] tokens = line.split("\\s+");
 
-                       if (tokens[0].length() == 1) {
-                               if (tokens.length != 4)
-                                       throw new ParseException(line, 0);
-                               cmd = tokens[0].codePointAt(0);
-                               tick = Integer.parseInt(tokens[1],16);
-                               tick_valid = true;
-                               a = Integer.parseInt(tokens[2],16);
-                               b = Integer.parseInt(tokens[3],16);
-                       } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
-                               cmd = Altos.AO_LOG_CONFIG_VERSION;
-                               data = tokens[2];
-                       } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
-                               cmd = Altos.AO_LOG_MAIN_DEPLOY;
-                               a = Integer.parseInt(tokens[2]);
-                       } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
-                               cmd = Altos.AO_LOG_APOGEE_DELAY;
-                               a = Integer.parseInt(tokens[2]);
-                       } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
-                               cmd = Altos.AO_LOG_RADIO_CHANNEL;
-                               a = Integer.parseInt(tokens[2]);
-                       } else if (tokens[0].equals("Callsign:")) {
-                               cmd = Altos.AO_LOG_CALLSIGN;
-                               data = tokens[1].replaceAll("\"","");
-                       } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
-                               cmd = Altos.AO_LOG_ACCEL_CAL;
-                               a = Integer.parseInt(tokens[3]);
-                               b = Integer.parseInt(tokens[5]);
-                       } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
-                               cmd = Altos.AO_LOG_RADIO_CAL;
-                               a = Integer.parseInt(tokens[2]);
-                       } else if (tokens[0].equals("manufacturer")) {
-                               cmd = Altos.AO_LOG_MANUFACTURER;
-                               data = tokens[1];
-                       } else if (tokens[0].equals("product")) {
-                               cmd = Altos.AO_LOG_PRODUCT;
-                               data = tokens[1];
-                       } else if (tokens[0].equals("serial-number")) {
-                               cmd = Altos.AO_LOG_SERIAL_NUMBER;
-                               a = Integer.parseInt(tokens[1]);
-                       } else if (tokens[0].equals("software-version")) {
-                               cmd = Altos.AO_LOG_SOFTWARE_VERSION;
-                               data = tokens[1];
-                       } else {
+                               if (tokens[0].length() == 1) {
+                                       if (tokens.length != 4) {
+                                               cmd = Altos.AO_LOG_INVALID;
+                                               data = line;
+                                       } else {
+                                               cmd = tokens[0].codePointAt(0);
+                                               tick = Integer.parseInt(tokens[1],16);
+                                               tick_valid = true;
+                                               a = Integer.parseInt(tokens[2],16);
+                                               b = Integer.parseInt(tokens[3],16);
+                                       }
+                               } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+                                       cmd = Altos.AO_LOG_CONFIG_VERSION;
+                                       data = tokens[2];
+                               } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+                                       cmd = Altos.AO_LOG_MAIN_DEPLOY;
+                                       a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+                                       cmd = Altos.AO_LOG_APOGEE_DELAY;
+                                       a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+                                       cmd = Altos.AO_LOG_RADIO_CHANNEL;
+                                       a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Callsign:")) {
+                                       cmd = Altos.AO_LOG_CALLSIGN;
+                                       data = tokens[1].replaceAll("\"","");
+                               } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+                                       cmd = Altos.AO_LOG_ACCEL_CAL;
+                                       a = Integer.parseInt(tokens[3]);
+                                       b = Integer.parseInt(tokens[5]);
+                               } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+                                       cmd = Altos.AO_LOG_RADIO_CAL;
+                                       a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("manufacturer")) {
+                                       cmd = Altos.AO_LOG_MANUFACTURER;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("product")) {
+                                       cmd = Altos.AO_LOG_PRODUCT;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("serial-number")) {
+                                       cmd = Altos.AO_LOG_SERIAL_NUMBER;
+                                       a = Integer.parseInt(tokens[1]);
+                               } else if (tokens[0].equals("software-version")) {
+                                       cmd = Altos.AO_LOG_SOFTWARE_VERSION;
+                                       data = tokens[1];
+                               } else {
+                                       cmd = Altos.AO_LOG_INVALID;
+                                       data = line;
+                               }
+                       } catch (NumberFormatException ne) {
                                cmd = Altos.AO_LOG_INVALID;
                                data = line;
                        }
                }
        }
 
+       public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) {
+               tick_valid = true;
+               cmd = in_cmd;
+               tick = in_tick;
+               a = in_a;
+               b = in_b;
+       }
 }
diff --git a/ao-tools/altosui/AltosFlash.java b/ao-tools/altosui/AltosFlash.java
new file mode 100644 (file)
index 0000000..a3e431c
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import altosui.AltosHexfile;
+
+public class AltosFlash {
+       File            file;
+       FileInputStream input;
+       AltosHexfile    image;
+       JFrame          frame;
+       AltosDevice     debug_dongle;
+       AltosDebug      debug;
+       AltosRomconfig  rom_config;
+       ActionListener  listener;
+       boolean         aborted;
+
+       static final byte MOV_direct_data       = (byte) 0x75;
+       static final byte MOV_DPTR_data16       = (byte) 0x90;
+       static final byte MOV_A_data            = (byte) 0x74;
+       static final byte MOVX_atDPTR_A         = (byte) 0xf0;
+       static final byte MOVX_A_atDPTR         = (byte) 0xe0;
+       static final byte INC_DPTR              = (byte) 0xa3;
+       static final byte TRAP                  = (byte) 0xa5;
+
+       static final byte JB                    = (byte) 0x20;
+
+       static final byte MOV_A_direct          = (byte) 0xe5;
+       static final byte MOV_direct1_direct2   = (byte) 0x85;
+       static final byte MOV_direct_A          = (byte) 0xf5;
+       static final byte MOV_R0_data           = (byte) (0x78 | 0);
+       static final byte MOV_R1_data           = (byte) (0x78 | 1);
+       static final byte MOV_R2_data           = (byte) (0x78 | 2);
+       static final byte MOV_R3_data           = (byte) (0x78 | 3);
+       static final byte MOV_R4_data           = (byte) (0x78 | 4);
+       static final byte MOV_R5_data           = (byte) (0x78 | 5);
+       static final byte MOV_R6_data           = (byte) (0x78 | 6);
+       static final byte MOV_R7_data           = (byte) (0x78 | 7);
+       static final byte DJNZ_R0_rel           = (byte) (0xd8 | 0);
+       static final byte DJNZ_R1_rel           = (byte) (0xd8 | 1);
+       static final byte DJNZ_R2_rel           = (byte) (0xd8 | 2);
+       static final byte DJNZ_R3_rel           = (byte) (0xd8 | 3);
+       static final byte DJNZ_R4_rel           = (byte) (0xd8 | 4);
+       static final byte DJNZ_R5_rel           = (byte) (0xd8 | 5);
+       static final byte DJNZ_R6_rel           = (byte) (0xd8 | 6);
+       static final byte DJNZ_R7_rel           = (byte) (0xd8 | 7);
+
+       static final byte P1DIR                 = (byte) 0xFE;
+       static final byte P1                    = (byte) 0x90;
+
+       /* flash controller */
+       static final byte FWT                   = (byte) 0xAB;
+       static final byte FADDRL                = (byte) 0xAC;
+       static final byte FADDRH                = (byte) 0xAD;
+       static final byte FCTL                  = (byte) 0xAE;
+       static final byte FCTL_BUSY             = (byte) 0x80;
+       static final byte FCTL_BUSY_BIT         = (byte) 7;
+       static final byte FCTL_SWBSY            = (byte) 0x40;
+       static final byte FCTL_SWBSY_BIT        = (byte) 6;
+       static final byte FCTL_CONTRD           = (byte) 0x10;
+       static final byte FCTL_WRITE            = (byte) 0x02;
+       static final byte FCTL_ERASE            = (byte) 0x01;
+       static final byte FWDATA                = (byte) 0xAF;
+
+       static final byte ACC                   = (byte) 0xE0;
+
+       /* offsets within the flash_page program */
+       static final int FLASH_ADDR_HIGH        = 8;
+       static final int FLASH_ADDR_LOW         = 11;
+       static final int RAM_ADDR_HIGH          = 13;
+       static final int RAM_ADDR_LOW           = 14;
+       static final int FLASH_WORDS_HIGH       = 16;
+       static final int FLASH_WORDS_LOW        = 18;
+       static final int FLASH_TIMING           = 21;
+
+       /* sleep mode control */
+       static final int SLEEP                  = (byte) 0xbe;
+       static final int  SLEEP_USB_EN          = (byte) 0x80;
+       static final int  SLEEP_XOSC_STB        = (byte) 0x40;
+       static final int  SLEEP_HFRC_STB        = (byte) 0x20;
+       static final int  SLEEP_RST_MASK        = (byte) 0x18;
+       static final int   SLEEP_RST_POWERON    = (byte) 0x00;
+       static final int   SLEEP_RST_EXTERNAL   = (byte) 0x10;
+       static final int   SLEEP_RST_WATCHDOG   = (byte) 0x08;
+       static final int  SLEEP_OSC_PD          = (byte) 0x04;
+       static final int  SLEEP_MODE_MASK       = (byte) 0x03;
+       static final int   SLEEP_MODE_PM0       = (byte) 0x00;
+       static final int   SLEEP_MODE_PM1       = (byte) 0x01;
+       static final int   SLEEP_MODE_PM2       = (byte) 0x02;
+       static final int   SLEEP_MODE_PM3       = (byte) 0x03;
+
+       /* clock controller */
+       static final byte CLKCON                = (byte) 0xC6;
+       static final byte  CLKCON_OSC32K        = (byte) 0x80;
+       static final byte  CLKCON_OSC           = (byte) 0x40;
+       static final byte  CLKCON_TICKSPD       = (byte) 0x38;
+       static final byte  CLKCON_CLKSPD        = (byte) 0x07;
+
+       static final byte[] flash_page_proto = {
+
+               MOV_direct_data, P1DIR, (byte) 0x02,
+               MOV_direct_data, P1,    (byte) 0xFF,
+
+               MOV_direct_data, FADDRH, 0,     /* FLASH_ADDR_HIGH */
+
+               MOV_direct_data, FADDRL, 0,     /* FLASH_ADDR_LOW */
+
+               MOV_DPTR_data16, 0, 0,          /* RAM_ADDR_HIGH, RAM_ADDR_LOW */
+
+               MOV_R7_data, 0,                 /* FLASH_WORDS_HIGH */
+
+               MOV_R6_data, 0,                 /* FLASH_WORDS_LOW */
+
+
+               MOV_direct_data, FWT, 0x20,     /* FLASH_TIMING */
+
+               MOV_direct_data, FCTL, FCTL_ERASE,
+/* eraseWaitLoop: */
+               MOV_A_direct,           FCTL,
+               JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb,
+
+               MOV_direct_data, P1, (byte) 0xfd,
+
+               MOV_direct_data, FCTL, FCTL_WRITE,
+/* writeLoop: */
+               MOV_R5_data, 2,
+/* writeWordLoop: */
+               MOVX_A_atDPTR,
+               INC_DPTR,
+               MOV_direct_A, FWDATA,
+               DJNZ_R5_rel, (byte) 0xfa,               /* writeWordLoop */
+/* writeWaitLoop: */
+               MOV_A_direct, FCTL,
+               JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb,    /* writeWaitLoop */
+               DJNZ_R6_rel, (byte) 0xf1,               /* writeLoop */
+               DJNZ_R7_rel, (byte) 0xef,                       /* writeLoop */
+
+               MOV_direct_data, P1DIR, (byte) 0x00,
+               MOV_direct_data, P1,    (byte) 0xFF,
+               TRAP,
+       };
+
+       public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) {
+               int flash_word_addr = flash_addr >> 1;
+               int flash_word_count = ((byte_count + 1) >> 1);
+
+               byte[] flash_page = new byte[flash_page_proto.length];
+               for (int i = 0; i < flash_page.length; i++)
+                       flash_page[i] = flash_page_proto[i];
+
+               flash_page[FLASH_ADDR_HIGH]  = (byte) (flash_word_addr >> 8);
+               flash_page[FLASH_ADDR_LOW]   = (byte) (flash_word_addr);
+               flash_page[RAM_ADDR_HIGH]    = (byte) (ram_addr >> 8);
+               flash_page[RAM_ADDR_LOW]     = (byte) (ram_addr);
+
+               byte flash_words_low = (byte) (flash_word_count);
+               byte flash_words_high = (byte) (flash_word_count >> 8);
+               /* the flashing code has a minor 'bug' */
+               if (flash_words_low != 0)
+                       flash_words_high++;
+
+               flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high;
+               flash_page[FLASH_WORDS_LOW]  = (byte) flash_words_low;
+               return flash_page;
+       }
+
+       static byte[] set_clkcon_fast = {
+               MOV_direct_data, CLKCON, 0x00
+       };
+
+       static byte[] get_sleep = {
+               MOV_A_direct, SLEEP
+       };
+
+       public void clock_init() throws IOException, InterruptedException {
+               debug.debug_instr(set_clkcon_fast);
+
+               byte    status;
+               for (int times = 0; times < 20; times++) {
+                       Thread.sleep(1);
+                       status = debug.debug_instr(get_sleep);
+                       if ((status & SLEEP_XOSC_STB) != 0)
+                               return;
+               }
+               throw new IOException("Failed to initialize target clock");
+       }
+
+       void action(String s, int percent) {
+               if (listener != null && !aborted)
+                       listener.actionPerformed(new ActionEvent(this,
+                                                                percent,
+                                                                s));
+       }
+
+       void action(int part, int total) {
+               int percent = 100 * part / total;
+               action(String.format("%d/%d (%d%%)",
+                                    part, total, percent),
+                      percent);
+       }
+
+       void run(int pc) throws IOException, InterruptedException {
+               debug.set_pc(pc);
+               int set_pc = debug.get_pc();
+               if (pc != set_pc)
+                       throw new IOException("Failed to set target program counter");
+               debug.resume();
+
+               for (int times = 0; times < 20; times++) {
+                       byte status = debug.read_status();
+                       if ((status & AltosDebug.STATUS_CPU_HALTED) != 0)
+                               return;
+               }
+
+               throw new IOException("Failed to execute program on target");
+       }
+
+       public void flash() throws IOException, FileNotFoundException, InterruptedException {
+               if (!check_rom_config())
+                       throw new IOException("Invalid rom config settings");
+               if (image.address + image.data.length > 0x8000)
+                       throw new IOException(String.format("Flash image too long %d",
+                                                           image.address +
+                                                           image.data.length));
+               if ((image.address & 0x3ff) != 0)
+                       throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)",
+                                                           image.address));
+               int ram_address = 0xf000;
+               int flash_prog = 0xf400;
+
+               /*
+                * Store desired config values into image
+                */
+               rom_config.write(image);
+               /*
+                * Bring up the clock
+                */
+               clock_init();
+
+               int remain = image.data.length;
+               int flash_addr = image.address;
+               int image_start = 0;
+
+               action("start", 0);
+               action(0, image.data.length);
+               while (remain > 0 && !aborted) {
+                       int this_time = remain;
+                       if (this_time > 0x400)
+                               this_time = 0x400;
+
+                       /* write the data */
+                       debug.write_memory(ram_address, image.data,
+                                          image_start, this_time);
+
+                       /* write the flash program */
+                       byte[] flash_page = make_flash_page(flash_addr,
+                                                           ram_address,
+                                                           this_time);
+                       debug.write_memory(flash_prog, flash_page);
+
+                       run(flash_prog);
+
+                       byte[] check = debug.read_memory(flash_addr, this_time);
+                       for (int i = 0; i < this_time; i++)
+                               if (check[i] != image.data[image_start + i])
+                                       throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
+                                                                           image.address + image_start + i,
+                                                                           check[i], image.data[image_start + i]));
+                       remain -= this_time;
+                       flash_addr += this_time;
+                       image_start += this_time;
+
+                       action(image.data.length - remain, image.data.length);
+               }
+               if (!aborted) {
+                       action("done", 100);
+                       debug.set_pc(image.address);
+                       debug.resume();
+               }
+               debug.close();
+       }
+
+       public void abort() {
+               aborted = true;
+               debug.close();
+       }
+
+       public void addActionListener(ActionListener l) {
+               listener = l;
+       }
+
+       public boolean check_rom_config() {
+               if (rom_config == null)
+                       rom_config = debug.romconfig();
+               return rom_config != null && rom_config.valid();
+       }
+
+       public void set_romconfig (AltosRomconfig romconfig) {
+               rom_config = romconfig;
+       }
+
+       public AltosRomconfig romconfig() {
+               if (!check_rom_config())
+                       return null;
+               return rom_config;
+       }
+
+       public void open() throws IOException, FileNotFoundException, InterruptedException {
+               input = new FileInputStream(file);
+               image = new AltosHexfile(input);
+               debug.open(debug_dongle);
+               if (!debug.check_connection())
+                       throw new IOException("Debug port not connected");
+       }
+
+       public AltosFlash(File in_file, AltosDevice in_debug_dongle) {
+               file = in_file;
+               debug_dongle = in_debug_dongle;
+               debug = new AltosDebug();
+       }
+}
\ No newline at end of file
diff --git a/ao-tools/altosui/AltosFlashUI.java b/ao-tools/altosui/AltosFlashUI.java
new file mode 100644 (file)
index 0000000..1879569
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import altosui.AltosHexfile;
+import altosui.AltosFlash;
+
+public class AltosFlashUI
+       extends JDialog
+       implements Runnable, ActionListener
+{
+       Container       pane;
+       Box             box;
+       JLabel          serial_label;
+       JLabel          serial_value;
+       JLabel          file_label;
+       JLabel          file_value;
+       JProgressBar    pbar;
+       JButton         cancel;
+
+       File            file;
+       Thread          thread;
+       JFrame          frame;
+       AltosDevice     debug_dongle;
+       AltosFlash      flash;
+
+       public void actionPerformed(ActionEvent e) {
+               if (e.getSource() == cancel) {
+                       abort();
+                       dispose();
+               } else {
+                       String  cmd = e.getActionCommand();
+                       if (cmd.equals("done"))
+                               ;
+                       else if (cmd.equals("start")) {
+                               setVisible(true);
+                       } else {
+                               pbar.setValue(e.getID());
+                               pbar.setString(cmd);
+                       }
+               }
+       }
+
+       public void run() {
+               flash = new AltosFlash(file, debug_dongle);
+               flash.addActionListener(this);
+               try {
+                       flash.open();
+                       AltosRomconfigUI romconfig_ui = new AltosRomconfigUI (frame);
+
+                       romconfig_ui.set(flash.romconfig());
+                       AltosRomconfig romconfig = romconfig_ui.showDialog();
+
+                       if (romconfig != null && romconfig.valid()) {
+                               flash.set_romconfig(romconfig);
+                               serial_value.setText(String.format("%d",
+                                                                  flash.romconfig().serial_number));
+                               file_value.setText(file.toString());
+                               setVisible(true);
+                               flash.flash();
+                               flash = null;
+                       }
+               } catch (FileNotFoundException ee) {
+                       JOptionPane.showMessageDialog(frame,
+                                                     "Cannot open image",
+                                                     file.toString(),
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (IOException e) {
+                       JOptionPane.showMessageDialog(frame,
+                                                     e.getMessage(),
+                                                     file.toString(),
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (InterruptedException ie) {
+               } finally {
+                       abort();
+               }
+               dispose();
+       }
+
+       public void abort() {
+               if (flash != null)
+                       flash.abort();
+       }
+
+       public void build_dialog() {
+               GridBagConstraints c;
+               Insets il = new Insets(4,4,4,4);
+               Insets ir = new Insets(4,4,4,4);
+
+               pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 0;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               serial_label = new JLabel("Serial:");
+               pane.add(serial_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 0;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               serial_value = new JLabel("");
+               pane.add(serial_value, c);
+
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.NONE;
+               c.gridx = 0; c.gridy = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               file_label = new JLabel("File:");
+               pane.add(file_label, c);
+
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.gridx = 1; c.gridy = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               file_value = new JLabel("");
+               pane.add(file_value, c);
+
+               pbar = new JProgressBar();
+               pbar.setMinimum(0);
+               pbar.setMaximum(100);
+               pbar.setValue(0);
+               pbar.setString("");
+               pbar.setStringPainted(true);
+               pbar.setPreferredSize(new Dimension(600, 20));
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0; c.gridy = 2;
+               c.gridwidth = GridBagConstraints.REMAINDER;
+               Insets ib = new Insets(4,4,4,4);
+               c.insets = ib;
+               pane.add(pbar, c);
+
+               cancel = new JButton("Cancel");
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0; c.gridy = 3;
+               c.gridwidth = GridBagConstraints.REMAINDER;
+               Insets ic = new Insets(4,4,4,4);
+               c.insets = ic;
+               pane.add(cancel, c);
+               cancel.addActionListener(this);
+               pack();
+               setLocationRelativeTo(frame);
+       }
+
+       public AltosFlashUI(JFrame in_frame) {
+               super(in_frame, "Program Altusmetrum Device", false);
+
+               frame = in_frame;
+
+               build_dialog();
+
+               debug_dongle = AltosDeviceDialog.show(frame, AltosDevice.Any);
+
+               if (debug_dongle == null)
+                       return;
+
+               JFileChooser    hexfile_chooser = new JFileChooser();
+
+               hexfile_chooser.setDialogTitle("Select Flash Image");
+               hexfile_chooser.setFileFilter(new FileNameExtensionFilter("Flash Image", "ihx"));
+               int returnVal = hexfile_chooser.showOpenDialog(frame);
+
+               if (returnVal != JFileChooser.APPROVE_OPTION)
+                       return;
+
+               file = hexfile_chooser.getSelectedFile();
+
+               thread = new Thread(this);
+               thread.start();
+       }
+}
\ No newline at end of file
index b3ee67e8369186dabbf392efc6a33ae06fa9ec75..acb6fb2c8bbbdcb4c211022951ea13fb1427c2d2 100644 (file)
@@ -52,14 +52,16 @@ public class AltosGPS {
 
        AltosGPSSat[] cc_gps_sat;       /* tracking data */
 
-       void ParseGPSTime(String date, String time) throws ParseException {
+       void ParseGPSDate(String date) throws ParseException {
                String[] ymd = date.split("-");
                if (ymd.length != 3)
                        throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0);
                year = AltosParse.parse_int(ymd[0]);
                month = AltosParse.parse_int(ymd[1]);
                day = AltosParse.parse_int(ymd[2]);
+       }
 
+       void ParseGPSTime(String time) throws ParseException {
                String[] hms = time.split(":");
                if (hms.length != 3)
                        throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0);
@@ -73,7 +75,7 @@ public class AltosGPS {
                hour = minute = second = 0;
        }
 
-       public AltosGPS(String[] words, int i) throws ParseException {
+       public AltosGPS(String[] words, int i, int version) throws ParseException {
                AltosParse.word(words[i++], "GPS");
                nsat = AltosParse.parse_int(words[i++]);
                AltosParse.word(words[i++], "sat");
@@ -92,32 +94,44 @@ public class AltosGPS {
                        locked = true;
                        connected = true;
 
-                       ParseGPSTime(words[i], words[i+1]); i += 2;
+                       if (version > 1)
+                               ParseGPSDate(words[i++]);
+                       else
+                               year = month = day = 0;
+                       ParseGPSTime(words[i++]);
                        lat = AltosParse.parse_coord(words[i++]);
                        lon = AltosParse.parse_coord(words[i++]);
-                       alt = AltosParse.parse_int(AltosParse.strip_suffix(words[i++], "m"));
-                       ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)"));
-                       course = AltosParse.parse_int(AltosParse.strip_suffix(words[i++], "°"));
-                       climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)"));
-                       hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)"));
-                       h_error = AltosParse.parse_int(AltosParse.strip_suffix(words[i++], "(herr)"));
-                       v_error = AltosParse.parse_int(AltosParse.strip_suffix(words[i++], "(verr)"));
+                       alt = AltosParse.parse_int(words[i++]);
+                       if (version > 1 || (i < words.length && !words[i].equals("SAT"))) {
+                               ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)"));
+                               course = AltosParse.parse_int(words[i++]);
+                               climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)"));
+                               hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)"));
+                               h_error = AltosParse.parse_int(words[i++]);
+                               v_error = AltosParse.parse_int(words[i++]);
+                       }
                } else {
                        i++;
                }
-               AltosParse.word(words[i++], "SAT");
-               int tracking_channels = 0;
-               if (words[i].equals("not-connected"))
-                       tracking_channels = 0;
-               else
-                       tracking_channels = AltosParse.parse_int(words[i]);
-               i++;
-               cc_gps_sat = new AltosGPS.AltosGPSSat[tracking_channels];
-               for (int chan = 0; chan < tracking_channels; chan++) {
-                       cc_gps_sat[chan] = new AltosGPS.AltosGPSSat();
-                       cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]);
-                       cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]);
-               }
+               if (i < words.length) {
+                       AltosParse.word(words[i++], "SAT");
+                       int tracking_channels = 0;
+                       if (words[i].equals("not-connected"))
+                               tracking_channels = 0;
+                       else
+                               tracking_channels = AltosParse.parse_int(words[i]);
+                       i++;
+                       cc_gps_sat = new AltosGPS.AltosGPSSat[tracking_channels];
+                       for (int chan = 0; chan < tracking_channels; chan++) {
+                               cc_gps_sat[chan] = new AltosGPS.AltosGPSSat();
+                               cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]);
+                               /* Older versions included SiRF status bits */
+                               if (version < 2)
+                                       i++;
+                               cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]);
+                       }
+               } else
+                       cc_gps_sat = new AltosGPS.AltosGPSSat[0];
        }
 
        public void set_latitude(int in_lat) {
@@ -172,6 +186,7 @@ public class AltosGPS {
                nsat = old.nsat;
                locked = old.locked;
                connected = old.connected;
+               date_valid = old.date_valid;
                lat = old.lat;          /* degrees (+N -S) */
                lon = old.lon;          /* degrees (+E -W) */
                alt = old.alt;          /* m */
index 878da03e2b6a7ad2ade1e87fc97a19fa80055315..07c02c16c34c17d665335ff3c657482a289a4a62 100644 (file)
@@ -17,6 +17,8 @@
 
 package altosui;
 
+import altosui.AltosGPS;
+
 import java.lang.Math;
 
 public class AltosGreatCircle {
@@ -28,8 +30,8 @@ public class AltosGreatCircle {
        static final double rad = Math.PI / 180;
        static final double earth_radius = 6371.2 * 1000;       /* in meters */
 
-       AltosGreatCircle (double start_lat, double start_lon,
-                         double end_lat, double end_lon)
+       public AltosGreatCircle (double start_lat, double start_lon,
+                                double end_lat, double end_lon)
        {
                double lat1 = rad * start_lat;
                double lon1 = rad * -start_lon;
@@ -63,4 +65,13 @@ public class AltosGreatCircle {
                distance = d * earth_radius;
                bearing = course * 180/Math.PI;
        }
+
+       public AltosGreatCircle(AltosGPS start, AltosGPS end) {
+               this(start.lat, start.lon, end.lat, end.lon);
+       }
+
+       public AltosGreatCircle() {
+               distance = 0;
+               bearing = 0;
+       }
 }
diff --git a/ao-tools/altosui/AltosHexfile.java b/ao-tools/altosui/AltosHexfile.java
new file mode 100644 (file)
index 0000000..19e35ae
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.lang.*;
+import java.io.*;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.Arrays;
+
+class HexFileInputStream extends PushbackInputStream {
+       public int line;
+
+       public HexFileInputStream(FileInputStream o) {
+               super(new BufferedInputStream(o));
+               line = 1;
+       }
+
+       public int read() throws IOException {
+               int     c = super.read();
+               if (c == '\n')
+                       line++;
+               return c;
+       }
+
+       public void unread(int c) throws IOException {
+               if (c == '\n')
+                       line--;
+               if (c != -1)
+                       super.unread(c);
+       }
+}
+
+class HexRecord implements Comparable {
+       public int      address;
+       public int      type;
+       public byte     checksum;
+       public byte[]   data;
+
+       static final int NORMAL = 0;
+       static final int EOF = 1;
+       static final int EXTENDED_ADDRESS = 2;
+
+       enum read_state {
+               marker,
+               length,
+               address,
+               type,
+               data,
+               checksum,
+               newline,
+               white,
+               done,
+       }
+
+       boolean ishex(int c) {
+               if ('0' <= c && c <= '9')
+                       return true;
+               if ('a' <= c && c <= 'f')
+                       return true;
+               if ('A' <= c && c <= 'F')
+                       return true;
+               return false;
+       }
+
+       boolean isspace(int c) {
+               switch (c) {
+               case ' ':
+               case '\t':
+                       return true;
+               }
+               return false;
+       }
+
+       int fromhex(int c) {
+               if ('0' <= c && c <= '9')
+                       return c - '0';
+               if ('a' <= c && c <= 'f')
+                       return c - 'a' + 10;
+               if ('A' <= c && c <= 'F')
+                       return c - 'A' + 10;
+               return -1;
+       }
+
+       public byte checksum() {
+               byte    got = 0;
+
+               got += data.length;
+               got += (address >> 8) & 0xff;
+               got += (address     ) & 0xff;
+               got += type;
+               for (int i = 0; i < data.length; i++)
+                       got += data[i];
+               return (byte) (-got);
+       }
+
+       public int compareTo(Object other) {
+               HexRecord       o = (HexRecord) other;
+               return address - o.address;
+       }
+
+       public String toString() {
+               return String.format("%04x: %02x (%d)", address, type, data.length);
+       }
+
+       public HexRecord(HexFileInputStream input) throws IOException {
+               read_state      state = read_state.marker;
+               int             nhexbytes = 0;
+               int             hex = 0;
+               int             ndata = 0;
+               byte            got_checksum;
+
+               while (state != read_state.done) {
+                       int c = input.read();
+                       if (c < 0 && state != read_state.white)
+                               throw new IOException(String.format("%d: Unexpected EOF", input.line));
+                       if (c == ' ')
+                               continue;
+                       switch (state) {
+                       case marker:
+                               if (c != ':')
+                                       throw new IOException("Missing ':'");
+                               state = read_state.length;
+                               nhexbytes = 2;
+                               hex = 0;
+                               break;
+                       case length:
+                       case address:
+                       case type:
+                       case data:
+                       case checksum:
+                               if(!ishex(c))
+                                       throw new IOException(String.format("Non-hex char '%c'", c));
+                               hex = hex << 4 | fromhex(c);
+                               --nhexbytes;
+                               if (nhexbytes != 0)
+                                       break;
+
+                               switch (state) {
+                               case length:
+                                       data = new byte[hex];
+                                       state = read_state.address;
+                                       nhexbytes = 4;
+                                       break;
+                               case address:
+                                       address = hex;
+                                       state = read_state.type;
+                                       nhexbytes = 2;
+                                       break;
+                               case type:
+                                       type = hex;
+                                       if (data.length > 0)
+                                               state = read_state.data;
+                                       else
+                                               state = read_state.checksum;
+                                       nhexbytes = 2;
+                                       ndata = 0;
+                                       break;
+                               case data:
+                                       data[ndata] = (byte) hex;
+                                       ndata++;
+                                       nhexbytes = 2;
+                                       if (ndata == data.length)
+                                               state = read_state.checksum;
+                                       break;
+                               case checksum:
+                                       checksum = (byte) hex;
+                                       state = read_state.newline;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               hex = 0;
+                               break;
+                       case newline:
+                               if (c != '\n' && c != '\r')
+                                       throw new IOException("Missing newline");
+                               state = read_state.white;
+                               break;
+                       case white:
+                               if (!isspace(c)) {
+                                       input.unread(c);
+                                       state = read_state.done;
+                               }
+                               break;
+                       case done:
+                               break;
+                       }
+               }
+               got_checksum = checksum();
+               if (got_checksum != checksum)
+                       throw new IOException(String.format("Invalid checksum (read 0x%02x computed 0x%02x)\n",
+                                                           checksum, got_checksum));
+       }
+}
+
+public class AltosHexfile {
+       public int      address;
+       public byte[]   data;
+
+       public byte get_byte(int a) {
+               return data[a - address];
+       }
+
+       public AltosHexfile(FileInputStream file) throws IOException {
+               HexFileInputStream      input = new HexFileInputStream(file);
+               LinkedList<HexRecord>   record_list = new LinkedList<HexRecord>();
+               boolean                 done = false;
+
+               while (!done) {
+                       HexRecord       record = new HexRecord(input);
+
+                       if (record.type == HexRecord.EOF)
+                               done = true;
+                       else
+                               record_list.add(record);
+               }
+               HexRecord[] records  = record_list.toArray(new HexRecord[0]);
+               Arrays.sort(records);
+               if (records.length > 0) {
+                       int     base = records[0].address;
+                       int     bound = records[records.length-1].address +
+                               records[records.length-1].data.length;
+
+                       data = new byte[bound - base];
+                       address = base;
+                       Arrays.fill(data, (byte) 0xff);
+
+                       /* Paint the records into the new array */
+                       for (int i = 0; i < records.length; i++) {
+                               for (int j = 0; j < records[i].data.length; j++)
+                                       data[records[i].address - base + j] = records[i].data[j];
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/ao-tools/altosui/AltosLine.java b/ao-tools/altosui/AltosLine.java
new file mode 100644 (file)
index 0000000..86e9d4c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+public class AltosLine {
+       public String   line;
+
+       public AltosLine() {
+               line = null;
+       }
+
+       public AltosLine(String s) {
+               line = s;
+       }
+}
\ No newline at end of file
index ec868b9c8dd2bcc078cf5b07541a07140e847c56..f876bebae9166c1b205f36ce55f926f3a956d714 100644 (file)
@@ -24,6 +24,7 @@ import java.text.ParseException;
 import java.util.concurrent.LinkedBlockingQueue;
 import altosui.AltosSerial;
 import altosui.AltosFile;
+import altosui.AltosLine;
 
 /*
  * This creates a thread to capture telemetry data and write it to
@@ -31,7 +32,7 @@ import altosui.AltosFile;
  */
 class AltosLog implements Runnable {
 
-       LinkedBlockingQueue<String>     input_queue;
+       LinkedBlockingQueue<AltosLine>  input_queue;
        LinkedBlockingQueue<String>     pending_queue;
        int                             serial;
        int                             flight;
@@ -64,9 +65,11 @@ class AltosLog implements Runnable {
        public void run () {
                try {
                        for (;;) {
-                               String  line = input_queue.take();
+                               AltosLine       line = input_queue.take();
+                               if (line.line == null)
+                                       continue;
                                try {
-                                       AltosTelemetry  telem = new AltosTelemetry(line);
+                                       AltosTelemetry  telem = new AltosTelemetry(line.line);
                                        if (telem.serial != serial || telem.flight != flight || log_file == null) {
                                                close();
                                                serial = telem.serial;
@@ -74,13 +77,14 @@ class AltosLog implements Runnable {
                                                open(telem);
                                        }
                                } catch (ParseException pe) {
+                               } catch (AltosCRCException ce) {
                                }
                                if (log_file != null) {
-                                       log_file.write(line);
+                                       log_file.write(line.line);
                                        log_file.write('\n');
                                        log_file.flush();
                                } else
-                                       pending_queue.put(line);
+                                       pending_queue.put(line.line);
                        }
                } catch (InterruptedException ie) {
                } catch (IOException ie) {
@@ -93,7 +97,7 @@ class AltosLog implements Runnable {
 
        public AltosLog (AltosSerial s) {
                pending_queue = new LinkedBlockingQueue<String> ();
-               input_queue = new LinkedBlockingQueue<String> ();
+               input_queue = new LinkedBlockingQueue<AltosLine> ();
                s.add_monitor(input_queue);
                serial = -1;
                flight = -1;
diff --git a/ao-tools/altosui/AltosLogfileChooser.java b/ao-tools/altosui/AltosLogfileChooser.java
new file mode 100644 (file)
index 0000000..36b51de
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+
+import altosui.AltosPreferences;
+import altosui.AltosReader;
+import altosui.AltosEepromReader;
+import altosui.AltosTelemetryReader;
+
+public class AltosLogfileChooser extends JFileChooser {
+       JFrame  frame;
+       String  filename;
+       File    file;
+
+       public String filename() {
+               return filename;
+       }
+
+       public File file() {
+               return file;
+       }
+
+       public AltosReader runDialog() {
+               int     ret;
+
+               ret = showOpenDialog(frame);
+               if (ret == APPROVE_OPTION) {
+                       file = getSelectedFile();
+                       if (file == null)
+                               return null;
+                       filename = file.getName();
+                       try {
+                               FileInputStream in;
+
+                               in = new FileInputStream(file);
+                               if (filename.endsWith("eeprom"))
+                                       return new AltosEepromReader(in);
+                               else
+                                       return new AltosTelemetryReader(in);
+                       } catch (FileNotFoundException fe) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             filename,
+                                                             "Cannot open file",
+                                                             JOptionPane.ERROR_MESSAGE);
+                       }
+               }
+               return null;
+       }
+
+       public AltosLogfileChooser(JFrame in_frame) {
+               frame = in_frame;
+               setDialogTitle("Select Flight Record File");
+               setFileFilter(new FileNameExtensionFilter("Flight data file",
+                                                         "eeprom",
+                                                         "telem"));
+               setCurrentDirectory(AltosPreferences.logdir());
+       }
+}
\ No newline at end of file
index a60dc69434a67aa454519979041fee7f7a4d47a3..4d82de7816ef2d625d3ef3ec386116c2bae527d7 100644 (file)
@@ -20,10 +20,16 @@ package altosui;
 import java.text.*;
 import java.lang.*;
 
+import altosui.Altos;
+
 public class AltosParse {
+       static boolean isdigit(char c) {
+               return '0' <= c && c <= '9';
+       }
+
        static int parse_int(String v) throws ParseException {
                try {
-                       return Integer.parseInt(v);
+                       return Altos.fromdec(v);
                } catch (NumberFormatException e) {
                        throw new ParseException("error parsing int " + v, 0);
                }
@@ -31,7 +37,7 @@ public class AltosParse {
 
        static int parse_hex(String v) throws ParseException {
                try {
-                       return Integer.parseInt(v, 16);
+                       return Altos.fromhex(v);
                } catch (NumberFormatException e) {
                        throw new ParseException("error parsing hex " + v, 0);
                }
index 81779e2bff5bd75675c4abcdb6422d1658bdbc4e..5be8795dc7e2a774f2dd21e1c25ddf3797f657b6 100644 (file)
@@ -25,4 +25,6 @@ import altosui.AltosRecord;
 
 public class AltosReader {
        public AltosRecord read() throws IOException, ParseException { return null; }
+       public void close() { }
+       public void write_comments(PrintStream out) { }
 }
diff --git a/ao-tools/altosui/AltosRomconfig.java b/ao-tools/altosui/AltosRomconfig.java
new file mode 100644 (file)
index 0000000..22d2dbd
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+import java.io.*;
+import altosui.AltosHexfile;
+
+public class AltosRomconfig {
+       public boolean  valid;
+       public int      version;
+       public int      check;
+       public int      serial_number;
+       public int      radio_calibration;
+
+       static int get_int(byte[] bytes, int start, int len) {
+               int     v = 0;
+               int     o = 0;
+               while (len > 0) {
+                       v = v | ((((int) bytes[start]) & 0xff) << o);
+                       start++;
+                       len--;
+                       o += 8;
+               }
+               return v;
+       }
+
+       static void put_int(int value, byte[] bytes, int start, int len) {
+               while (len > 0) {
+                       bytes[start] = (byte) (value & 0xff);
+                       start++;
+                       len--;
+                       value >>= 8;
+               }
+       }
+
+       static void put_string(String value, byte[] bytes, int start) {
+               for (int i = 0; i < value.length(); i++)
+                       bytes[start + i] = (byte) value.charAt(i);
+       }
+
+       static final int AO_USB_DESC_STRING     = 3;
+
+       static void put_usb_serial(int value, byte[] bytes, int start) {
+               int offset = start + 0xa;
+               int string_num = 0;
+
+               while (offset < bytes.length && bytes[offset] != 0) {
+                       if (bytes[offset + 1] == AO_USB_DESC_STRING) {
+                               ++string_num;
+                               if (string_num == 4)
+                                       break;
+                       }
+                       offset += ((int) bytes[offset]) & 0xff;
+               }
+               if (offset >= bytes.length || bytes[offset] == 0)
+                       return;
+               int len = ((((int) bytes[offset]) & 0xff) - 2) / 2;
+               String fmt = String.format("%%0%dd", len);
+
+               String s = String.format(fmt, value);
+               if (s.length() != len) {
+                       System.out.printf("weird usb length issue %s isn't %d\n",
+                                         s, len);
+                       return;
+               }
+               for (int i = 0; i < len; i++) {
+                       bytes[offset + 2 + i*2] = (byte) s.charAt(i);
+                       bytes[offset + 2 + i*2+1] = 0;
+               }
+       }
+
+       public AltosRomconfig(byte[] bytes, int offset) {
+               version = get_int(bytes, offset + 0, 2);
+               check = get_int(bytes, offset + 2, 2);
+               if (check == (~version & 0xffff)) {
+                       switch (version) {
+                       case 2:
+                       case 1:
+                               serial_number = get_int(bytes, offset + 4, 2);
+                               radio_calibration = get_int(bytes, offset + 6, 4);
+                               valid = true;
+                               break;
+                       }
+               }
+       }
+
+       public AltosRomconfig(AltosHexfile hexfile) {
+               this(hexfile.data, 0xa0 - hexfile.address);
+       }
+
+       public void write(byte[] bytes, int offset) throws IOException {
+               if (!valid)
+                       throw new IOException("rom configuration invalid");
+
+               if (offset < 0 || bytes.length < offset + 10)
+                       throw new IOException("image cannot contain rom config");
+
+               AltosRomconfig existing = new AltosRomconfig(bytes, offset);
+               if (!existing.valid)
+                       throw new IOException("image does not contain existing rom config");
+
+               switch (existing.version) {
+               case 2:
+                       put_usb_serial(serial_number, bytes, offset);
+               case 1:
+                       put_int(serial_number, bytes, offset + 4, 2);
+                       put_int(radio_calibration, bytes, offset + 6, 4);
+                       break;
+               }
+       }
+
+       public void write (AltosHexfile hexfile) throws IOException {
+               write(hexfile.data, 0xa0 - hexfile.address);
+               AltosRomconfig check = new AltosRomconfig(hexfile);
+               if (!check.valid())
+                       throw new IOException("writing new rom config failed\n");
+       }
+
+       public AltosRomconfig(int in_serial_number, int in_radio_calibration) {
+               valid = true;
+               version = 1;
+               check = (~version & 0xffff);
+               serial_number = in_serial_number;
+               radio_calibration = in_radio_calibration;
+       }
+
+       public boolean valid() {
+               return valid && serial_number != 0;
+       }
+
+       public AltosRomconfig() {
+               valid = false;
+       }
+}
diff --git a/ao-tools/altosui/AltosRomconfigUI.java b/ao-tools/altosui/AltosRomconfigUI.java
new file mode 100644 (file)
index 0000000..2134975
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+
+import altosui.AltosRomconfig;
+
+public class AltosRomconfigUI
+       extends JDialog
+       implements ActionListener
+{
+       Container       pane;
+       Box             box;
+       JLabel          serial_label;
+       JLabel          radio_calibration_label;
+
+       JFrame          owner;
+       JTextField      serial_value;
+       JTextField      radio_calibration_value;
+
+       JButton         ok;
+       JButton         cancel;
+
+       /* Build the UI using a grid bag */
+       public AltosRomconfigUI(JFrame in_owner) {
+               super (in_owner, "Configure TeleMetrum Rom Values", true);
+
+               owner = in_owner;
+               GridBagConstraints c;
+
+               Insets il = new Insets(4,4,4,4);
+               Insets ir = new Insets(4,4,4,4);
+
+               pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               /* Serial */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 0;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               serial_label = new JLabel("Serial:");
+               pane.add(serial_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 3; c.gridy = 0;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               serial_value = new JTextField("0");
+               pane.add(serial_value, c);
+
+               /* Radio calibration value */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 1;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               radio_calibration_label = new JLabel("Radio Calibration:");
+               pane.add(radio_calibration_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 3; c.gridy = 1;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               radio_calibration_value = new JTextField("1186611");
+               pane.add(radio_calibration_value, c);
+
+               /* Buttons */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 2;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = il;
+               ok = new JButton("OK");
+               pane.add(ok, c);
+               ok.addActionListener(this);
+               ok.setActionCommand("ok");
+
+               c = new GridBagConstraints();
+               c.gridx = 3; c.gridy = 2;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = il;
+               cancel = new JButton("Cancel");
+               pane.add(cancel, c);
+               cancel.addActionListener(this);
+               cancel.setActionCommand("cancel");
+
+               pack();
+               setLocationRelativeTo(owner);
+       }
+
+       boolean selected;
+
+       /* Listen for events from our buttons */
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+
+               if (cmd.equals("ok")) {
+                       AltosRomconfig  romconfig = romconfig();
+                       if (romconfig == null || !romconfig.valid()) {
+                               JOptionPane.showMessageDialog(this,
+                                                             "Invalid serial number or radio calibration value",
+                                                             "Invalid rom configuration",
+                                                             JOptionPane.ERROR_MESSAGE);
+                               return;
+                       }
+                       selected = true;
+               }
+               setVisible(false);
+       }
+
+       int serial() {
+               return Integer.parseInt(serial_value.getText());
+       }
+
+       void set_serial(int serial) {
+               serial_value.setText(String.format("%d", serial));
+       }
+
+       int radio_calibration() {
+               return Integer.parseInt(radio_calibration_value.getText());
+       }
+
+       void set_radio_calibration(int calibration) {
+               radio_calibration_value.setText(String.format("%d", calibration));
+       }
+
+       public void set(AltosRomconfig config) {
+               if (config != null && config.valid()) {
+                       set_serial(config.serial_number);
+                       set_radio_calibration(config.radio_calibration);
+               }
+       }
+
+       AltosRomconfig romconfig() {
+               try {
+                       return new AltosRomconfig(serial(), radio_calibration());
+               } catch (NumberFormatException ne) {
+                       return null;
+               }
+       }
+
+       public AltosRomconfig showDialog() {
+               setVisible(true);
+               if (selected)
+                       return romconfig();
+               return null;
+       }
+}
index ba00b55e98d3b4674974e3dab4fa2d7fa323f588..a1fc4371c8a805b2175f6175c8111d4dcd567a3f 100644 (file)
@@ -27,10 +27,12 @@ import java.util.concurrent.LinkedBlockingQueue;
 import java.util.LinkedList;
 import java.util.Iterator;
 import altosui.AltosSerialMonitor;
+import altosui.AltosLine;
 import libaltosJNI.libaltos;
 import libaltosJNI.altos_device;
 import libaltosJNI.SWIGTYPE_p_altos_file;
 import libaltosJNI.SWIGTYPE_p_altos_list;
+import libaltosJNI.libaltosConstants;
 
 /*
  * This class reads from the serial port and places each received
@@ -41,10 +43,13 @@ import libaltosJNI.SWIGTYPE_p_altos_list;
 public class AltosSerial implements Runnable {
 
        SWIGTYPE_p_altos_file altos;
-       LinkedList<LinkedBlockingQueue<String>> monitors;
-       LinkedBlockingQueue<String> reply_queue;
+       LinkedList<LinkedBlockingQueue<AltosLine>> monitors;
+       LinkedBlockingQueue<AltosLine> reply_queue;
        Thread input_thread;
        String line;
+       byte[] line_bytes;
+       int line_count;
+       boolean monitor_mode;
 
        public void run () {
                int c;
@@ -54,24 +59,50 @@ public class AltosSerial implements Runnable {
                                c = libaltos.altos_getchar(altos, 0);
                                if (Thread.interrupted())
                                        break;
-                               if (c == -1)
+                               if (c == libaltosConstants.LIBALTOS_ERROR) {
+                                       for (int e = 0; e < monitors.size(); e++) {
+                                               LinkedBlockingQueue<AltosLine> q = monitors.get(e);
+                                               q.put(new AltosLine());
+                                       }
+                                       reply_queue.put (new AltosLine());
+                                       break;
+                               }
+                               if (c == libaltosConstants.LIBALTOS_TIMEOUT)
                                        continue;
                                if (c == '\r')
                                        continue;
                                synchronized(this) {
                                        if (c == '\n') {
-                                               if (line != "") {
-                                                       if (line.startsWith("VERSION")) {
+                                               if (line_count != 0) {
+                                                       try {
+                                                               line = new String(line_bytes, 0, line_count, "UTF-8");
+                                                       } catch (UnsupportedEncodingException ue) {
+                                                               line = "";
+                                                               for (int i = 0; i < line_count; i++)
+                                                                       line = line + line_bytes[i];
+                                                       }
+                                                       if (line.startsWith("VERSION") || line.startsWith("CRC")) {
                                                                for (int e = 0; e < monitors.size(); e++) {
-                                                                       LinkedBlockingQueue<String> q = monitors.get(e);
-                                                                       q.put(line);
+                                                                       LinkedBlockingQueue<AltosLine> q = monitors.get(e);
+                                                                       q.put(new AltosLine (line));
                                                                }
-                                                       } else
-                                                               reply_queue.put(line);
+                                                       } else {
+//                                                             System.out.printf("GOT: %s\n", line);
+                                                               reply_queue.put(new AltosLine (line));
+                                                       }
+                                                       line_count = 0;
                                                        line = "";
                                                }
                                        } else {
-                                               line = line + (char) c;
+                                               if (line_bytes == null) {
+                                                       line_bytes = new byte[256];
+                                               } else if (line_count == line_bytes.length) {
+                                                       byte[] new_line_bytes = new byte[line_count * 2];
+                                                       System.arraycopy(line_bytes, 0, new_line_bytes, 0, line_count);
+                                                       line_bytes = new_line_bytes;
+                                               }
+                                               line_bytes[line_count] = (byte) c;
+                                               line_count++;
                                        }
                                }
                        }
@@ -79,24 +110,40 @@ public class AltosSerial implements Runnable {
                }
        }
 
+       public void flush_output() {
+               if (altos != null)
+                       libaltos.altos_flush(altos);
+       }
+
+       public void flush_input() {
+               flush_output();
+               try {
+                       Thread.sleep(200);
+               } catch (InterruptedException ie) {
+               }
+               synchronized(this) {
+                       if (!"VERSION".startsWith(line) &&
+                           !line.startsWith("VERSION"))
+                               line = "";
+                       reply_queue.clear();
+               }
+       }
+
        public String get_reply() throws InterruptedException {
-               return reply_queue.take();
+               flush_output();
+               AltosLine line = reply_queue.take();
+               return line.line;
        }
 
-       public void add_monitor(LinkedBlockingQueue<String> q) {
+       public void add_monitor(LinkedBlockingQueue<AltosLine> q) {
+               set_monitor(true);
                monitors.add(q);
        }
 
-       public void remove_monitor(LinkedBlockingQueue<String> q) {
+       public void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
                monitors.remove(q);
-       }
-
-       public void flush () {
-               synchronized(this) {
-                       if (!"VERSION".startsWith(line) && !line.startsWith("VERSION"))
-                               line = "";
-                       reply_queue.clear();
-               }
+               if (monitors.isEmpty())
+                       set_monitor(false);
        }
 
        public boolean opened() {
@@ -104,8 +151,9 @@ public class AltosSerial implements Runnable {
        }
 
        public void close() {
-               if (altos != null)
+               if (altos != null) {
                        libaltos.altos_close(altos);
+               }
                if (input_thread != null) {
                        try {
                                input_thread.interrupt();
@@ -126,6 +174,7 @@ public class AltosSerial implements Runnable {
        }
 
        public void print(String data) {
+//             System.out.printf("\"%s\" ", data);
                for (int i = 0; i < data.length(); i++)
                        putc(data.charAt(i));
        }
@@ -141,29 +190,45 @@ public class AltosSerial implements Runnable {
                        throw new FileNotFoundException(device.getPath());
                input_thread = new Thread(this);
                input_thread.start();
-               print("\nE 0\n");
-               try {
-                       Thread.sleep(200);
-               } catch (InterruptedException e) {
-               }
-               flush();
+               print("~\nE 0\n");
+               flush_output();
+               set_monitor(monitor_mode);
        }
 
        public void set_channel(int channel) {
-               if (altos != null)
-                       printf("m 0\nc r %d\nm 1\n", channel);
+               if (altos != null) {
+                       if (monitor_mode)
+                               printf("m 0\nc r %d\nm 1\n", channel);
+                       else
+                               printf("c r %d\n", channel);
+                       flush_output();
+               }
+       }
+
+       void set_monitor(boolean monitor) {
+               monitor_mode = monitor;
+               if (altos != null) {
+                       if (monitor)
+                               printf("m 1\n");
+                       else
+                               printf("m 0\n");
+                       flush_output();
+               }
        }
 
        public void set_callsign(String callsign) {
-               if (altos != null)
+               if (altos != null) {
                        printf ("c c %s\n", callsign);
+                       flush_output();
+               }
        }
 
        public AltosSerial() {
                altos = null;
                input_thread = null;
                line = "";
-               monitors = new LinkedList<LinkedBlockingQueue<String>> ();
-               reply_queue = new LinkedBlockingQueue<String> ();
+               monitor_mode = false;
+               monitors = new LinkedList<LinkedBlockingQueue<AltosLine>> ();
+               reply_queue = new LinkedBlockingQueue<AltosLine> ();
        }
 }
index deeb4c771dcec9fb825d918bea922f75c3ff4024..3ef00f35d7d87375cf4967553f5e28c3bdd6edd6 100644 (file)
@@ -64,6 +64,8 @@ public class AltosState {
        boolean gps_ready;
 
        AltosGreatCircle from_pad;
+       double  elevation;      /* from pad */
+       double  range;          /* total distance */
 
        double  gps_height;
 
@@ -124,12 +126,7 @@ public class AltosState {
                }
 
                if (state == Altos.ao_flight_pad) {
-                       if (data.gps == null)
-                               System.out.printf("on pad, gps null\n");
-                       else
-                               System.out.printf ("on pad gps lat %f lon %f locked %d nsat %d\n",
-                                                  data.gps.lat, data.gps.lon, data.gps.locked ? 1 : 0, data.gps.nsat);
-                       if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) {
+                       if (data.gps != null && data.gps.locked) {
                                npad++;
                                if (npad > 1) {
                                        /* filter pad position */
@@ -166,11 +163,18 @@ public class AltosState {
                if (data.gps != null) {
                        if (gps == null || !gps.locked || data.gps.locked)
                                gps = data.gps;
-                       if (npad > 0 && gps.locked)
+                       if (npad > 0 && gps.locked) {
                                from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon);
+                       }
                }
+               elevation = 0;
+               range = -1;
                if (npad > 0) {
                        gps_height = gps.alt - pad_alt;
+                       if (from_pad != null) {
+                               elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI;
+                               range = Math.sqrt(height * height + from_pad.distance * from_pad.distance);
+                       }
                } else {
                        gps_height = 0;
                }
index af29b8c04ef5e940e25dd1ca3e796e9dc895fbeb..be22dac60aa308c8e170f960b3718f79c6088bdd 100644 (file)
@@ -23,6 +23,7 @@ import java.util.HashMap;
 import altosui.AltosConvert;
 import altosui.AltosRecord;
 import altosui.AltosGPS;
+import altosui.AltosCRCException;
 
 /*
  * Telemetry data contents
@@ -53,12 +54,22 @@ import altosui.AltosGPS;
  */
 
 public class AltosTelemetry extends AltosRecord {
-       public AltosTelemetry(String line) throws ParseException {
+       public AltosTelemetry(String line) throws ParseException, AltosCRCException {
                String[] words = line.split("\\s+");
                int     i = 0;
 
-               AltosParse.word (words[i++], "VERSION");
-               version = AltosParse.parse_int(words[i++]);
+               if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
+                       i += 2;
+                       AltosParse.word(words[i++], "RSSI");
+                       rssi = AltosParse.parse_int(words[i++]);
+                       throw new AltosCRCException(rssi);
+               }
+               if (words[i].equals("CALL")) {
+                       version = 0;
+               } else {
+                       AltosParse.word (words[i++], "VERSION");
+                       version = AltosParse.parse_int(words[i++]);
+               }
 
                AltosParse.word (words[i++], "CALL");
                callsign = words[i++];
@@ -66,12 +77,19 @@ public class AltosTelemetry extends AltosRecord {
                AltosParse.word (words[i++], "SERIAL");
                serial = AltosParse.parse_int(words[i++]);
 
-               AltosParse.word (words[i++], "FLIGHT");
-               flight = AltosParse.parse_int(words[i++]);
+               if (version >= 2) {
+                       AltosParse.word (words[i++], "FLIGHT");
+                       flight = AltosParse.parse_int(words[i++]);
+               } else
+                       flight = 0;
 
                AltosParse.word(words[i++], "RSSI");
                rssi = AltosParse.parse_int(words[i++]);
 
+               /* Older telemetry data had mis-computed RSSI value */
+               if (version <= 2)
+                       rssi = (rssi + 74) / 2 - 74;
+
                AltosParse.word(words[i++], "STATUS");
                status = AltosParse.parse_hex(words[i++]);
 
@@ -113,12 +131,17 @@ public class AltosTelemetry extends AltosRecord {
                AltosParse.word(words[i++], "gp:");
                ground_pres = AltosParse.parse_int(words[i++]);
 
-               AltosParse.word(words[i++], "a+:");
-               accel_plus_g = AltosParse.parse_int(words[i++]);
+               if (version >= 1) {
+                       AltosParse.word(words[i++], "a+:");
+                       accel_plus_g = AltosParse.parse_int(words[i++]);
 
-               AltosParse.word(words[i++], "a-:");
-               accel_minus_g = AltosParse.parse_int(words[i++]);
+                       AltosParse.word(words[i++], "a-:");
+                       accel_minus_g = AltosParse.parse_int(words[i++]);
+               } else {
+                       accel_plus_g = ground_accel;
+                       accel_minus_g = ground_accel + 530;
+               }
 
-               gps = new AltosGPS(words, i);
+               gps = new AltosGPS(words, i, version);
        }
 }
index f1f6788c0afbc17973574a0b98c5459647d153a8..fdedbde279345499e1ac926104478ade2106fa24 100644 (file)
@@ -47,20 +47,27 @@ public class AltosTelemetryReader extends AltosReader {
                try {
                        for (;;) {
                                String line = AltosRecord.gets(input);
-                               if (line == null)
+                               if (line == null) {
                                        break;
-                               AltosTelemetry record = new AltosTelemetry(line);
-                               if (record == null)
-                                       break;
-                               if (!saw_boost && record.state >= Altos.ao_flight_boost)
-                               {
-                                       saw_boost = true;
-                                       boost_tick = record.tick;
                                }
-                               records.add(record);
+                               try {
+                                       AltosTelemetry record = new AltosTelemetry(line);
+                                       if (record == null)
+                                               break;
+                                       if (!saw_boost && record.state >= Altos.ao_flight_boost)
+                                       {
+                                               saw_boost = true;
+                                               boost_tick = record.tick;
+                                       }
+                                       records.add(record);
+                               } catch (ParseException pe) {
+                                       System.out.printf("parse exception %s\n", pe.getMessage());
+                               } catch (AltosCRCException ce) {
+                                       System.out.printf("crc error\n");
+                               }
                        }
                } catch (IOException io) {
-               } catch (ParseException pe) {
+                       System.out.printf("io exception\n");
                }
                record_iterator = records.iterator();
                try {
index 49d1f11a67f23e04c52d69ea768d9d0a9aff8393..3aaeb888380c5400caed334476238da980e166a6 100644 (file)
@@ -41,6 +41,10 @@ import altosui.AltosVoice;
 import altosui.AltosFlightStatusTableModel;
 import altosui.AltosFlightInfoTableModel;
 import altosui.AltosChannelMenu;
+import altosui.AltosFlashUI;
+import altosui.AltosLogfileChooser;
+import altosui.AltosCSVUI;
+import altosui.AltosLine;
 
 import libaltosJNI.*;
 
@@ -71,6 +75,10 @@ public class AltosUI extends JFrame {
                String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
                Object[][] statusData = { { "0", "pad", "-50", "0" } };
 
+               java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg");
+               if (imgURL != null)
+                       setIconImage(new ImageIcon(imgURL).getImage());
+
                AltosPreferences.init(this);
 
                vbox = Box.createVerticalBox();
@@ -165,21 +173,19 @@ public class AltosUI extends JFrame {
                        flightInfoModel[i].finish();
        }
 
-       public void show(AltosState state) {
+       public void show(AltosState state, int crc_errors) {
+               if (state == null)
+                       return;
                flightStatusModel.set(state);
 
                info_reset();
-               if (state.gps_ready)
-                       info_add_row(0, "Ground state", "%s", "ready");
-               else
-                       info_add_row(0, "Ground state", "wait (%d)",
-                                    state.gps_waiting);
                info_add_row(0, "Rocket state", "%s", state.data.state());
                info_add_row(0, "Callsign", "%s", state.data.callsign);
                info_add_row(0, "Rocket serial", "%6d", state.data.serial);
                info_add_row(0, "Rocket flight", "%6d", state.data.flight);
 
                info_add_row(0, "RSSI", "%6d    dBm", state.data.rssi);
+               info_add_row(0, "CRC Errors", "%6d", crc_errors);
                info_add_row(0, "Height", "%6.0f    m", state.height);
                info_add_row(0, "Max height", "%6.0f    m", state.max_height);
                info_add_row(0, "Acceleration", "%8.1f  m/s²", state.acceleration);
@@ -194,6 +200,11 @@ public class AltosUI extends JFrame {
                if (state.gps == null) {
                        info_add_row(1, "GPS", "not available");
                } else {
+                       if (state.gps_ready)
+                               info_add_row(1, "GPS state", "%s", "ready");
+                       else
+                               info_add_row(1, "GPS state", "wait (%d)",
+                                            state.gps_waiting);
                        if (state.data.gps.locked)
                                info_add_row(1, "GPS", "   locked");
                        else if (state.data.gps.connected)
@@ -220,11 +231,19 @@ public class AltosUI extends JFrame {
 
                        if (state.npad > 0) {
                                if (state.from_pad != null) {
-                                       info_add_row(1, "Distance from pad", "%6.0f m", state.from_pad.distance);
-                                       info_add_row(1, "Direction from pad", "%6.0f°", state.from_pad.bearing);
+                                       info_add_row(1, "Distance from pad", "%6d m",
+                                                    (int) (state.from_pad.distance + 0.5));
+                                       info_add_row(1, "Direction from pad", "%6d°",
+                                                    (int) (state.from_pad.bearing + 0.5));
+                                       info_add_row(1, "Elevation from pad", "%6d°",
+                                                    (int) (state.elevation + 0.5));
+                                       info_add_row(1, "Range from pad", "%6d m",
+                                                    (int) (state.range + 0.5));
                                } else {
                                        info_add_row(1, "Distance from pad", "unknown");
                                        info_add_row(1, "Direction from pad", "unknown");
+                                       info_add_row(1, "Elevation from pad", "unknown");
+                                       info_add_row(1, "Range from pad", "unknown");
                                }
                                info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S');
                                info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W');
@@ -258,10 +277,13 @@ public class AltosUI extends JFrame {
 
        class IdleThread extends Thread {
 
+               boolean started;
                private AltosState state;
                int     reported_landing;
+               int     report_interval;
+               long    report_time;
 
-               public void report(boolean last) {
+               public synchronized void report(boolean last) {
                        if (state == null)
                                return;
 
@@ -275,7 +297,16 @@ public class AltosUI extends JFrame {
                        }
 
                        /* If the rocket isn't on the pad, then report height */
-                       if (state.state > Altos.ao_flight_pad) {
+                       if (Altos.ao_flight_drogue <= state.state &&
+                           state.state < Altos.ao_flight_landed &&
+                           state.range >= 0)
+                       {
+                               voice.speak("Height %d, bearing %d, elevation %d, range %d.\n",
+                                           (int) (state.height + 0.5),
+                                           (int) (state.from_pad.bearing + 0.5),
+                                           (int) (state.elevation + 0.5),
+                                           (int) (state.range + 0.5));
+                       } else if (state.state > Altos.ao_flight_pad) {
                                voice.speak("%d meters", (int) (state.height + 0.5));
                        } else {
                                reported_landing = 0;
@@ -285,7 +316,7 @@ public class AltosUI extends JFrame {
                         * either we've got a landed report or we haven't heard from it in
                         * a long time
                         */
-                       if (!state.ascent &&
+                       if (state.state >= Altos.ao_flight_drogue &&
                            (last ||
                             System.currentTimeMillis() - state.report_time >= 15000 ||
                             state.state == Altos.ao_flight_landed))
@@ -295,51 +326,95 @@ public class AltosUI extends JFrame {
                                else
                                        voice.speak("rocket may have crashed");
                                if (state.from_pad != null)
-                                       voice.speak("bearing %d degrees, range %d meters",
+                                       voice.speak("Bearing %d degrees, range %d meters.",
                                                    (int) (state.from_pad.bearing + 0.5),
                                                    (int) (state.from_pad.distance + 0.5));
                                ++reported_landing;
                        }
                }
 
+               long now () {
+                       return System.currentTimeMillis();
+               }
+
+               void set_report_time() {
+                       report_time = now() + report_interval;
+               }
+
                public void run () {
 
                        reported_landing = 0;
                        state = null;
+                       report_interval = 10000;
                        try {
                                for (;;) {
-                                       Thread.sleep(10000);
+                                       set_report_time();
+                                       for (;;) {
+                                               voice.drain();
+                                               synchronized (this) {
+                                                       long    sleep_time = report_time - now();
+                                                       if (sleep_time <= 0)
+                                                               break;
+                                                       wait(sleep_time);
+                                               }
+                                       }
                                        report(false);
                                }
                        } catch (InterruptedException ie) {
+                               try {
+                                       voice.drain();
+                               } catch (InterruptedException iie) { }
                        }
                }
 
-               public void notice(AltosState new_state) {
+               public synchronized void notice(AltosState new_state, boolean spoken) {
+                       AltosState old_state = state;
                        state = new_state;
+                       if (!started && state.state > Altos.ao_flight_pad) {
+                               started = true;
+                               start();
+                       }
+
+                       if (state.state < Altos.ao_flight_drogue)
+                               report_interval = 10000;
+                       else
+                               report_interval = 20000;
+                       if (old_state != null && old_state.state != state.state) {
+                               report_time = now();
+                               this.notify();
+                       } else if (spoken)
+                               set_report_time();
                }
        }
 
-       private void tell(AltosState state, AltosState old_state) {
+       private boolean tell(AltosState state, AltosState old_state) {
+               boolean ret = false;
                if (old_state == null || old_state.state != state.state) {
                        voice.speak(state.data.state());
                        if ((old_state == null || old_state.state <= Altos.ao_flight_boost) &&
                            state.state > Altos.ao_flight_boost) {
                                voice.speak("max speed: %d meters per second.",
                                            (int) (state.max_speed + 0.5));
+                               ret = true;
                        } else if ((old_state == null || old_state.state < Altos.ao_flight_drogue) &&
                                   state.state >= Altos.ao_flight_drogue) {
                                voice.speak("max height: %d meters.",
                                            (int) (state.max_height + 0.5));
+                               ret = true;
                        }
                }
                if (old_state == null || old_state.gps_ready != state.gps_ready) {
-                       if (state.gps_ready)
+                       if (state.gps_ready) {
                                voice.speak("GPS ready");
-                       else if (old_state != null)
+                               ret = true;
+                       }
+                       else if (old_state != null) {
                                voice.speak("GPS lost");
+                               ret = true;
+                       }
                }
                old_state = state;
+               return ret;
        }
 
        class DisplayThread extends Thread {
@@ -347,22 +422,27 @@ public class AltosUI extends JFrame {
 
                String          name;
 
-               AltosRecord read() throws InterruptedException, ParseException { return null; }
+               int             crc_errors;
+
+               void init() { }
 
-               void close() { }
+               AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; }
+
+               void close(boolean interrupted) { }
 
                void update(AltosState state) throws InterruptedException { }
 
                public void run() {
+                       boolean         interrupted = false;
                        String          line;
                        AltosState      state = null;
                        AltosState      old_state = null;
+                       boolean         told;
 
                        idle_thread = new IdleThread();
 
                        info_reset();
                        info_finish();
-                       idle_thread.start();
                        try {
                                for (;;) {
                                        try {
@@ -372,17 +452,29 @@ public class AltosUI extends JFrame {
                                                old_state = state;
                                                state = new AltosState(record, state);
                                                update(state);
-                                               show(state);
-                                               tell(state, old_state);
-                                               idle_thread.notice(state);
+                                               show(state, crc_errors);
+                                               told = tell(state, old_state);
+                                               idle_thread.notice(state, told);
                                        } catch (ParseException pp) {
                                                System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage());
+                                       } catch (AltosCRCException ce) {
+                                               ++crc_errors;
+                                               show(state, crc_errors);
                                        }
                                }
                        } catch (InterruptedException ee) {
+                               interrupted = true;
+                       } catch (IOException ie) {
+                               JOptionPane.showMessageDialog(AltosUI.this,
+                                                             String.format("Error reading from \"%s\"", name),
+                                                             "Telemetry Read Error",
+                                                             JOptionPane.ERROR_MESSAGE);
                        } finally {
-                               close();
+                               close(interrupted);
                                idle_thread.interrupt();
+                               try {
+                                       idle_thread.join();
+                               } catch (InterruptedException ie) {}
                        }
                }
 
@@ -394,22 +486,25 @@ public class AltosUI extends JFrame {
 
        class DeviceThread extends DisplayThread {
                AltosSerial     serial;
-               LinkedBlockingQueue<String> telem;
+               LinkedBlockingQueue<AltosLine> telem;
 
-               AltosRecord read() throws InterruptedException, ParseException {
-                       return new AltosTelemetry(telem.take());
+               AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException {
+                       AltosLine l = telem.take();
+                       if (l.line == null)
+                               throw new IOException("IO error");
+                       return new AltosTelemetry(l.line);
                }
 
-               void close() {
+               void close(boolean interrupted) {
                        serial.close();
                        serial.remove_monitor(telem);
                }
 
-               public DeviceThread(AltosSerial s) {
+               public DeviceThread(AltosSerial s, String in_name) {
                        serial = s;
-                       telem = new LinkedBlockingQueue<String>();
+                       telem = new LinkedBlockingQueue<AltosLine>();
                        serial.add_monitor(telem);
-                       name = "telemetry";
+                       name = in_name;
                }
        }
 
@@ -418,8 +513,9 @@ public class AltosUI extends JFrame {
 
                if (device != null) {
                        try {
+                               stop_display();
                                serial_line.open(device);
-                               DeviceThread thread = new DeviceThread(serial_line);
+                               DeviceThread thread = new DeviceThread(serial_line, device.getPath());
                                serial_line.set_channel(AltosPreferences.channel());
                                serial_line.set_callsign(AltosPreferences.callsign());
                                run_display(thread);
@@ -457,6 +553,11 @@ public class AltosUI extends JFrame {
        void ConfigureTeleMetrum() {
                new AltosConfig(AltosUI.this);
        }
+
+       void FlashImage() {
+               new AltosFlashUI(AltosUI.this);
+       }
+
        /*
         * Open an existing telemetry file and replay it in realtime
         */
@@ -478,8 +579,9 @@ public class AltosUI extends JFrame {
                        return null;
                }
 
-               public void close () {
-                       report();
+               public void close (boolean interrupted) {
+                       if (!interrupted)
+                               report();
                }
 
                public ReplayThread(AltosReader in_reader, String in_name) {
@@ -508,8 +610,12 @@ public class AltosUI extends JFrame {
        Thread          display_thread;
 
        private void stop_display() {
-               if (display_thread != null && display_thread.isAlive())
+               if (display_thread != null && display_thread.isAlive()) {
                        display_thread.interrupt();
+                       try {
+                               display_thread.join();
+                       } catch (InterruptedException ie) {}
+               }
                display_thread = null;
        }
 
@@ -523,33 +629,12 @@ public class AltosUI extends JFrame {
         * Replay a flight from telemetry data
         */
        private void Replay() {
-               JFileChooser    logfile_chooser = new JFileChooser();
-
-               logfile_chooser.setDialogTitle("Select Flight Record File");
-               logfile_chooser.setFileFilter(new FileNameExtensionFilter("Flight data file", "eeprom", "telem"));
-               logfile_chooser.setCurrentDirectory(AltosPreferences.logdir());
-               int returnVal = logfile_chooser.showOpenDialog(AltosUI.this);
-
-               if (returnVal == JFileChooser.APPROVE_OPTION) {
-                       File file = logfile_chooser.getSelectedFile();
-                       if (file == null)
-                               System.out.println("No file selected?");
-                       String  filename = file.getName();
-                       try {
-                               FileInputStream replay = new FileInputStream(file);
-                               DisplayThread   thread;
-                               if (filename.endsWith("eeprom"))
-                                   thread = new ReplayEepromThread(replay, filename);
-                               else
-                                   thread = new ReplayTelemetryThread(replay, filename);
-                               run_display(thread);
-                       } catch (FileNotFoundException ee) {
-                               JOptionPane.showMessageDialog(AltosUI.this,
-                                                             filename,
-                                                             "Cannot open telemetry file",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       }
-               }
+               AltosLogfileChooser chooser = new AltosLogfileChooser(
+                       AltosUI.this);
+               AltosReader reader = chooser.runDialog();
+               if (reader != null)
+                       run_display(new ReplayThread(reader,
+                                                    chooser.filename()));
        }
 
        /* Connect to TeleMetrum, either directly or through
@@ -559,6 +644,14 @@ public class AltosUI extends JFrame {
                new AltosEepromDownload(AltosUI.this);
        }
 
+       /* Load a flight log file and write out a CSV file containing
+        * all of the data in standard units
+        */
+
+       private void ExportData() {
+               new AltosCSVUI(AltosUI.this);
+       }
+
        /* Create the AltosUI menus
         */
        private void createMenu() {
@@ -589,6 +682,22 @@ public class AltosUI extends JFrame {
                                });
                        menu.add(item);
 
+                       item = new JMenuItem("Flash Image",KeyEvent.VK_F);
+                       item.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               FlashImage();
+                                       }
+                               });
+                       menu.add(item);
+
+                       item = new JMenuItem("Export Data",KeyEvent.VK_F);
+                       item.addActionListener(new ActionListener() {
+                                       public void actionPerformed(ActionEvent e) {
+                                               ExportData();
+                                       }
+                               });
+                       menu.add(item);
+
                        item = new JMenuItem("Quit",KeyEvent.VK_Q);
                        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
                                                                   ActionEvent.CTRL_MASK));
@@ -708,8 +817,67 @@ public class AltosUI extends JFrame {
                this.setJMenuBar(menubar);
 
        }
+
+       static String replace_extension(String input, String extension) {
+               int dot = input.lastIndexOf(".");
+               if (dot > 0)
+                       input = input.substring(0,dot);
+               return input.concat(extension);
+       }
+
+       static AltosReader open_logfile(String filename) {
+               File file = new File (filename);
+               try {
+                       FileInputStream in;
+
+                       in = new FileInputStream(file);
+                       if (filename.endsWith("eeprom"))
+                               return new AltosEepromReader(in);
+                       else
+                               return new AltosTelemetryReader(in);
+               } catch (FileNotFoundException fe) {
+                       System.out.printf("Cannot open '%s'\n", filename);
+                       return null;
+               }
+       }
+
+       static AltosCSV open_csv(String filename) {
+               File file = new File (filename);
+               try {
+                       return new AltosCSV(file);
+               } catch (FileNotFoundException fe) {
+                       System.out.printf("Cannot open '%s'\n", filename);
+                       return null;
+               }
+       }
+
+       static void process_file(String input) {
+               String output = replace_extension(input,".csv");
+               if (input.equals(output)) {
+                       System.out.printf("Not processing '%s'\n", input);
+                       return;
+               }
+               System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
+               AltosReader reader = open_logfile(input);
+               if (reader == null)
+                       return;
+               AltosCSV writer = open_csv(output);
+               if (writer == null)
+                       return;
+               writer.write(reader);
+               reader.close();
+               writer.close();
+       }
+
        public static void main(final String[] args) {
-               AltosUI altosui = new AltosUI();
-               altosui.setVisible(true);
+
+               /* Handle batch-mode */
+               if (args.length > 0) {
+                       for (int i = 0; i < args.length; i++)
+                               process_file(args[i]);
+               } else {
+                       AltosUI altosui = new AltosUI();
+                       altosui.setVisible(true);
+               }
        }
 }
\ No newline at end of file
index ebe9d5a81c0d5c8b1cab4084db70925dc59049b8..ac13ee14e81176c69d46587392340c3a8018ba62 100644 (file)
@@ -27,6 +27,7 @@ public class AltosVoice implements Runnable {
        Voice                           voice;
        LinkedBlockingQueue<String>     phrases;
        Thread                          thread;
+       boolean                         busy;
 
        final static String voice_name = "kevin16";
 
@@ -35,15 +36,30 @@ public class AltosVoice implements Runnable {
                        for (;;) {
                                String s = phrases.take();
                                voice.speak(s);
+                               synchronized(this) {
+                                       if (phrases.isEmpty()) {
+                                               busy = false;
+                                               notifyAll();
+                                       }
+                               }
                        }
                } catch (InterruptedException e) {
                }
        }
 
+       public synchronized void drain() throws InterruptedException {
+               while (busy)
+                       wait();
+       }
+
        public void speak_always(String s) {
                try {
-                       if (voice != null)
-                               phrases.put(s);
+                       if (voice != null) {
+                               synchronized(this) {
+                                       busy = true;
+                                       phrases.put(s);
+                               }
+                       }
                } catch (InterruptedException e) {
                }
        }
@@ -58,6 +74,7 @@ public class AltosVoice implements Runnable {
        }
 
        public AltosVoice () {
+               busy = false;
                voice_manager = VoiceManager.getInstance();
                voice = voice_manager.getVoice(voice_name);
                if (voice != null) {
diff --git a/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/Example.nsi b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/Example.nsi
new file mode 100644 (file)
index 0000000..3ed821e
--- /dev/null
@@ -0,0 +1,84 @@
+#\r
+# InstDrv Example, (c) 2003 Jan Kiszka (Jan Kiszka@web.de)\r
+#\r
+\r
+Name "InstDrv.dll test"\r
+\r
+OutFile "InstDrv-Test.exe"\r
+\r
+ShowInstDetails show\r
+\r
+ComponentText "InstDrv Plugin Usage Example"\r
+\r
+Page components\r
+Page instfiles\r
+\r
+Section "Install a Driver" InstDriver\r
+    InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k"\r
+    Pop $0\r
+    DetailPrint "InitDriverSetup: $0"\r
+\r
+    InstDrv::DeleteOemInfFiles /NOUNLOAD\r
+    Pop $0\r
+    DetailPrint "DeleteOemInfFiles: $0"\r
+    StrCmp $0 "00000000" PrintInfNames ContInst1\r
+\r
+  PrintInfNames:\r
+    Pop $0\r
+    DetailPrint "Deleted $0"\r
+    Pop $0\r
+    DetailPrint "Deleted $0"\r
+\r
+  ContInst1:\r
+    InstDrv::CreateDevice /NOUNLOAD\r
+    Pop $0\r
+    DetailPrint "CreateDevice: $0"\r
+\r
+    SetOutPath $TEMP\r
+    File "ircomm2k.inf"\r
+    File "ircomm2k.sys"\r
+\r
+    InstDrv::InstallDriver /NOUNLOAD "$TEMP\ircomm2k.inf"\r
+    Pop $0\r
+    DetailPrint "InstallDriver: $0"\r
+    StrCmp $0 "00000000" PrintReboot ContInst2\r
+\r
+  PrintReboot:\r
+    Pop $0\r
+    DetailPrint "Reboot: $0"\r
+\r
+  ContInst2:\r
+    InstDrv::CountDevices\r
+    Pop $0\r
+    DetailPrint "CountDevices: $0"\r
+SectionEnd\r
+\r
+Section "Uninstall the driver again" UninstDriver\r
+    InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k"\r
+    Pop $0\r
+    DetailPrint "InitDriverSetup: $0"\r
+\r
+    InstDrv::DeleteOemInfFiles /NOUNLOAD\r
+    Pop $0\r
+    DetailPrint "DeleteOemInfFiles: $0"\r
+    StrCmp $0 "00000000" PrintInfNames ContUninst1\r
+\r
+  PrintInfNames:\r
+    Pop $0\r
+    DetailPrint "Deleted $0"\r
+    Pop $0\r
+    DetailPrint "Deleted $0"\r
+\r
+  ContUninst1:\r
+    InstDrv::RemoveAllDevices\r
+    Pop $0\r
+    DetailPrint "RemoveAllDevices: $0"\r
+    StrCmp $0 "00000000" PrintReboot ContUninst2\r
+\r
+  PrintReboot:\r
+    Pop $0\r
+    DetailPrint "Reboot: $0"\r
+\r
+  ContUninst2:\r
+    Delete "$SYSDIR\system32\ircomm2k.sys"\r
+SectionEnd
\ No newline at end of file
diff --git a/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe
new file mode 100644 (file)
index 0000000..615bae1
Binary files /dev/null and b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv-Test.exe differ
diff --git a/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.c b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.c
new file mode 100644 (file)
index 0000000..efe866e
--- /dev/null
@@ -0,0 +1,704 @@
+/*\r
+\r
+InstDrv.dll - Installs or Removes Device Drivers\r
+\r
+Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de)\r
+\r
+This software is provided 'as-is', without any express or implied\r
+warranty. In no event will the authors be held liable for any damages\r
+arising from the use of this software.\r
+\r
+Permission is granted to anyone to use this software for any purpose,\r
+including commercial applications, and to alter it and redistribute\r
+it freely, subject to the following restrictions:\r
+\r
+1. The origin of this software must not be misrepresented; \r
+   you must not claim that you wrote the original software.\r
+   If you use this software in a product, an acknowledgment in the\r
+   product documentation would be appreciated but is not required.\r
+2. Altered versions must be plainly marked as such,\r
+   and must not be misrepresented as being the original software.\r
+3. This notice may not be removed or altered from any distribution.\r
+\r
+*/\r
+\r
+\r
+#include <windows.h>\r
+#include <setupapi.h>\r
+#include <newdev.h>\r
+#include "../exdll/exdll.h"\r
+\r
+\r
+char    paramBuf[1024];\r
+GUID    devClass;\r
+char    hwIdBuf[1024];\r
+int     initialized = 0;\r
+\r
+\r
+\r
+void* memset(void* dst, int val, unsigned int len)\r
+{\r
+    while (len-- > 0)\r
+        *((char *)dst)++ = val;\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+\r
+void* memcpy(void* dst, const void* src, unsigned int len)\r
+{\r
+    while (len-- > 0)\r
+        *((char *)dst)++ = *((char *)src)++;\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+\r
+int HexCharToInt(char c)\r
+{\r
+    if ((c >= '0') && (c <= '9'))\r
+        return c - '0';\r
+    else if ((c >= 'a') && (c <= 'f'))\r
+        return c - 'a' + 10;\r
+    else if ((c >= 'A') && (c <= 'F'))\r
+        return c - 'A' + 10;\r
+    else\r
+        return -1;\r
+}\r
+\r
+\r
+\r
+BOOLEAN HexStringToUInt(char* str, int width, void* valBuf)\r
+{\r
+    int i, val;\r
+\r
+\r
+    for (i = width - 4; i >= 0; i -= 4)\r
+    {\r
+        val = HexCharToInt(*str++);\r
+        if (val < 0)\r
+            return FALSE;\r
+        *(unsigned int *)valBuf += val << i;\r
+    }\r
+\r
+    return TRUE;\r
+}\r
+\r
+\r
+\r
+BOOLEAN StringToGUID(char* guidStr, GUID* pGuid)\r
+{\r
+    int i;\r
+\r
+\r
+    memset(pGuid, 0, sizeof(GUID));\r
+\r
+    if (*guidStr++ != '{')\r
+        return FALSE;\r
+\r
+    if (!HexStringToUInt(guidStr, 32, &pGuid->Data1))\r
+        return FALSE;\r
+    guidStr += 8;\r
+\r
+    if (*guidStr++ != '-')\r
+        return FALSE;\r
+\r
+    if (!HexStringToUInt(guidStr, 16, &pGuid->Data2))\r
+        return FALSE;\r
+    guidStr += 4;\r
+\r
+    if (*guidStr++ != '-')\r
+        return FALSE;\r
+\r
+    if (!HexStringToUInt(guidStr, 16, &pGuid->Data3))\r
+        return FALSE;\r
+    guidStr += 4;\r
+\r
+    if (*guidStr++ != '-')\r
+        return FALSE;\r
+\r
+    for (i = 0; i < 2; i++)\r
+    {\r
+        if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))\r
+            return FALSE;\r
+        guidStr += 2;\r
+    }\r
+\r
+    if (*guidStr++ != '-')\r
+        return FALSE;\r
+\r
+    for (i = 2; i < 8; i++)\r
+    {\r
+        if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))\r
+            return FALSE;\r
+        guidStr += 2;\r
+    }\r
+\r
+    if (*guidStr++ != '}')\r
+        return FALSE;\r
+\r
+    return TRUE;\r
+}\r
+\r
+\r
+\r
+DWORD FindNextDevice(HDEVINFO devInfoSet, SP_DEVINFO_DATA* pDevInfoData, DWORD* pIndex)\r
+{\r
+    DWORD   buffersize = 0;\r
+    LPTSTR  buffer     = NULL;\r
+    DWORD   dataType;\r
+    DWORD   result;\r
+\r
+\r
+    while (1)\r
+    {\r
+        if (!SetupDiEnumDeviceInfo(devInfoSet, (*pIndex)++, pDevInfoData))\r
+        {\r
+            result = GetLastError();\r
+            break;\r
+        }\r
+\r
+      GetDeviceRegistryProperty:\r
+        if (!SetupDiGetDeviceRegistryProperty(devInfoSet, pDevInfoData, SPDRP_HARDWAREID,\r
+                                              &dataType, (PBYTE)buffer, buffersize,\r
+                                              &buffersize))\r
+        {\r
+            result = GetLastError();\r
+\r
+            if (result == ERROR_INSUFFICIENT_BUFFER)\r
+            {\r
+                if (buffer != NULL)\r
+                    LocalFree(buffer);\r
+\r
+                buffer = (LPTSTR)LocalAlloc(LPTR, buffersize);\r
+\r
+                if (buffer == NULL)\r
+                    break;\r
+\r
+                goto GetDeviceRegistryProperty;\r
+            }\r
+            else if (result == ERROR_INVALID_DATA)\r
+                continue;   // ignore invalid entries\r
+            else\r
+                break;      // break on other errors\r
+        }\r
+\r
+        if (lstrcmpi(buffer, hwIdBuf) == 0)\r
+        {\r
+            result  = 0;\r
+            break;\r
+        }\r
+    }\r
+\r
+    if (buffer != NULL)\r
+        LocalFree(buffer);\r
+\r
+    return result;\r
+}\r
+\r
+\r
+\r
+DWORD FindFirstDevice(HWND hwndParent, const GUID* pDevClass, const LPTSTR hwId,\r
+                      HDEVINFO* pDevInfoSet, SP_DEVINFO_DATA* pDevInfoData,\r
+                      DWORD *pIndex, DWORD flags)\r
+{\r
+    DWORD   result;\r
+\r
+\r
+    *pDevInfoSet = SetupDiGetClassDevs((GUID*)pDevClass, NULL, hwndParent, flags);\r
+    if (*pDevInfoSet == INVALID_HANDLE_VALUE)\r
+        return GetLastError();\r
+\r
+    pDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);\r
+    *pIndex = 0;\r
+\r
+    result = FindNextDevice(*pDevInfoSet, pDevInfoData, pIndex);\r
+\r
+    if (result != 0)\r
+        SetupDiDestroyDeviceInfoList(*pDevInfoSet);\r
+\r
+    return result;\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::InitDriverSetup devClass drvHWID\r
+ *\r
+ *  devClass    - GUID of the driver's device setup class\r
+ *  drvHWID     - Hardware ID of the supported device\r
+ *\r
+ * Return:\r
+ *  result      - error message, empty on success\r
+ */\r
+void __declspec(dllexport) InitDriverSetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+    EXDLL_INIT();\r
+\r
+    /* convert class GUID */\r
+    popstring(paramBuf);\r
+\r
+    if (!StringToGUID(paramBuf, &devClass))\r
+    {\r
+        popstring(paramBuf);\r
+        pushstring("Invalid GUID!");\r
+        return;\r
+    }\r
+\r
+    /* get hardware ID */\r
+    memset(hwIdBuf, 0, sizeof(hwIdBuf));\r
+    popstring(hwIdBuf);\r
+\r
+    initialized = 1;\r
+    pushstring("");\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::CountDevices\r
+ *\r
+ * Return:\r
+ *  result      - Number of installed devices the driver supports\r
+ */\r
+void __declspec(dllexport) CountDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+    HDEVINFO            devInfoSet;\r
+    SP_DEVINFO_DATA     devInfoData;\r
+    int                 count = 0;\r
+    char                countBuf[16];\r
+    DWORD               index;\r
+    DWORD               result;\r
+\r
+\r
+    EXDLL_INIT();\r
+\r
+    if (!initialized)\r
+    {\r
+        pushstring("Fatal error!");\r
+        return;\r
+    }\r
+\r
+    result = FindFirstDevice(hwndParent, &devClass, hwIdBuf, &devInfoSet, &devInfoData,\r
+                             &index, DIGCF_PRESENT);\r
+    if (result != 0)\r
+    {\r
+        pushstring("0");\r
+        return;\r
+    }\r
+\r
+    do\r
+    {\r
+        count++;\r
+    } while (FindNextDevice(devInfoSet, &devInfoData, &index) == 0);\r
+\r
+    SetupDiDestroyDeviceInfoList(devInfoSet);\r
+\r
+    wsprintf(countBuf, "%d", count);\r
+    pushstring(countBuf);\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::CreateDevice\r
+ *\r
+ * Return:\r
+ *  result      - Windows error code\r
+ */\r
+void __declspec(dllexport) CreateDevice(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+    HDEVINFO            devInfoSet;\r
+    SP_DEVINFO_DATA     devInfoData;\r
+    DWORD               result = 0;\r
+    char                resultBuf[16];\r
+\r
+\r
+    EXDLL_INIT();\r
+\r
+    if (!initialized)\r
+    {\r
+        pushstring("Fatal error!");\r
+        return;\r
+    }\r
+\r
+    devInfoSet = SetupDiCreateDeviceInfoList(&devClass, hwndParent);\r
+    if (devInfoSet == INVALID_HANDLE_VALUE)\r
+    {\r
+        wsprintf(resultBuf, "%08X", GetLastError());\r
+        pushstring(resultBuf);\r
+        return;\r
+    }\r
+\r
+    devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);\r
+    if (!SetupDiCreateDeviceInfo(devInfoSet, hwIdBuf, &devClass, NULL,\r
+                                 hwndParent, DICD_GENERATE_ID, &devInfoData))\r
+    {\r
+        result = GetLastError();\r
+        goto InstallCleanup;\r
+    }\r
+\r
+    if (!SetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID,\r
+                                          hwIdBuf, (lstrlen(hwIdBuf)+2)*sizeof(TCHAR))) \r
+    {\r
+        result = GetLastError();\r
+        goto InstallCleanup;\r
+    }\r
+\r
+    if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))\r
+        result = GetLastError();\r
+\r
+  InstallCleanup:\r
+    SetupDiDestroyDeviceInfoList(devInfoSet);\r
+\r
+    wsprintf(resultBuf, "%08X", result);\r
+    pushstring(resultBuf);\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::InstallDriver infPath\r
+ *\r
+ * Return:\r
+ *  result      - Windows error code\r
+ *  reboot      - non-zero if reboot is required\r
+ */\r
+void __declspec(dllexport) InstallDriver(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+    char    resultBuf[16];\r
+    BOOL    reboot;\r
+\r
+\r
+    EXDLL_INIT();\r
+    popstring(paramBuf);\r
+\r
+    if (!initialized)\r
+    {\r
+        pushstring("Fatal error!");\r
+        return;\r
+    }\r
+\r
+    if (!UpdateDriverForPlugAndPlayDevices(hwndParent, hwIdBuf, paramBuf,\r
+                                           INSTALLFLAG_FORCE, &reboot))\r
+    {\r
+        wsprintf(resultBuf, "%08X", GetLastError());\r
+        pushstring(resultBuf);\r
+    }\r
+    else\r
+    {\r
+        wsprintf(resultBuf, "%d", reboot);\r
+        pushstring(resultBuf);\r
+        pushstring("00000000");\r
+    }\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::DeleteOemInfFiles\r
+ *\r
+ * Return:\r
+ *  result      - Windows error code\r
+ *  oeminf      - Path of the deleted devices setup file (oemXX.inf)\r
+ *  oempnf      - Path of the deleted devices setup file (oemXX.pnf)\r
+ */\r
+void __declspec(dllexport) DeleteOemInfFiles(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+    HDEVINFO                devInfo;\r
+    SP_DEVINFO_DATA         devInfoData;\r
+    SP_DRVINFO_DATA         drvInfoData;\r
+    SP_DRVINFO_DETAIL_DATA  drvInfoDetail;\r
+    DWORD                   index;\r
+    DWORD                   result;\r
+    char                    resultBuf[16];\r
+\r
+\r
+    if (!initialized)\r
+    {\r
+        pushstring("Fatal error!");\r
+        return;\r
+    }\r
+\r
+    result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);\r
+    if (result != 0)\r
+        goto Cleanup1;\r
+\r
+    if (!SetupDiBuildDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER))\r
+    {\r
+        result = GetLastError();\r
+        goto Cleanup2;\r
+    }\r
+\r
+    drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);\r
+    drvInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);\r
+\r
+    if (!SetupDiEnumDriverInfo(devInfo, &devInfoData, SPDIT_COMPATDRIVER, 0, &drvInfoData))\r
+    {\r
+        result = GetLastError();\r
+        goto Cleanup3;\r
+    }\r
+\r
+    if (!SetupDiGetDriverInfoDetail(devInfo, &devInfoData, &drvInfoData,\r
+                                    &drvInfoDetail, sizeof(drvInfoDetail), NULL))\r
+    {\r
+        result = GetLastError();\r
+\r
+        if (result != ERROR_INSUFFICIENT_BUFFER)\r
+            goto Cleanup3;\r
+\r
+        result = 0;\r
+    }\r
+\r
+    pushstring(drvInfoDetail.InfFileName);\r
+    if (!DeleteFile(drvInfoDetail.InfFileName))\r
+        result = GetLastError();\r
+    else\r
+    {\r
+        index = lstrlen(drvInfoDetail.InfFileName);\r
+        if (index > 3)\r
+        {\r
+            lstrcpy(drvInfoDetail.InfFileName+index-3, "pnf");\r
+            pushstring(drvInfoDetail.InfFileName);\r
+            if (!DeleteFile(drvInfoDetail.InfFileName))\r
+                result = GetLastError();\r
+        }\r
+    }\r
+\r
+  Cleanup3:\r
+    SetupDiDestroyDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER);\r
+\r
+  Cleanup2:\r
+    SetupDiDestroyDeviceInfoList(devInfo);\r
+\r
+  Cleanup1:\r
+    wsprintf(resultBuf, "%08X", result);\r
+    pushstring(resultBuf);\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::RemoveAllDevices\r
+ *\r
+ * Return:\r
+ *  result      - Windows error code\r
+ *  reboot      - non-zero if reboot is required\r
+ */\r
+void __declspec(dllexport) RemoveAllDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+    HDEVINFO                devInfo;\r
+    SP_DEVINFO_DATA         devInfoData;\r
+    DWORD                   index;\r
+    DWORD                   result;\r
+    char                    resultBuf[16];\r
+    BOOL                    reboot = FALSE;\r
+    SP_DEVINSTALL_PARAMS    instParams;\r
+\r
+\r
+    EXDLL_INIT();\r
+\r
+    if (!initialized)\r
+    {\r
+        pushstring("Fatal error!");\r
+        return;\r
+    }\r
+\r
+    result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);\r
+    if (result != 0)\r
+        goto Cleanup1;\r
+\r
+    do\r
+    {\r
+        if (!SetupDiCallClassInstaller(DIF_REMOVE, devInfo, &devInfoData))\r
+        {\r
+            result = GetLastError();\r
+            break;\r
+        }\r
+\r
+        instParams.cbSize = sizeof(instParams);\r
+        if (!reboot &&\r
+            SetupDiGetDeviceInstallParams(devInfo, &devInfoData, &instParams) &&\r
+            ((instParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0))\r
+        {\r
+            reboot = TRUE;\r
+        }\r
+\r
+        result = FindNextDevice(devInfo, &devInfoData, &index);\r
+    } while (result == 0);\r
+\r
+    SetupDiDestroyDeviceInfoList(devInfo);\r
+\r
+  Cleanup1:\r
+    if ((result == 0) || (result == ERROR_NO_MORE_ITEMS))\r
+    {\r
+        wsprintf(resultBuf, "%d", reboot);\r
+        pushstring(resultBuf);\r
+        pushstring("00000000");\r
+    }\r
+    else\r
+    {\r
+        wsprintf(resultBuf, "%08X", result);\r
+        pushstring(resultBuf);\r
+    }\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::StartSystemService serviceName\r
+ *\r
+ * Return:\r
+ *  result      - Windows error code\r
+ */\r
+void __declspec(dllexport) StartSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+    SC_HANDLE       managerHndl;\r
+    SC_HANDLE       svcHndl;\r
+    SERVICE_STATUS  svcStatus;\r
+    DWORD           oldCheckPoint;\r
+    DWORD           result;\r
+    char            resultBuf[16];\r
+\r
+\r
+    EXDLL_INIT();\r
+    popstring(paramBuf);\r
+\r
+    managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
+    if (managerHndl == NULL)\r
+    {\r
+        result = GetLastError();\r
+        goto Cleanup1;\r
+    }\r
+\r
+    svcHndl = OpenService(managerHndl, paramBuf, SERVICE_START | SERVICE_QUERY_STATUS);\r
+    if (svcHndl == NULL)\r
+    {\r
+        result = GetLastError();\r
+        goto Cleanup2;\r
+    }\r
+\r
+    if (!StartService(svcHndl, 0, NULL) || !QueryServiceStatus(svcHndl, &svcStatus))\r
+    {\r
+        result = GetLastError();\r
+        goto Cleanup3;\r
+    }\r
+\r
+    while (svcStatus.dwCurrentState == SERVICE_START_PENDING)\r
+    {\r
+        oldCheckPoint = svcStatus.dwCheckPoint;\r
+\r
+        Sleep(svcStatus.dwWaitHint);\r
+\r
+        if (!QueryServiceStatus(svcHndl, &svcStatus))\r
+        {\r
+            result = GetLastError();\r
+            break;\r
+        }\r
+\r
+        if (oldCheckPoint >= svcStatus.dwCheckPoint)\r
+        {\r
+            if ((svcStatus.dwCurrentState == SERVICE_STOPPED) &&\r
+                (svcStatus.dwWin32ExitCode != 0))\r
+                result = svcStatus.dwWin32ExitCode;\r
+            else\r
+                result = ERROR_SERVICE_REQUEST_TIMEOUT;\r
+        }\r
+    }\r
+\r
+    if (svcStatus.dwCurrentState == SERVICE_RUNNING)\r
+        result = 0;\r
+\r
+  Cleanup3:\r
+    CloseServiceHandle(svcHndl);\r
+\r
+  Cleanup2:\r
+    CloseServiceHandle(managerHndl);\r
+\r
+  Cleanup1:\r
+    wsprintf(resultBuf, "%08X", result);\r
+    pushstring(resultBuf);\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::StopSystemService serviceName\r
+ *\r
+ * Return:\r
+ *  result      - Windows error code\r
+ */\r
+void __declspec(dllexport) StopSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+    SC_HANDLE       managerHndl;\r
+    SC_HANDLE       svcHndl;\r
+    SERVICE_STATUS  svcStatus;\r
+    DWORD           oldCheckPoint;\r
+    DWORD           result;\r
+    char            resultBuf[16];\r
+\r
+\r
+    EXDLL_INIT();\r
+    popstring(paramBuf);\r
+\r
+    managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
+    if (managerHndl == NULL)\r
+    {\r
+        result = GetLastError();\r
+        goto Cleanup1;\r
+    }\r
+\r
+    svcHndl = OpenService(managerHndl, paramBuf, SERVICE_STOP | SERVICE_QUERY_STATUS);\r
+    if (svcHndl == NULL)\r
+    {\r
+        result = GetLastError();\r
+        goto Cleanup2;\r
+    }\r
+\r
+    if (!ControlService(svcHndl, SERVICE_CONTROL_STOP, &svcStatus))\r
+    {\r
+        result = GetLastError();\r
+        goto Cleanup3;\r
+    }\r
+\r
+    while (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)\r
+    {\r
+        oldCheckPoint = svcStatus.dwCheckPoint;\r
+\r
+        Sleep(svcStatus.dwWaitHint);\r
+\r
+        if (!QueryServiceStatus(svcHndl, &svcStatus))\r
+        {\r
+            result = GetLastError();\r
+            break;\r
+        }\r
+\r
+        if (oldCheckPoint >= svcStatus.dwCheckPoint)\r
+        {\r
+            result = ERROR_SERVICE_REQUEST_TIMEOUT;\r
+            break;\r
+        }\r
+    }\r
+\r
+    if (svcStatus.dwCurrentState == SERVICE_STOPPED)\r
+        result = 0;\r
+\r
+  Cleanup3:\r
+    CloseServiceHandle(svcHndl);\r
+\r
+  Cleanup2:\r
+    CloseServiceHandle(managerHndl);\r
+\r
+  Cleanup1:\r
+    wsprintf(resultBuf, "%08X", result);\r
+    pushstring(resultBuf);\r
+}\r
+\r
+\r
+\r
+BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)\r
+{\r
+    return TRUE;\r
+}\r
diff --git a/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsp b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsp
new file mode 100644 (file)
index 0000000..874e66c
--- /dev/null
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="InstDrv" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** NICHT BEARBEITEN **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=InstDrv - Win32 Debug\r
+!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE\r
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "InstDrv.mak".\r
+!MESSAGE \r
+!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben\r
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "InstDrv.mak" CFG="InstDrv - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Für die Konfiguration stehen zur Auswahl:\r
+!MESSAGE \r
+!MESSAGE "InstDrv - Win32 Release" (basierend auf  "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "InstDrv - Win32 Debug" (basierend auf  "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "InstDrv - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 1\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O1 /I "C:\Programme\WINDDK\3790\inc\ddk\w2k" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x407 /d "NDEBUG"\r
+# ADD RSC /l 0x407 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib setupapi.lib newdev.lib /nologo /entry:"_DllMainCRTStartup" /dll /machine:I386 /nodefaultlib /out:"../../Plugins/InstDrv.dll" /libpath:"C:\Programme\WINDDK\3790\lib\w2k\i386" /opt:nowin98\r
+# SUBTRACT LINK32 /pdb:none\r
+\r
+!ELSEIF  "$(CFG)" == "InstDrv - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /GZ  /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /GZ  /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x407 /d "_DEBUG"\r
+# ADD RSC /l 0x407 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /entry:"_DllMainCRTStartup" /dll /debug /machine:I386 /pdbtype:sept\r
+# SUBTRACT LINK32 /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "InstDrv - Win32 Release"\r
+# Name "InstDrv - Win32 Debug"\r
+# Begin Group "Quellcodedateien"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\InstDrv.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header-Dateien"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Ressourcendateien"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsw b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/InstDrv.dsw
new file mode 100644 (file)
index 0000000..b3d02f0
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN!\r
+\r
+###############################################################################\r
+\r
+Project: "InstDrv"=.\InstDrv.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/Readme.txt b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/Readme.txt
new file mode 100644 (file)
index 0000000..e5877aa
--- /dev/null
@@ -0,0 +1,141 @@
+InstDrv.dll version 0.2 - Installs or Removes Device Drivers\r
+------------------------------------------------------------\r
+\r
+\r
+The plugin helps you to create NSIS scripts for installing device drivers or\r
+removing them again. It can count installed device instances, create new ones\r
+or delete all supported device. InstDrv works on Windows 2000 or later.\r
+\r
+\r
+\r
+InstDrv::InitDriverSetup devClass drvHWID\r
+Return: result\r
+\r
+To start processing a driver, first call this function. devClass is the GUID\r
+of the device class the driver supports, drvHWID is the device hardware ID. If\r
+you don't know what these terms mean, you may want to take a look at the\r
+Windows DDK. This function returns an empty string on success, otherwise an\r
+error message.\r
+\r
+InitDriverSetup has to be called every time after the plugin dll has been\r
+(re-)loaded, or if you want to switch to a different driver.\r
+\r
+\r
+\r
+InstDrv::CountDevices\r
+Return: number\r
+\r
+This call returns the number of installed and supported devices of the driver.\r
+\r
+\r
+\r
+InstDrv::CreateDevice\r
+Return: result\r
+\r
+To create a new deviced node which the driver has to support, use this\r
+function. You may even call it multiple times for more than one instance. The\r
+return value is the Windows error code (in hex). Use CreateDevice before\r
+installing or updating the driver itself.\r
+\r
+\r
+\r
+InstDrv::InstallDriver infPath\r
+Return: result\r
+        reboot\r
+\r
+InstallDriver installs or updates a device driver as specified in the .inf\r
+setup script. It returns a Windows error code (in hex) and, on success, a flag\r
+signalling if a system reboot is required.\r
+\r
+\r
+\r
+InstDrv::DeleteOemInfFiles\r
+Return: result\r
+        oeminf\r
+        oempnf\r
+\r
+DeleteOemInfFiles tries to clean up the Windows inf directory by deleting the\r
+oemXX.inf and oemXX.pnf files associated with the drivers. It returns a\r
+Windows error code (in hex) and, on success, the names of the deleted files.\r
+This functions requires that at least one device instance is still present.\r
+So, call it before you remove the devices itself. You should also call it\r
+before updating a driver. This avoids that the inf directory gets slowly\r
+messed up with useless old setup scripts (which does NOT really accelerate\r
+Windows). The error code which comes up when no device is installed is\r
+"00000103".\r
+\r
+\r
+\r
+InstDrv::RemoveAllDevices\r
+Return: result\r
+        reboot\r
+\r
+This functions deletes all devices instances the driver supported. It returns\r
+a Windows error code (in hex) and, on success, a flag signalling if the system\r
+needs to be rebooted. You additionally have to remove the driver binaries from\r
+the system paths.\r
+\r
+\r
+\r
+InstDrv::StartSystemService serviceName\r
+Return: result\r
+\r
+Call this function to start the provided system service. The function blocks\r
+until the service is started or the system reported a timeout. The return value\r
+is the Windows error code (in hex).\r
+\r
+\r
+\r
+InstDrv::StopSystemService serviceName\r
+Return: result\r
+\r
+This function tries to stop the provided system service. It blocks until the\r
+service has been shut down or the system reported a timeout. The return value\r
+is the Windows error code (in hex).\r
+\r
+\r
+\r
+Example.nsi\r
+\r
+The example script installs or removes the virtual COM port driver of IrCOMM2k\r
+(2.0.0-alpha8, see www.ircomm2k.de/english). The driver and its setup script\r
+are only included for demonstration purposes, they do not work without the\r
+rest of IrCOMM2k (but they also do not cause any harm).\r
+\r
+\r
+\r
+Building the Source Code\r
+\r
+To build the plugin from the source code, some include files and libraries\r
+which come with the Windows DDK are required.\r
+\r
+\r
+\r
+History\r
+\r
+ 0.2    - fixed bug when calling InitDriverSetup the second time\r
+        - added StartSystemService and StopSystemService\r
+\r
+ 0.1    - first release\r
+\r
+\r
+\r
+License\r
+\r
+Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de)\r
+\r
+This software is provided 'as-is', without any express or implied\r
+warranty. In no event will the authors be held liable for any damages\r
+arising from the use of this software.\r
+\r
+Permission is granted to anyone to use this software for any purpose,\r
+including commercial applications, and to alter it and redistribute\r
+it freely, subject to the following restrictions:\r
+\r
+1. The origin of this software must not be misrepresented; \r
+   you must not claim that you wrote the original software.\r
+   If you use this software in a product, an acknowledgment in the\r
+   product documentation would be appreciated but is not required.\r
+2. Altered versions must be plainly marked as such,\r
+   and must not be misrepresented as being the original software.\r
+3. This notice may not be removed or altered from any distribution.\r
diff --git a/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.inf b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.inf
new file mode 100644 (file)
index 0000000..ccda1d8
--- /dev/null
@@ -0,0 +1,137 @@
+; IrCOMM2k.inf\r
+;\r
+; Installation file for the Virtual Infrared-COM-Port\r
+;\r
+; (c) Copyright 2001, 2002 Jan Kiszka \r
+;\r
+\r
+[Version]\r
+Signature="$Windows NT$"\r
+Provider=%JK%\r
+Class=Ports\r
+ClassGUID={4d36e978-e325-11ce-bfc1-08002be10318}\r
+;DriverVer=03/26/2002,1.2.1.0\r
+\r
+[DestinationDirs]\r
+IrCOMM2k.Copy2Drivers  = 12\r
+IrCOMM2k.Copy2Winnt    = 10\r
+IrCOMM2k.Copy2System32 = 11\r
+IrCOMM2k.Copy2Help     = 18\r
+\r
+\r
+;\r
+; Driver information\r
+;\r
+\r
+[Manufacturer]\r
+%JK%   = JK.Mfg\r
+\r
+[JK.Mfg]\r
+%JK.DeviceDescIrCOMM% = IrCOMM2k_inst,IrCOMM2k\r
+\r
+\r
+;\r
+; General installation section\r
+;\r
+\r
+[IrCOMM2k_inst]\r
+CopyFiles = IrCOMM2k.Copy2Drivers ;,IrCOMM2k.Copy2System32,IrCOMM2k.Copy2Help,IrCOMM2k.Copy2Winnt\r
+;AddReg    = IrCOMM2k_inst_AddReg\r
+\r
+\r
+;\r
+; File sections\r
+;\r
+\r
+[IrCOMM2k.Copy2Drivers]\r
+ircomm2k.sys,,,2\r
+\r
+;[IrCOMM2k.Copy2System32]\r
+;ircomm2k.exe,,,2\r
+;ircomm2k.dll,,,2\r
+\r
+;[IrCOMM2k.Copy2Help]\r
+;ircomm2k.hlp,,,2\r
+\r
+;[IrCOMM2k.Copy2Winnt]\r
+;IrCOMM2k-Setup.exe,Setup.exe,,2\r
+\r
+\r
+;\r
+; Service Installation\r
+;\r
+\r
+[IrCOMM2k_inst.Services]\r
+AddService = IrCOMM2k,0x00000002,IrCOMM2k_DriverService_Inst,IrCOMM2k_DriverEventLog_Inst\r
+;AddService = IrCOMM2kSvc,,IrCOMM2k_Service_Inst\r
+\r
+[IrCOMM2k_DriverService_Inst]\r
+DisplayName    = %IrCOMM2k.DrvName%\r
+ServiceType    = 1                  ; SERVICE_KERNEL_DRIVER\r
+StartType      = 3                  ; SERVICE_DEMAND_START\r
+ErrorControl   = 0                  ; SERVICE_ERROR_IGNORE\r
+ServiceBinary  = %12%\ircomm2k.sys\r
+\r
+;[IrCOMM2k_Service_Inst]\r
+;DisplayName    = %IrCOMM2k.SvcName%\r
+;Description    = %IrCOMM2k.SvcDesc%\r
+;ServiceType    = 0x00000120         ; SERVICE_WIN32_SHARE_PROCESS, SERVICE_INTERACTIVE_PROCESS\r
+;StartType      = 2                  ; SERVICE_AUTO_START\r
+;ErrorControl   = 0                  ; SERVICE_ERROR_IGNORE\r
+;ServiceBinary  = %11%\ircomm2k.exe\r
+;Dependencies   = IrCOMM2k\r
+;AddReg         = IrCOMM2kSvcAddReg\r
+\r
+\r
+[IrCOMM2k_inst.nt.HW]\r
+AddReg=IrCOMM2kHwAddReg\r
+\r
+[IrCOMM2kHwAddReg]\r
+HKR,,PortSubClass,REG_BINARY,0x00000001\r
+;HKR,,TimeoutScaling,REG_DWORD,0x00000001\r
+;HKR,,StatusLines,REG_DWORD,0x00000000\r
+\r
+;[IrCOMM2k_inst_AddReg]\r
+;HKR,,EnumPropPages32,,"ircomm2k.dll,IrCOMM2kPropPageProvider"\r
+;HKLM,%UNINSTALL_KEY%,DisplayIcon,0x00020000,"%windir%\IrCOMM2k-Setup.exe"\r
+;HKLM,%UNINSTALL_KEY%,DisplayName,,"IrCOMM2k 1.2.1 "\r
+;HKLM,%UNINSTALL_KEY%,DisplayVersion,,"1.2.1"\r
+;HKLM,%UNINSTALL_KEY%,HelpLink,,"http://www.ircomm2k.de"\r
+;HKLM,%UNINSTALL_KEY%,Publisher,,%JK%\r
+;HKLM,%UNINSTALL_KEY%,UninstallString,0x00020000,"%windir%\IrCOMM2k-Setup.exe"\r
+\r
+;[IrCOMM2kSvcAddReg]\r
+;HKR,Parameters,ActiveConnectOnly,REG_DWORD,0x00000000\r
+\r
+\r
+[IrCOMM2k_DriverEventLog_Inst]\r
+AddReg = IrCOMM2k_DriverEventLog_AddReg\r
+\r
+[IrCOMM2k_DriverEventLog_AddReg]\r
+HKR,,EventMessageFile,REG_EXPAND_SZ,"%SystemRoot%\System32\IoLogMsg.dll;%SystemRoot%\System32\drivers\ircomm2k.sys"\r
+HKR,,TypesSupported,REG_DWORD,7\r
+\r
+\r
+[Strings]\r
+\r
+;\r
+; Non-Localizable Strings\r
+;\r
+\r
+REG_SZ         = 0x00000000\r
+REG_MULTI_SZ   = 0x00010000\r
+REG_EXPAND_SZ  = 0x00020000\r
+REG_BINARY     = 0x00000001\r
+REG_DWORD      = 0x00010001\r
+SERVICEROOT    = "System\CurrentControlSet\Services"\r
+UNINSTALL_KEY  = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IrCOMM2k"\r
+\r
+;\r
+; Localizable Strings\r
+;\r
+\r
+JK                  = "Jan Kiszka"\r
+JK.DeviceDescIrCOMM = "Virtueller Infrarot-Kommunikationsanschluss"\r
+IrCOMM2k.DrvName    = "Virtueller Infrarot-Kommunikationsanschluss"\r
+;IrCOMM2k.SvcName    = "Virtueller Infrarot-Kommunikationsanschluß, Dienstprogramm"\r
+;IrCOMM2k.SvcDesc    = "Bildet über Infarot einen Kommunikationsanschluß nach."\r
diff --git a/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys
new file mode 100644 (file)
index 0000000..7882583
Binary files /dev/null and b/ao-tools/altosui/Instdrv/NSIS/Contrib/InstDrv/ircomm2k.sys differ
diff --git a/ao-tools/altosui/Instdrv/NSIS/Plugins/InstDrv.dll b/ao-tools/altosui/Instdrv/NSIS/Plugins/InstDrv.dll
new file mode 100644 (file)
index 0000000..482e955
Binary files /dev/null and b/ao-tools/altosui/Instdrv/NSIS/Plugins/InstDrv.dll differ
diff --git a/ao-tools/altosui/Makefile b/ao-tools/altosui/Makefile
deleted file mode 100644 (file)
index 63359fb..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-.SUFFIXES: .java .class
-
-CLASSPATH=classes:./*:/usr/share/java/*
-CLASSFILES=\
-       Altos.class \
-       AltosChannelMenu.class \
-       AltosConfig.class \
-       AltosConfigUI.class \
-       AltosConvert.class \
-       AltosCSV.class \
-       AltosEepromDownload.class \
-       AltosEepromMonitor.class \
-       AltosEepromReader.class \
-       AltosEepromRecord.class \
-       AltosFile.class \
-       AltosFlightInfoTableModel.class \
-       AltosFlightStatusTableModel.class \
-       AltosGPS.class \
-       AltosGreatCircle.class \
-       AltosLog.class \
-       AltosParse.class \
-       AltosPreferences.class \
-       AltosRecord.class \
-       AltosSerialMonitor.class \
-       AltosSerial.class \
-       AltosState.class \
-       AltosTelemetry.class \
-       AltosTelemetryReader.class \
-       AltosUI.class \
-       AltosDevice.class \
-       AltosDeviceDialog.class \
-       AltosVoice.class
-
-#FREETTSSRC=/home/keithp/src/freetts/freetts-1.2.2
-#FREETTSLIB=$(FREETTSSRC)/lib
-#FREETTSJAR=/usr/share/java/freetts.jar
-#FREETTSJAR= \
-#      cmudict04.jar \
-#      cmulex.jar \
-#      cmu_time_awb.jar \
-#      cmutimelex.jar \
-#      cmu_us_kal.jar \
-#      en_us.jar \
-#      freetts.jar
-
-JAVAFLAGS=-Xlint:unchecked -Xlint:deprecation
-
-OS:=$(shell uname)
-
-ifeq ($(OS),Linux)
-ALTOSUI_APP=altosui
-endif
-
-ifeq ($(OS),Darwin)
-ALTOSUI_APP=AltosUI.app/Contents/Resources/Java/altosui.jar
-endif
-
-all: altosui.jar $(ALTOSUI_APP)
-
-$(CLASSFILES):
-
-.java.class:
-       javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
-
-altosui.jar: classes/altosui classes/libaltosJNI $(FREETTSJAR) $(CLASSFILES) Manifest.txt
-       cd ./classes && jar cfm ../$@ altosui/Manifest.txt altosui/*.class libaltosJNI/*.class
-
-classes/altosui:
-       mkdir -p classes
-       ln -sf .. classes/altosui
-
-classes/libaltosJNI:
-       mkdir -p classes
-       ln -sf ../../libaltos/libaltosJNI classes/libaltosJNI
-
-#$(FREETTSJAR):
-#      ln -s $(FREETTSLIB)/$@ .
-
-ifeq ($(OS),Darwin)
-RESOURCES=altosui.jar $(FREETTSJAR) ../libaltos/libaltos.dylib
-
-$(ALTOSUI_APP): $(RESOURCES)
-       mkdir -p AltosUI.app/Contents/Resources/Java
-       cp $(RESOURCES) AltosUI.app/Contents/Resources/Java
-
-endif
-
-ifeq ($(OS),Linux)
-altosui:
-       echo "#!/bin/sh" > $@
-       echo "exec java -Djava.library.path=../libaltos -jar altosui.jar" >> $@
-       chmod +x ./altosui
-endif
-
-clean:
-       rm -f *.class altosui.jar
-       rm -f AltosUI.app/Contents/Resources/Java/*
-       rm -rf classes
diff --git a/ao-tools/altosui/Makefile-standalone b/ao-tools/altosui/Makefile-standalone
new file mode 100644 (file)
index 0000000..90621f3
--- /dev/null
@@ -0,0 +1,182 @@
+.SUFFIXES: .java .class
+
+CLASSPATH=classes:./*:/usr/share/java/*
+CLASSFILES=\
+       Altos.class \
+       AltosChannelMenu.class \
+       AltosConfig.class \
+       AltosConfigUI.class \
+       AltosConvert.class \
+       AltosCRCException.class \
+       AltosCSV.class \
+       AltosCSVUI.class \
+       AltosDebug.class \
+       AltosEepromDownload.class \
+       AltosEepromMonitor.class \
+       AltosEepromReader.class \
+       AltosEepromRecord.class \
+       AltosFile.class \
+       AltosFlash.class \
+       AltosFlashUI.class \
+       AltosFlightInfoTableModel.class \
+       AltosFlightStatusTableModel.class \
+       AltosGPS.class \
+       AltosGreatCircle.class \
+       AltosHexfile.class \
+       AltosLine.class \
+       AltosLog.class \
+       AltosLogfileChooser.class \
+       AltosParse.class \
+       AltosPreferences.class \
+       AltosReader.class \
+       AltosRecord.class \
+       AltosSerialMonitor.class \
+       AltosSerial.class \
+       AltosState.class \
+       AltosTelemetry.class \
+       AltosTelemetryReader.class \
+       AltosUI.class \
+       AltosDevice.class \
+       AltosDeviceDialog.class \
+       AltosRomconfig.class \
+       AltosRomconfigUI.class \
+       AltosVoice.class
+
+JAVA_ICON=../../icon/altus-metrum-16x16.jpg
+WINDOWS_ICON=../../icon/altus-metrum.ico
+
+# where altosui.jar gets installed
+ALTOSLIB=/usr/share/java
+
+# where freetts.jar is to be found
+FREETTSLIB=/usr/share/java
+
+# all of the freetts files
+FREETTSJAR= \
+       $(FREETTSLIB)/cmudict04.jar \
+       $(FREETTSLIB)/cmulex.jar \
+       $(FREETTSLIB)/cmu_time_awb.jar \
+       $(FREETTSLIB)/cmutimelex.jar \
+       $(FREETTSLIB)/cmu_us_kal.jar \
+       $(FREETTSLIB)/en_us.jar \
+       $(FREETTSLIB)/freetts.jar
+
+# The current hex files
+HEXLIB=../../src
+HEXFILES = \
+       $(HEXLIB)/telemetrum-v1.0.ihx \
+       $(HEXLIB)/teledongle-v0.2.ihx
+
+JAVAFLAGS=-Xlint:unchecked -Xlint:deprecation
+
+ALTOSUIJAR = altosui.jar
+FATJAR = fat/altosui.jar
+
+OS:=$(shell uname)
+
+LINUX_APP=altosui
+
+DARWIN_ZIP=Altos-Mac.zip
+
+WINDOWS_EXE=Altos-Windows.exe
+
+LINUX_TGZ=Altos-Linux.tgz
+
+all: altosui.jar $(LINUX_APP)
+fat: altosui.jar $(LINUX_APP) $(DARWIN_ZIP) $(WINDOWS_EXE) $(LINUX_TGZ)
+
+$(CLASSFILES):
+
+.java.class:
+       javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
+
+altosui.jar: classes/images classes/altosui classes/libaltosJNI $(CLASSFILES) Manifest.txt
+       cd ./classes && jar cfm ../$@ altosui/Manifest.txt images/* altosui/*.class libaltosJNI/*.class
+
+Manifest.txt: Makefile $(CLASSFILES)
+       echo 'Main-Class: altosui.AltosUI' > $@
+       echo "Class-Path: $(FREETTSLIB)/freetts.jar" >> $@
+
+classes/altosui:
+       mkdir -p classes
+       ln -sf .. classes/altosui
+
+classes/libaltosJNI:
+       mkdir -p classes
+       ln -sf ../../libaltos/libaltosJNI classes/libaltosJNI
+
+classes/images:
+       mkdir -p classes/images
+       ln -sf ../../$(JAVA_ICON) classes/images
+
+altosui:
+       echo "#!/bin/sh" > $@
+       echo "exec java -Djava.library.path=/usr/lib/altos -jar /usr/share/java/altosui.jar" >> $@
+       chmod +x ./altosui
+
+fat/altosui:
+       echo "#!/bin/sh" > $@
+       echo 'ME=`which "$0"`' >> $@
+       echo 'DIR=`dirname "$ME"`' >> $@
+       echo 'exec java -Djava.library.path="$$DIR" -jar "$$DIR"/altosui.jar' >> $@
+       chmod +x $@
+
+fat/altosui.jar: $(CLASSFILES) $(JAVA_ICON) fat/classes/Manifest.txt
+       mkdir -p fat/classes
+       test -L fat/classes/altosui || ln -sf ../.. fat/classes/altosui
+       mkdir -p fat/classes/images
+       cp $(JAVA_ICON) fat/classes/images
+       test -L fat/classes/libaltosJNI || ln -sf ../../../libaltos/libaltosJNI fat/classes/libaltosJNI
+       cd ./fat/classes && jar cfm ../../$@ Manifest.txt images/* altosui/*.class libaltosJNI/*.class
+
+fat/classes/Manifest.txt: $(CLASSFILES) Makefile
+       mkdir -p fat/classes
+       echo 'Main-Class: altosui.AltosUI' > $@
+       echo "Class-Path: freetts.jar" >> $@
+
+install: altosui.jar altosui
+       install -m 0644 altosui.jar $(DESTDIR)/usr/share/java/altosui.jar
+       install -m 0644 altosui.1 $(DESTDIR)/usr/share/man/man1/altosui.1
+       install altosui $(DESTDIR)/usr/bin/altosui
+
+clean:
+       rm -f *.class altosui.jar
+       rm -f AltosUI.app/Contents/Resources/Java/*
+       rm -rf classes
+       rm -rf windows linux
+
+distclean:     clean
+       rm -f $(DARWIN_ZIP) $(WINDOWS_EXE) $(LINUX_TGZ)
+       rm -rf darwin fat
+
+FAT_FILES=$(FATJAR) $(FREETTSJAR) $(HEXFILES)
+
+LINUX_FILES=$(FAT_FILES) ../libaltos/libaltos.so fat/altosui
+$(LINUX_TGZ): $(LINUX_FILES)
+       rm -f $@
+       mkdir -p linux/AltOS
+       rm -f linux/AltOS/*
+       cp $(LINUX_FILES) linux/AltOS
+       cd linux && tar czf ../$@ AltOS
+
+DARWIN_RESOURCES=$(FATJAR) $(FREETTSJAR) ../libaltos/libaltos.dylib
+DARWIN_EXTRA=$(HEXFILES)
+DARWIN_FILES=$(DARWIN_RESOURCES) $(DARWIN_EXTRA)
+
+$(DARWIN_ZIP): $(DARWIN_FILES)
+       rm -f $@
+       cp -a AltosUI.app darwin/
+       mkdir -p darwin/AltosUI.app/Contents/Resources/Java
+       cp $(DARWIN_RESOURCES) darwin/AltosUI.app/Contents/Resources/Java
+       mkdir -p darwin/AltOS
+       cp $(DARWIN_EXTRA) darwin/AltOS
+       cd darwin && zip -r ../$@ AltosUI.app AltOS
+
+WINDOWS_FILES = $(FAT_FILES) ../libaltos/altos.dll ../../telemetrum.inf $(WINDOWS_ICON)
+
+$(WINDOWS_EXE): $(WINDOWS_FILES) altos-windows.nsi
+       rm -f $@
+       mkdir -p windows/AltOS
+       rm -f windows/AltOS/*
+       cp $(WINDOWS_FILES) windows/AltOS
+       makensis altos-windows.nsi
diff --git a/ao-tools/altosui/Makefile.am b/ao-tools/altosui/Makefile.am
new file mode 100644 (file)
index 0000000..dd4b31e
--- /dev/null
@@ -0,0 +1,172 @@
+JAVAROOT=classes
+AM_JAVACFLAGS=-encoding UTF-8
+
+CLASSPATH_ENV=CLASSPATH=".:classes:../libaltos:$(FREETTS)/*:/usr/share/java/*"
+
+bin_SCRIPTS=altosui
+
+altosui_JAVA = \
+       AltosChannelMenu.java \
+       AltosConfig.java \
+       AltosConfigUI.java \
+       AltosConvert.java \
+       AltosCRCException.java \
+       AltosCSV.java \
+       AltosCSVUI.java \
+       AltosDebug.java \
+       AltosDeviceDialog.java \
+       AltosDevice.java \
+       AltosEepromDownload.java \
+       AltosEepromMonitor.java \
+       AltosEepromReader.java \
+       AltosEepromRecord.java \
+       AltosFile.java \
+       AltosFlash.java \
+       AltosFlashUI.java \
+       AltosFlightInfoTableModel.java \
+       AltosFlightStatusTableModel.java \
+       AltosGPS.java \
+       AltosGreatCircle.java \
+       AltosHexfile.java \
+       Altos.java \
+       AltosLine.java \
+      &nb